about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml16
-rw-r--r--CODE_OF_CONDUCT.md2
-rw-r--r--CONTRIBUTING.md116
-rw-r--r--README.md3
-rw-r--r--RELEASES.md12
-rw-r--r--config.toml.example22
-rw-r--r--src/Cargo.lock222
-rw-r--r--src/Cargo.toml1
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/README.md8
-rw-r--r--src/bootstrap/bin/rustc.rs23
-rw-r--r--src/bootstrap/bin/rustdoc.rs11
-rw-r--r--src/bootstrap/bootstrap.py10
-rw-r--r--src/bootstrap/bootstrap_test.py1
-rw-r--r--src/bootstrap/builder.rs74
-rw-r--r--src/bootstrap/cc_detect.rs52
-rw-r--r--src/bootstrap/check.rs106
-rw-r--r--src/bootstrap/compile.rs28
-rw-r--r--src/bootstrap/config.rs19
-rwxr-xr-xsrc/bootstrap/configure.py67
-rw-r--r--src/bootstrap/dist.rs205
-rw-r--r--src/bootstrap/doc.rs12
-rw-r--r--src/bootstrap/lib.rs51
-rw-r--r--src/bootstrap/native.rs75
-rw-r--r--src/bootstrap/tool.rs90
-rw-r--r--src/bootstrap/toolstate.rs7
-rw-r--r--src/bootstrap/util.rs21
-rw-r--r--src/build_helper/lib.rs21
-rw-r--r--src/ci/docker/asmjs/Dockerfile8
-rwxr-xr-xsrc/ci/docker/cross/build-arm-musl.sh2
-rw-r--r--src/ci/docker/cross2/Dockerfile54
-rwxr-xr-xsrc/ci/docker/cross2/build-fuchsia-toolchain.sh (renamed from src/ci/docker/dist-fuchsia/build-toolchain.sh)0
-rwxr-xr-xsrc/ci/docker/cross2/build-solaris-toolchain.sh107
-rw-r--r--src/ci/docker/cross2/shared.sh (renamed from src/ci/docker/dist-fuchsia/shared.sh)0
-rw-r--r--src/ci/docker/dist-fuchsia/Dockerfile41
-rw-r--r--src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh2
-rw-r--r--src/ci/docker/dist-x86_64-musl/build-musl.sh2
-rw-r--r--src/ci/docker/scripts/android-sdk.sh2
-rw-r--r--src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile (renamed from src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile)6
-rw-r--r--src/doc/man/rustc.13
-rw-r--r--src/doc/rustdoc/src/command-line-arguments.md12
-rw-r--r--src/doc/unstable-book/src/language-features/crate-visibility-modifier.md20
-rw-r--r--src/doc/unstable-book/src/language-features/lang-items.md92
-rw-r--r--src/doc/unstable-book/src/language-features/non-ascii-idents.md32
-rw-r--r--src/doc/unstable-book/src/language-features/optin-builtin-traits.md47
-rw-r--r--src/doc/unstable-book/src/language-features/unboxed-closures.md25
-rw-r--r--src/doc/unstable-book/src/library-features/alloc-jemalloc.md53
-rw-r--r--src/doc/unstable-book/src/library-features/alloc-system.md31
-rw-r--r--src/doc/unstable-book/src/library-features/collections.md5
-rw-r--r--src/doc/unstable-book/src/library-features/fn-traits.md35
-rwxr-xr-xsrc/etc/gdb_rust_pretty_printing.py15
-rw-r--r--src/etc/installer/exe/rust.iss4
-rw-r--r--src/etc/installer/msi/rust.wxs4
-rw-r--r--src/etc/installer/pkg/Distribution.xml6
-rw-r--r--src/etc/lldb_batchmode.py2
-rw-r--r--src/grammar/lexer.l73
-rw-r--r--src/grammar/parser-lalr.y366
-rw-r--r--src/grammar/tokens.h18
-rw-r--r--src/liballoc/allocator.rs6
-rw-r--r--src/liballoc/arc.rs6
-rw-r--r--src/liballoc/boxed.rs44
-rw-r--r--src/liballoc/fmt.rs1
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/rc.rs2
-rw-r--r--src/liballoc/str.rs4
-rw-r--r--src/liballoc/vec.rs25
-rw-r--r--src/liballoc_jemalloc/Cargo.toml2
-rw-r--r--src/liballoc_jemalloc/build.rs15
-rw-r--r--src/liballoc_system/lib.rs2
-rw-r--r--src/libcollections/Cargo.toml12
-rw-r--r--src/libcollections/lib.rs68
-rw-r--r--src/libcore/fmt/builders.rs10
-rw-r--r--src/libcore/fmt/mod.rs19
-rw-r--r--src/libcore/hash/sip.rs7
-rw-r--r--src/libcore/iter/iterator.rs186
-rw-r--r--src/libcore/macros.rs4
-rw-r--r--src/libcore/mem.rs10
-rw-r--r--src/libcore/ptr.rs12
-rw-r--r--src/libcore/result.rs2
-rw-r--r--src/libcore/str/mod.rs13
-rw-r--r--src/libcore/sync/atomic.rs17
-rw-r--r--src/libcore/tests/hash/sip.rs14
-rw-r--r--src/libcore/tests/mem.rs16
-rw-r--r--src/libcore/tests/num/flt2dec/estimator.rs5
m---------src/liblibc0
-rw-r--r--src/libproc_macro/lib.rs2
-rw-r--r--src/libprofiler_builtins/Cargo.toml2
-rw-r--r--src/librustc/README.md4
-rw-r--r--src/librustc/dep_graph/dep_node.rs42
-rw-r--r--src/librustc/dep_graph/graph.rs12
-rw-r--r--src/librustc/dep_graph/mod.rs3
-rw-r--r--src/librustc/hir/README.md4
-rw-r--r--src/librustc/hir/def_id.rs4
-rw-r--r--src/librustc/hir/intravisit.rs8
-rw-r--r--src/librustc/hir/itemlikevisit.rs2
-rw-r--r--src/librustc/hir/lowering.rs10
-rw-r--r--src/librustc/hir/map/definitions.rs21
-rw-r--r--src/librustc/hir/mod.rs4
-rw-r--r--src/librustc/hir/print.rs19
-rw-r--r--src/librustc/ich/fingerprint.rs15
-rw-r--r--src/librustc/ich/impls_hir.rs10
-rw-r--r--src/librustc/ich/impls_ty.rs131
-rw-r--r--src/librustc/infer/mod.rs6
-rw-r--r--src/librustc/lib.rs3
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc/middle/borrowck.rs31
-rw-r--r--src/librustc/middle/dataflow.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs22
-rw-r--r--src/librustc/middle/mem_categorization.rs46
-rw-r--r--src/librustc/middle/reachable.rs17
-rw-r--r--src/librustc/middle/region.rs31
-rw-r--r--src/librustc/middle/resolve_lifetime.rs4
-rw-r--r--src/librustc/middle/stability.rs2
-rw-r--r--src/librustc/mir/README.md6
-rw-r--r--src/librustc/mir/mod.rs34
-rw-r--r--src/librustc/session/config.rs60
-rw-r--r--src/librustc/session/filesearch.rs2
-rw-r--r--src/librustc/session/mod.rs91
-rw-r--r--src/librustc/traits/coherence.rs1
-rw-r--r--src/librustc/traits/error_reporting.rs215
-rw-r--r--src/librustc/traits/mod.rs94
-rw-r--r--src/librustc/traits/select.rs14
-rw-r--r--src/librustc/traits/trans/mod.rs162
-rw-r--r--src/librustc/ty/README.md10
-rw-r--r--src/librustc/ty/context.rs54
-rw-r--r--src/librustc/ty/erase_regions.rs79
-rw-r--r--src/librustc/ty/fold.rs61
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs151
-rw-r--r--src/librustc/ty/instance.rs3
-rw-r--r--src/librustc/ty/maps/README.md6
-rw-r--r--src/librustc/ty/maps/config.rs38
-rw-r--r--src/librustc/ty/maps/keys.rs18
-rw-r--r--src/librustc/ty/maps/mod.rs41
-rw-r--r--src/librustc/ty/maps/plumbing.rs240
-rw-r--r--src/librustc/ty/mod.rs17
-rw-r--r--src/librustc/ty/outlives.rs36
-rw-r--r--src/librustc/ty/sty.rs49
-rw-r--r--src/librustc/util/ppaux.rs1757
-rw-r--r--src/librustc_back/build.rs1
-rw-r--r--src/librustc_back/target/arm_linux_androideabi.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabi.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabihf.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_musleabi.rs2
-rw-r--r--src/librustc_back/target/arm_unknown_linux_musleabihf.rs2
-rw-r--r--src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs8
-rw-r--r--src/librustc_back/target/asmjs_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/le32_unknown_nacl.rs51
-rw-r--r--src/librustc_back/target/mod.rs13
-rw-r--r--src/librustc_back/target/msp430_none_elf.rs5
-rw-r--r--src/librustc_back/target/wasm32_experimental_emscripten.rs1
-rw-r--r--src/librustc_back/target/wasm32_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/windows_msvc_base.rs31
-rw-r--r--src/librustc_back/target/x86_64_rumprun_netbsd.rs1
-rw-r--r--src/librustc_back/target/x86_64_unknown_linux_gnux32.rs35
-rw-r--r--src/librustc_borrowck/Cargo.toml1
-rw-r--r--src/librustc_borrowck/borrowck/README.md5
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs15
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs19
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs39
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs138
-rw-r--r--src/librustc_borrowck/borrowck/unused.rs118
-rw-r--r--src/librustc_borrowck/diagnostics.rs735
-rw-r--r--src/librustc_borrowck/lib.rs10
-rw-r--r--src/librustc_const_eval/_match.rs12
-rw-r--r--src/librustc_const_eval/check_match.rs4
-rw-r--r--src/librustc_data_structures/graph/mod.rs15
-rw-r--r--src/librustc_data_structures/indexed_vec.rs75
-rw-r--r--src/librustc_data_structures/lib.rs2
-rw-r--r--src/librustc_data_structures/sip128.rs533
-rw-r--r--src/librustc_data_structures/stable_hasher.rs96
-rw-r--r--src/librustc_driver/driver.rs3
-rw-r--r--src/librustc_driver/lib.rs3
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs458
-rw-r--r--src/librustc_incremental/persist/file_format.rs2
-rw-r--r--src/librustc_incremental/persist/fs.rs21
-rw-r--r--src/librustc_incremental/persist/load.rs4
-rw-r--r--src/librustc_incremental/persist/save.rs73
-rw-r--r--src/librustc_incremental/persist/work_product.rs14
-rw-r--r--src/librustc_lint/Cargo.toml1
-rw-r--r--src/librustc_lint/builtin.rs65
-rw-r--r--src/librustc_lint/lib.rs2
-rw-r--r--src/librustc_lint/types.rs14
-rw-r--r--src/librustc_lint/unused.rs89
-rw-r--r--src/librustc_llvm/Cargo.toml2
-rw-r--r--src/librustc_llvm/build.rs3
-rw-r--r--src/librustc_llvm/ffi.rs56
-rw-r--r--src/librustc_llvm/lib.rs4
-rw-r--r--src/librustc_metadata/astencode.rs5
-rw-r--r--src/librustc_mir/borrow_check.rs310
-rw-r--r--src/librustc_mir/build/matches/mod.rs29
-rw-r--r--src/librustc_mir/build/matches/simplify.rs8
-rw-r--r--src/librustc_mir/build/mod.rs4
-rw-r--r--src/librustc_mir/build/scope.rs139
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs165
-rw-r--r--src/librustc_mir/dataflow/move_paths/mod.rs31
-rw-r--r--src/librustc_mir/diagnostics.rs775
-rw-r--r--src/librustc_mir/transform/dump_mir.rs13
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs2
-rw-r--r--src/librustc_mir/transform/generator.rs8
-rw-r--r--src/librustc_mir/transform/nll/infer.rs222
-rw-r--r--src/librustc_mir/transform/nll/mod.rs56
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs2
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs179
-rw-r--r--src/librustc_mir/util/liveness.rs2
-rw-r--r--src/librustc_mir/util/mod.rs2
-rw-r--r--src/librustc_mir/util/pretty.rs98
-rw-r--r--src/librustc_passes/ast_validation.rs2
-rw-r--r--src/librustc_passes/consts.rs112
-rw-r--r--src/librustc_passes/lib.rs6
-rw-r--r--src/librustc_resolve/diagnostics.rs6
-rw-r--r--src/librustc_resolve/lib.rs48
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs9
-rw-r--r--src/librustc_save_analysis/sig.rs8
-rw-r--r--src/librustc_trans/Cargo.toml2
-rw-r--r--src/librustc_trans/abi.rs28
-rw-r--r--src/librustc_trans/adt.rs2
-rw-r--r--src/librustc_trans/back/archive.rs7
-rw-r--r--src/librustc_trans/back/link.rs155
-rw-r--r--src/librustc_trans/back/lto.rs495
-rw-r--r--src/librustc_trans/back/symbol_names.rs54
-rw-r--r--src/librustc_trans/back/write.rs324
-rw-r--r--src/librustc_trans/base.rs102
-rw-r--r--src/librustc_trans/callee.rs7
-rw-r--r--src/librustc_trans/common.rs17
-rw-r--r--src/librustc_trans/context.rs2
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs9
-rw-r--r--src/librustc_trans/debuginfo/mod.rs4
-rw-r--r--src/librustc_trans/declare.rs5
-rw-r--r--src/librustc_trans/lib.rs37
-rw-r--r--src/librustc_trans/llvm_util.rs3
-rw-r--r--src/librustc_trans/meth.rs4
-rw-r--r--src/librustc_trans/mir/mod.rs29
-rw-r--r--src/librustc_trans/partitioning.rs150
-rw-r--r--src/librustc_trans/time_graph.rs152
-rw-r--r--src/librustc_trans/trans_item.rs372
-rw-r--r--src/librustc_trans_utils/Cargo.toml1
-rw-r--r--src/librustc_trans_utils/collector.rs (renamed from src/librustc_trans/collector.rs)13
-rw-r--r--src/librustc_trans_utils/common.rs78
-rw-r--r--src/librustc_trans_utils/lib.rs5
-rw-r--r--src/librustc_trans_utils/monomorphize.rs (renamed from src/librustc_trans/monomorphize.rs)11
-rw-r--r--src/librustc_trans_utils/trans_item.rs464
-rw-r--r--src/librustc_typeck/astconv.rs12
-rw-r--r--src/librustc_typeck/check/callee.rs3
-rw-r--r--src/librustc_typeck/check/compare_method.rs14
-rw-r--r--src/librustc_typeck/check/method/mod.rs17
-rw-r--r--src/librustc_typeck/check/method/probe.rs8
-rw-r--r--src/librustc_typeck/check/method/suggest.rs13
-rw-r--r--src/librustc_typeck/check/mod.rs60
-rw-r--r--src/librustc_typeck/check/regionck.rs3
-rw-r--r--src/librustc_typeck/check/writeback.rs3
-rw-r--r--src/librustc_typeck/check_unused.rs5
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs14
-rw-r--r--src/librustc_typeck/collect.rs52
-rw-r--r--src/librustc_typeck/diagnostics.rs5
-rw-r--r--src/librustc_typeck/lib.rs10
-rw-r--r--src/librustc_typeck/namespace.rs39
-rw-r--r--src/librustc_typeck/outlives/mod.rs29
-rw-r--r--src/librustc_typeck/outlives/test.rs41
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/cfg.rs3
-rw-r--r--src/librustdoc/clean/mod.rs48
-rw-r--r--src/librustdoc/externalfiles.rs9
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/layout.rs6
-rw-r--r--src/librustdoc/html/render.rs117
-rw-r--r--src/librustdoc/html/static/main.js257
-rw-r--r--src/librustdoc/html/static/rustdoc.css55
-rw-r--r--src/librustdoc/html/static/styles/main.css4
-rw-r--r--src/librustdoc/lib.rs55
-rw-r--r--src/librustdoc/markdown.rs18
-rw-r--r--src/librustdoc/test.rs101
-rw-r--r--src/libstd/Cargo.toml2
-rw-r--r--src/libstd/ascii.rs4
-rw-r--r--src/libstd/build.rs12
-rw-r--r--src/libstd/collections/hash/map.rs3
-rw-r--r--src/libstd/collections/hash/table.rs32
-rw-r--r--src/libstd/ffi/c_str.rs251
-rw-r--r--src/libstd/ffi/mod.rs151
-rw-r--r--src/libstd/ffi/os_str.rs50
-rw-r--r--src/libstd/io/impls.rs8
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/macros.rs4
-rw-r--r--src/libstd/net/tcp.rs94
-rw-r--r--src/libstd/net/udp.rs2
-rw-r--r--src/libstd/os/mod.rs1
-rw-r--r--src/libstd/os/nacl/fs.rs128
-rw-r--r--src/libstd/os/nacl/raw.rs56
-rw-r--r--src/libstd/primitive_docs.rs7
-rw-r--r--src/libstd/process.rs142
-rw-r--r--src/libstd/sync/mpsc/cache_aligned.rs37
-rw-r--r--src/libstd/sync/mpsc/mod.rs26
-rw-r--r--src/libstd/sync/mpsc/select.rs18
-rw-r--r--src/libstd/sync/mpsc/spsc_queue.rs153
-rw-r--r--src/libstd/sync/mpsc/stream.rs105
-rw-r--r--src/libstd/sync/mutex.rs13
-rw-r--r--src/libstd/sync/once.rs94
-rw-r--r--src/libstd/sync/rwlock.rs13
-rw-r--r--src/libstd/sys/unix/condvar.rs5
-rw-r--r--src/libstd/sys/unix/env.rs21
-rw-r--r--src/libstd/sys/unix/fs.rs4
-rw-r--r--src/libstd/sys/unix/mod.rs5
-rw-r--r--src/libstd/sys/unix/net.rs13
-rw-r--r--src/libstd/sys/unix/os.rs2
-rw-r--r--src/libstd/sys/unix/process/process_common.rs1
-rw-r--r--src/libstd/sys/unix/process/process_fuchsia.rs10
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs4
-rw-r--r--src/libstd/sys/unix/process/zircon.rs25
-rw-r--r--src/libstd/sys/unix/thread.rs2
-rw-r--r--src/libstd/sys/unix/time.rs4
-rw-r--r--src/libstd/sys/windows/c.rs18
-rw-r--r--src/libstd/sys/windows/ext/ffi.rs56
-rw-r--r--src/libstd/sys/windows/ext/fs.rs6
-rw-r--r--src/libstd/sys/windows/rand.rs38
-rw-r--r--src/libstd/sys_common/backtrace.rs2
-rw-r--r--src/libstd/sys_common/remutex.rs13
-rw-r--r--src/libstd/thread/local.rs5
-rw-r--r--src/libstd/thread/mod.rs12
-rw-r--r--src/libsyntax/ast.rs23
-rw-r--r--src/libsyntax/codemap.rs11
-rw-r--r--src/libsyntax/ext/placeholders.rs5
-rw-r--r--src/libsyntax/feature_gate.rs22
-rw-r--r--src/libsyntax/fold.rs7
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs2
-rw-r--r--src/libsyntax/parse/parser.rs150
-rw-r--r--src/libsyntax/parse/token.rs6
-rw-r--r--src/libsyntax/print/pprust.rs17
-rw-r--r--src/libsyntax/visit.rs16
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs3
-rw-r--r--src/libsyntax_pos/lib.rs7
-rw-r--r--src/libsyntax_pos/symbol.rs9
-rw-r--r--src/libtest/lib.rs6
m---------src/llvm0
-rw-r--r--src/rustc/compiler_builtins_shim/Cargo.toml2
-rw-r--r--src/rustllvm/PassWrapper.cpp516
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs7
-rw-r--r--src/test/codegen-units/item-collection/generic-drop-glue.rs13
-rw-r--r--src/test/codegen-units/item-collection/instantiation-through-vtable.rs5
-rw-r--r--src/test/codegen-units/item-collection/non-generic-drop-glue.rs5
-rw-r--r--src/test/codegen-units/item-collection/transitive-drop-glue.rs19
-rw-r--r--src/test/codegen-units/item-collection/tuple-drop-glue.rs9
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs9
-rw-r--r--src/test/codegen-units/partitioning/extern-drop-glue.rs1
-rw-r--r--src/test/codegen-units/partitioning/inlining-from-extern-crate.rs1
-rw-r--r--src/test/codegen-units/partitioning/local-drop-glue.rs1
-rw-r--r--src/test/codegen-units/partitioning/local-inlining-but-not-all.rs54
-rw-r--r--src/test/codegen-units/partitioning/local-inlining.rs1
-rw-r--r--src/test/codegen-units/partitioning/local-transitive-inlining.rs1
-rw-r--r--src/test/codegen-units/partitioning/vtable-through-const.rs1
-rw-r--r--src/test/codegen/abi-x86-interrupt.rs1
-rw-r--r--src/test/codegen/auxiliary/nounwind.rs13
-rw-r--r--src/test/codegen/float_math.rs2
-rw-r--r--src/test/codegen/issue-37945.rs1
-rw-r--r--src/test/codegen/mainsubprogram.rs7
-rw-r--r--src/test/codegen/mainsubprogramstart.rs7
-rw-r--r--src/test/codegen/nounwind.rs26
-rw-r--r--src/test/codegen/panic-abort-windows.rs2
-rw-r--r--src/test/compile-fail/borrowck/borrowck-assign-comp.rs4
-rw-r--r--src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs2
-rw-r--r--src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs330
-rw-r--r--src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-init-in-fru.rs8
-rw-r--r--src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs25
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs15
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs15
-rw-r--r--src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs11
-rw-r--r--src/test/compile-fail/borrowck/borrowck-unary-move.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs49
-rw-r--r--src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs60
-rw-r--r--src/test/compile-fail/borrowck/borrowck-union-borrow.rs12
-rw-r--r--src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs11
-rw-r--r--src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs7
-rw-r--r--src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs7
-rw-r--r--src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs11
-rw-r--r--src/test/compile-fail/dyn-trait-compatibility.rs29
-rw-r--r--src/test/compile-fail/feature-gate-crate_visibility_modifier.rs18
-rw-r--r--src/test/compile-fail/feature-gate-dyn-trait.rs14
-rw-r--r--src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs2
-rw-r--r--src/test/compile-fail/hygiene/impl_items.rs2
-rw-r--r--src/test/compile-fail/index-help.rs15
-rw-r--r--src/test/compile-fail/issue-12997-2.rs2
-rw-r--r--src/test/compile-fail/issue-30355.rs21
-rw-r--r--src/test/compile-fail/issue-33241.rs23
-rw-r--r--src/test/compile-fail/issue-37887.rs14
-rw-r--r--src/test/compile-fail/issue-44239.rs19
-rw-r--r--src/test/compile-fail/issue-44578.rs34
-rw-r--r--src/test/compile-fail/lint-unexported-no-mangle.rs5
-rw-r--r--src/test/compile-fail/macro-expanded-include/test.rs2
-rw-r--r--src/test/compile-fail/outlives-associated-types.rs23
-rw-r--r--src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs7
-rw-r--r--src/test/compile-fail/privacy/restricted/private-in-public.rs3
-rw-r--r--src/test/compile-fail/privacy/restricted/test.rs2
-rw-r--r--src/test/compile-fail/private-inferred-type-3.rs2
-rw-r--r--src/test/compile-fail/private-inferred-type.rs2
-rw-r--r--src/test/compile-fail/regions-fn-subtyping-return-static.rs4
-rw-r--r--src/test/compile-fail/trait-bounds-not-on-struct.rs3
-rw-r--r--src/test/debuginfo/pretty-std.rs4
-rw-r--r--src/test/incremental/hashes/call_expressions.rs50
-rw-r--r--src/test/incremental/hashes/consts.rs45
-rw-r--r--src/test/incremental/hashes/enum_constructors.rs111
-rw-r--r--src/test/incremental/hashes/enum_defs.rs162
-rw-r--r--src/test/incremental/hashes/extern_mods.rs56
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs229
-rw-r--r--src/test/incremental/hashes/let_expressions.rs160
-rw-r--r--src/test/incremental/hashes/statics.rs60
-rw-r--r--src/test/incremental/hashes/struct_constructors.rs60
-rw-r--r--src/test/incremental/hashes/type_defs.rs64
-rw-r--r--src/test/incremental/macro_export.rs (renamed from src/test/compile-fail/incr_comp_with_macro_export.rs)3
-rw-r--r--src/test/mir-opt/README.md33
-rw-r--r--src/test/mir-opt/box_expr.rs5
-rw-r--r--src/test/mir-opt/copy_propagation.rs6
-rw-r--r--src/test/mir-opt/deaggregator_test.rs6
-rw-r--r--src/test/mir-opt/deaggregator_test_enum.rs8
-rw-r--r--src/test/mir-opt/deaggregator_test_enum_2.rs10
-rw-r--r--src/test/mir-opt/deaggregator_test_multiple.rs10
-rw-r--r--src/test/mir-opt/end_region_1.rs4
-rw-r--r--src/test/mir-opt/end_region_2.rs6
-rw-r--r--src/test/mir-opt/end_region_3.rs6
-rw-r--r--src/test/mir-opt/end_region_4.rs5
-rw-r--r--src/test/mir-opt/end_region_5.rs3
-rw-r--r--src/test/mir-opt/end_region_6.rs5
-rw-r--r--src/test/mir-opt/end_region_7.rs6
-rw-r--r--src/test/mir-opt/end_region_8.rs3
-rw-r--r--src/test/mir-opt/end_region_9.rs7
-rw-r--r--src/test/mir-opt/end_region_cyclic.rs1
-rw-r--r--src/test/mir-opt/issue-41110.rs10
-rw-r--r--src/test/mir-opt/storage_live_dead_in_statics.rs200
-rw-r--r--src/test/mir-opt/storage_ranges.rs1
-rw-r--r--src/test/mir-opt/validate_1.rs9
-rw-r--r--src/test/mir-opt/validate_2.rs8
-rw-r--r--src/test/mir-opt/validate_3.rs15
-rw-r--r--src/test/mir-opt/validate_4.rs21
-rw-r--r--src/test/mir-opt/validate_5.rs9
-rw-r--r--src/test/parse-fail/issue-20711-2.rs2
-rw-r--r--src/test/parse-fail/issue-20711.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-static-fn.rs2
-rw-r--r--src/test/parse-fail/require-parens-for-chained-comparison.rs3
-rw-r--r--src/test/parse-fail/trait-object-bad-parens.rs2
-rw-r--r--src/test/pretty/issue-4264.pp50
-rw-r--r--src/test/run-fail/mir_drop_panics.rs3
-rw-r--r--src/test/run-fail/mir_dynamic_drops_1.rs5
-rw-r--r--src/test/run-fail/mir_dynamic_drops_2.rs5
-rw-r--r--src/test/run-fail/mir_dynamic_drops_3.rs5
-rw-r--r--src/test/run-fail/mir_trans_calls_converging_drops.rs6
-rw-r--r--src/test/run-fail/mir_trans_calls_converging_drops_2.rs6
-rw-r--r--src/test/run-fail/mir_trans_calls_diverging_drops.rs4
-rw-r--r--src/test/run-fail/panic-set-handler.rs3
-rw-r--r--src/test/run-fail/panic-set-unset-handler.rs3
-rw-r--r--src/test/run-make/archive-duplicate-names/Makefile2
-rw-r--r--src/test/run-make/compiler-rt-works-on-mingw/Makefile4
-rw-r--r--src/test/run-make/extra-filename-with-temp-outputs/Makefile2
-rw-r--r--src/test/run-make/inline-always-many-cgu/Makefile8
-rw-r--r--src/test/run-make/inline-always-many-cgu/foo.rs25
-rw-r--r--src/test/run-make/invalid-library/Makefile2
-rw-r--r--src/test/run-make/issue-19371/foo.rs7
-rw-r--r--src/test/run-make/issue-22131/Makefile2
-rw-r--r--src/test/run-make/rustdoc-output-path/Makefile2
-rw-r--r--src/test/run-make/sepcomp-cci-copies/Makefile5
-rw-r--r--src/test/run-make/sepcomp-inlining/Makefile11
-rw-r--r--src/test/run-make/sepcomp-separate/Makefile2
-rw-r--r--src/test/run-make/staticlib-blank-lib/Makefile4
-rw-r--r--src/test/run-make/target-specs/Makefile2
-rw-r--r--src/test/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json (renamed from src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json)2
-rw-r--r--src/test/run-make/tools.mk10
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs1
-rw-r--r--src/test/run-pass/asm-concat-src.rs2
-rw-r--r--src/test/run-pass/backtrace-debuginfo.rs4
-rw-r--r--src/test/run-pass/command-before-exec.rs2
-rw-r--r--src/test/run-pass/command-exec.rs3
-rw-r--r--src/test/run-pass/core-run-destroy.rs2
-rw-r--r--src/test/run-pass/dyn-trait.rs24
-rw-r--r--src/test/run-pass/dynamic-drop.rs36
-rw-r--r--src/test/run-pass/env-args-reverse-iterator.rs2
-rw-r--r--src/test/run-pass/env-funky-keys.rs2
-rw-r--r--src/test/run-pass/env-home-dir.rs2
-rw-r--r--src/test/run-pass/extern-pass-empty.rs2
-rw-r--r--src/test/run-pass/fds-are-cloexec.rs2
-rw-r--r--src/test/run-pass/format-no-std.rs2
-rw-r--r--src/test/run-pass/generator/smoke.rs2
-rw-r--r--src/test/run-pass/i128.rs2
-rw-r--r--src/test/run-pass/issue-10626.rs2
-rw-r--r--src/test/run-pass/issue-13304.rs3
-rw-r--r--src/test/run-pass/issue-14456.rs2
-rw-r--r--src/test/run-pass/issue-14940.rs2
-rw-r--r--src/test/run-pass/issue-16272.rs2
-rw-r--r--src/test/run-pass/issue-20091.rs3
-rw-r--r--src/test/run-pass/issue-2190-1.rs2
-rw-r--r--src/test/run-pass/issue-24313.rs2
-rw-r--r--src/test/run-pass/issue-28950.rs2
-rw-r--r--src/test/run-pass/issue-29485.rs2
-rw-r--r--src/test/run-pass/issue-29663.rs2
-rw-r--r--src/test/run-pass/issue-30490.rs2
-rw-r--r--src/test/run-pass/issue-33770.rs2
-rw-r--r--src/test/run-pass/issue-35600.rs24
-rw-r--r--src/test/run-pass/issue-36023.rs2
-rw-r--r--src/test/run-pass/issue-40003.rs186
-rw-r--r--src/test/run-pass/issue-44247.rs27
-rw-r--r--src/test/run-pass/issue-44402.rs36
-rw-r--r--src/test/run-pass/issue-45124.rs24
-rw-r--r--src/test/run-pass/linkage1.rs2
-rw-r--r--src/test/run-pass/macro-pub-matcher.rs14
-rw-r--r--src/test/run-pass/multi-panic.rs2
-rw-r--r--src/test/run-pass/no-stdio.rs2
-rw-r--r--src/test/run-pass/out-of-stack.rs2
-rw-r--r--src/test/run-pass/packed-struct-layout.rs2
-rw-r--r--src/test/run-pass/packed-tuple-struct-layout.rs2
-rw-r--r--src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs2
-rw-r--r--src/test/run-pass/panic-runtime/abort.rs2
-rw-r--r--src/test/run-pass/panic-runtime/lto-abort.rs2
-rw-r--r--src/test/run-pass/panic-runtime/lto-unwind.rs2
-rw-r--r--src/test/run-pass/process-envs.rs2
-rw-r--r--src/test/run-pass/process-exit.rs2
-rw-r--r--src/test/run-pass/process-remove-from-env.rs2
-rw-r--r--src/test/run-pass/process-spawn-with-unicode-params.rs2
-rw-r--r--src/test/run-pass/process-status-inherits-stdin.rs3
-rw-r--r--src/test/run-pass/running-with-no-runtime.rs2
-rw-r--r--src/test/run-pass/signal-exit-status.rs2
-rw-r--r--src/test/run-pass/sigpipe-should-be-ignored.rs2
-rw-r--r--src/test/run-pass/simd-intrinsic-generic-cast.rs3
-rw-r--r--src/test/run-pass/smallest-hello-world.rs41
-rw-r--r--src/test/run-pass/specialization/defaultimpl/allowed-cross-crate.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/assoc-fns.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs (renamed from src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs (renamed from src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/basics.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-basics.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs)6
-rw-r--r--src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs)6
-rw-r--r--src/test/run-pass/specialization/defaultimpl/cross-crate.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs)6
-rw-r--r--src/test/run-pass/specialization/defaultimpl/default-methods.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/out-of-order.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/overlap-projection.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/projection-alias.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs)0
-rw-r--r--src/test/run-pass/specialization/defaultimpl/projection.rs (renamed from src/test/run-pass/specialization/defaultimpl/specialization-projection.rs)0
-rw-r--r--src/test/run-pass/stack-probes-lto.rs2
-rw-r--r--src/test/run-pass/stack-probes.rs2
-rw-r--r--src/test/run-pass/stdio-is-blocking.rs2
-rw-r--r--src/test/run-pass/thin-lto-global-allocator.rs19
-rw-r--r--src/test/run-pass/thinlto/auxiliary/dylib.rs16
-rw-r--r--src/test/run-pass/thinlto/auxiliary/msvc-imp-present.rs21
-rw-r--r--src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs (renamed from src/libstd/os/nacl/mod.rs)11
-rw-r--r--src/test/run-pass/thinlto/dylib-works.rs18
-rw-r--r--src/test/run-pass/thinlto/msvc-imp-present.rs31
-rw-r--r--src/test/run-pass/thinlto/thin-lto-inlines.rs39
-rw-r--r--src/test/run-pass/thinlto/thin-lto-inlines2.rs38
-rw-r--r--src/test/run-pass/try-wait.rs2
-rw-r--r--src/test/run-pass/u128.rs2
-rw-r--r--src/test/run-pass/vec-macro-no-std.rs2
-rw-r--r--src/test/run-pass/wait-forked-but-failed-child.rs2
-rw-r--r--src/test/rustdoc/crate-version.rs13
-rw-r--r--src/test/rustdoc/empty-mod-private.rs2
-rw-r--r--src/test/rustdoc/fn-pointer-arg-name.rs15
-rw-r--r--src/test/rustdoc/issue-15347.rs2
-rw-r--r--src/test/rustdoc/pub-method.rs2
-rw-r--r--src/test/ui/anonymous-higher-ranked-lifetime.rs40
-rw-r--r--src/test/ui/anonymous-higher-ranked-lifetime.stderr112
-rw-r--r--src/test/ui/did_you_mean/issue-40396.stderr4
-rw-r--r--src/test/ui/issue-22644.rs2
-rw-r--r--src/test/ui/issue-22644.stderr13
-rw-r--r--src/test/ui/issue-36400.rs16
-rw-r--r--src/test/ui/issue-36400.stderr10
-rw-r--r--src/test/ui/issue-44406.rs19
-rw-r--r--src/test/ui/issue-44406.stderr26
-rw-r--r--src/test/ui/issue-45296.rs15
-rw-r--r--src/test/ui/issue-45296.stderr11
-rw-r--r--src/test/ui/lint/suggestions.rs17
-rw-r--r--src/test/ui/lint/suggestions.stderr95
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.rs2
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.stderr2
-rw-r--r--src/test/ui/method-call-err-msg.rs (renamed from src/test/compile-fail/method-call-err-msg.rs)0
-rw-r--r--src/test/ui/method-call-err-msg.stderr44
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.rs4
-rw-r--r--src/test/ui/mismatched_types/closure-arg-count.stderr42
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static.stderr4
-rw-r--r--src/test/ui/span/missing-unit-argument.rs8
-rw-r--r--src/test/ui/span/missing-unit-argument.stderr54
-rw-r--r--src/test/ui/struct-field-init-syntax.rs27
-rw-r--r--src/test/ui/struct-field-init-syntax.stderr18
-rw-r--r--src/test/ui/suggestions/closure-immutable-outer-variable.rs20
-rw-r--r--src/test/ui/suggestions/closure-immutable-outer-variable.stderr10
-rw-r--r--src/test/ui/suggestions/suggest-labels.rs26
-rw-r--r--src/test/ui/suggestions/suggest-labels.stderr20
-rw-r--r--src/tools/build-manifest/src/main.rs3
m---------src/tools/clippy29
-rw-r--r--src/tools/compiletest/src/common.rs2
-rw-r--r--src/tools/compiletest/src/errors.rs2
-rw-r--r--src/tools/compiletest/src/header.rs13
-rw-r--r--src/tools/compiletest/src/main.rs33
-rw-r--r--src/tools/compiletest/src/runtest.rs187
-rw-r--r--src/tools/compiletest/src/util.rs2
-rw-r--r--src/tools/tidy/src/lib.rs5
-rw-r--r--src/tools/tidy/src/main.rs3
-rw-r--r--src/tools/toolstate.toml7
595 files changed, 15140 insertions, 6774 deletions
diff --git a/.travis.yml b/.travis.yml
index 9e3225a103a..c76e17a27d1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,7 +12,7 @@ matrix:
   fast_finish: true
   include:
     # Images used in testing PR and try-build should be run first.
-    - env: IMAGE=x86_64-gnu-llvm-3.7 RUST_BACKTRACE=1
+    - env: IMAGE=x86_64-gnu-llvm-3.9 RUST_BACKTRACE=1
       if: type = pull_request OR branch = auto
 
     - env: IMAGE=dist-x86_64-linux DEPLOY=1
@@ -36,7 +36,7 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
       os: osx
-      osx_image: xcode7
+      osx_image: xcode7.3
       if: branch = auto
 
     # macOS builders. These are placed near the beginning because they are very
@@ -57,7 +57,7 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
       os: osx
-      osx_image: xcode8.2
+      osx_image: xcode8.3
       if: branch = auto
 
     - env: >
@@ -71,7 +71,7 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
       os: osx
-      osx_image: xcode8.2
+      osx_image: xcode8.3
       if: branch = auto
 
     # OSX builders producing releases. These do not run the full test suite and
@@ -91,7 +91,7 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
       os: osx
-      osx_image: xcode7
+      osx_image: xcode7.3
       if: branch = auto
 
     - env: >
@@ -105,7 +105,7 @@ matrix:
         NO_LLVM_ASSERTIONS=1
         NO_DEBUG_ASSERTIONS=1
       os: osx
-      osx_image: xcode7
+      osx_image: xcode7.3
       if: branch = auto
 
     # Linux builders, remaining docker images
@@ -115,6 +115,8 @@ matrix:
       if: branch = auto
     - env: IMAGE=cross DEPLOY=1
       if: branch = auto
+    - env: IMAGE=cross2 DEPLOY=1
+      if: branch = auto
     - env: IMAGE=dist-aarch64-linux DEPLOY=1
       if: branch = auto
     - env: IMAGE=dist-android DEPLOY=1
@@ -125,8 +127,6 @@ matrix:
       if: branch = auto
     - env: IMAGE=dist-armv7-linux DEPLOY=1
       if: branch = auto
-    - env: IMAGE=dist-fuchsia DEPLOY=1
-      if: branch = auto
     - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1
       if: branch = auto
     - env: IMAGE=dist-i686-freebsd DEPLOY=1
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 6bec9330186..d42476bc413 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -6,7 +6,7 @@ A version of this document [can be found online](https://www.rust-lang.org/condu
 
 **Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
 
-* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
+* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
 * On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
 * Please be kind and courteous. There's no need to be mean or rude.
 * Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a86742d7bd4..4c296a28e90 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -360,8 +360,120 @@ git add path/to/submodule
 
 outside the submodule.
 
-It can also be more convenient during development to set `submodules = false`
-in the `config.toml` to prevent `x.py` from resetting to the original branch.
+In order to prepare your PR, you can run the build locally by doing
+`./x.py build src/tools/TOOL`. If you will be editing the sources
+there, you may wish to set `submodules = false` in the `config.toml`
+to prevent `x.py` from resetting to the original branch.
+
+#### Breaking Tools Built With The Compiler
+[breaking-tools-built-with-the-compiler]: #breaking-tools-built-with-the-compiler
+
+Rust's build system builds a number of tools that make use of the
+internals of the compiler. This includes clippy,
+[RLS](https://github.com/rust-lang-nursery/rls) and
+[rustfmt](https://github.com/rust-lang-nursery/rustfmt). If these tools
+break because of your changes, you may run into a sort of "chicken and egg"
+problem. These tools rely on the latest compiler to be built so you can't update
+them to reflect your changes to the compiler until those changes are merged into
+the compiler. At the same time, you can't get your changes merged into the compiler
+because the rust-lang/rust build won't pass until those tools build and pass their
+tests.
+
+That means that, in the default state, you can't update the compiler without first
+fixing rustfmt, rls and the other tools that the compiler builds.
+
+Luckily, a feature was [added to Rust's build](https://github.com/rust-lang/rust/pull/45243)
+to make all of this easy to handle. The idea is that you mark the tools as "broken",
+so that the rust-lang/rust build passes without trying to build them, then land the change
+in the compiler, wait for a nightly, and go update the tools that you broke. Once you're done
+and the tools are working again, you go back in the compiler and change the tools back
+from "broken".
+
+This should avoid a bunch of synchronization dances and is also much easier on contributors as
+there's no need to block on rls/rustfmt/other tools changes going upstream.
+
+Here are those same steps in detail:
+
+1. (optional) First, if it doesn't exist already, create a `config.toml` by copying
+   `config.toml.example` in the root directory of the Rust repository.
+   Set `submodules = false` in the `[build]` section. This will prevent `x.py`
+   from resetting to the original branch after you make your changes. If you
+   need to [update any submodules to their latest versions][updating-submodules],
+   see the section of this file about that for more information.
+2. (optional) Run `./x.py test src/tools/rustfmt` (substituting the submodule
+   that broke for `rustfmt`). Fix any errors in the submodule (and possibly others).
+3. (optional) Make commits for your changes and send them to upstream repositories as a PR.
+4. (optional) Maintainers of these submodules will **not** merge the PR. The PR can't be
+   merged because CI will be broken. You'll want to write a message on the PR referencing
+   your change, and how the PR should be merged once your change makes it into a nightly.
+5. Update `src/tools/toolstate.toml` to indicate that the tool in question is "broken",
+   that will disable building it on CI. See the documentation in that file for the exact
+   configuration values you can use.
+6. Commit the changes to `src/tools/toolstate.toml`, **do not update submodules in your commit**,
+   and then update the PR you have for rust-lang/rust.
+7. Wait for your PR to merge.
+8. Wait for a nightly
+9. (optional) Help land your PR on the upstream repository now that your changes are in nightly.
+10. (optional) Send a PR to rust-lang/rust updating the submodule, reverting `src/tools/toolstate.toml` back to a "building" or "testing" state.
+
+#### Updating submodules
+[updating-submodules]: #updating-submodules
+
+These instructions are specific to updating `rustfmt`, however they may apply
+to the other submodules as well. Please help by improving these instructions
+if you find any discrepencies or special cases that need to be addressed.
+
+To update the `rustfmt` submodule, start by running the appropriate
+[`git submodule` command](https://git-scm.com/book/en/v2/Git-Tools-Submodules).
+For example, to update to the latest commit on the remote master branch,
+you may want to run:
+```
+git submodule update --remote src/tools/rustfmt
+```
+If you run `./x.py build` now, and you are lucky, it may just work. If you see
+an error message about patches that did not resolve to any crates, you will need
+to complete a few more steps which are outlined with their rationale below.
+
+*(This error may change in the future to include more information.)*
+```
+error: failed to resolve patches for `https://github.com/rust-lang-nursery/rustfmt`
+
+Caused by:
+  patch for `rustfmt-nightly` in `https://github.com/rust-lang-nursery/rustfmt` did not resolve to any crates
+failed to run: ~/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo build --manifest-path ~/rust/src/bootstrap/Cargo.toml
+```
+
+If you haven't used the `[patch]`
+section of `Cargo.toml` before, there is [some relevant documentation about it
+in the cargo docs](http://doc.crates.io/manifest.html#the-patch-section). In
+addition to that, you should read the 
+[Overriding dependencies](http://doc.crates.io/specifying-dependencies.html#overriding-dependencies)
+section of the documentation as well.
+
+Specifically, the following [section in Overriding dependencies](http://doc.crates.io/specifying-dependencies.html#testing-a-bugfix) reveals what the problem is:
+
+> Next up we need to ensure that our lock file is updated to use this new version of uuid so our project uses the locally checked out copy instead of one from crates.io. The way [patch] works is that it'll load the dependency at ../path/to/uuid and then whenever crates.io is queried for versions of uuid it'll also return the local version.
+> 
+> This means that the version number of the local checkout is significant and will affect whether the patch is used. Our manifest declared uuid = "1.0" which means we'll only resolve to >= 1.0.0, < 2.0.0, and Cargo's greedy resolution algorithm also means that we'll resolve to the maximum version within that range. Typically this doesn't matter as the version of the git repository will already be greater or match the maximum version published on crates.io, but it's important to keep this in mind!
+
+This says that when we updated the submodule, the version number in our
+`src/tools/rustfmt/Cargo.toml` changed. The new version is different from
+the version in `Cargo.lock`, so the build can no longer continue.
+
+To resolve this, we need to update `Cargo.lock`. Luckily, cargo provides a
+command to do this easily.
+
+First, go into the `src/` directory since that is where `Cargo.toml` is in
+the rust repository. Then run, `cargo update -p rustfmt-nightly` to solve
+the problem.
+
+```
+$ cd src
+$ cargo update -p rustfmt-nightly
+```
+
+This should change the version listed in `src/Cargo.lock` to the new version you updated
+the submodule to. Running `./x.py build` should work now.
 
 ## Writing Documentation
 [writing-documentation]: #writing-documentation
diff --git a/README.md b/README.md
index 95d543b8bb3..4fc003036e9 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ Read ["Installation"] from [The Book].
 ## Building from Source
 [building-from-source]: #building-from-source
 
+### Building on *nix
 1. Make sure you have installed the dependencies:
 
    * `g++` 4.7 or later or `clang++` 3.x or later
@@ -193,7 +194,7 @@ Snapshot binaries are currently built and tested on several platforms:
 You may find that other platforms work, but these are our officially
 supported build environments that are most likely to work.
 
-Rust currently needs between 600MiB and 1.5GiB to build, depending on platform.
+Rust currently needs between 600MiB and 1.5GiB of RAM to build, depending on platform.
 If it hits swap, it will take a very long time to build.
 
 There is more advice about hacking on Rust in [CONTRIBUTING.md].
diff --git a/RELEASES.md b/RELEASES.md
index e65934a89e6..194745d9caa 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -3,12 +3,6 @@ Version 1.21.0 (2017-10-12)
 
 Language
 --------
-- [Relaxed path syntax. You can now add type parameters to values][43540]
-  Example:
-  ```rust
-  my_macro!(Vec<i32>::new); // Always worked
-  my_macro!(Vec::<i32>::new); // Now works
-  ```
 - [You can now use static references for literals.][43838]
   Example:
   ```rust
@@ -16,6 +10,12 @@ Language
       let x: &'static u32 = &0;
   }
   ```
+- [Relaxed path syntax. Optional `::` before `<` is now allowed in all contexts.][43540]
+  Example:
+  ```rust
+  my_macro!(Vec<i32>::new); // Always worked
+  my_macro!(Vec::<i32>::new); // Now works
+  ```
 
 Compiler
 --------
diff --git a/config.toml.example b/config.toml.example
index a3790c8d202..261fe205387 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -35,7 +35,7 @@
 # If an external LLVM root is specified, we automatically check the version by
 # default to make sure it's within the range that we're expecting, but setting
 # this flag will indicate that this version check should not be done.
-#version-check = false
+#version-check = true
 
 # Link libstdc++ statically into the librustc_llvm instead of relying on a
 # dynamic version to be available.
@@ -250,14 +250,11 @@
 # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
 #backtrace = true
 
-# The default linker that will be used by the generated compiler. Note that this
-# is not the linker used to link said compiler.
+# The default linker that will be hard-coded into the generated compiler for
+# targets that don't specify linker explicitly in their target specifications.
+# Note that this is not the linker used to link said compiler.
 #default-linker = "cc"
 
-# The default ar utility that will be used by the generated compiler if LLVM
-# cannot be used. Note that this is not used to assemble said compiler.
-#default-ar = "ar"
-
 # The "channel" for the Rust build to produce. The stable/beta channels only
 # allow using stable features, whereas the nightly and dev channels allow using
 # nightly features
@@ -303,7 +300,7 @@
 # =============================================================================
 [target.x86_64-unknown-linux-gnu]
 
-# C compiler to be used to compiler C code and link Rust code. Note that the
+# C compiler to be used to compiler C code. Note that the
 # default value is platform specific, and if not specified it may also depend on
 # what platform is crossing to what platform.
 #cc = "cc"
@@ -312,6 +309,15 @@
 # This is only used for host targets.
 #cxx = "c++"
 
+# Archiver to be used to assemble static libraries compiled from C/C++ code.
+# Note: an absolute path should be used, otherwise LLVM build will break.
+#ar = "ar"
+
+# Linker to be used to link Rust code. Note that the
+# default value is platform specific, and if not specified it may also depend on
+# what platform is crossing to what platform.
+#linker = "cc"
+
 # Path to the `llvm-config` binary of the installation of a custom LLVM to link
 # against. Note that if this is specifed we don't compile LLVM at all for this
 # target.
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 934f5d6eed9..42705a0261d 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -1,7 +1,3 @@
-[root]
-name = "workspace_symbol"
-version = "0.1.0"
-
 [[package]]
 name = "advapi32-sys"
 version = "0.2.0"
@@ -42,7 +38,7 @@ dependencies = [
  "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core 0.0.0",
  "libc 0.0.0",
 ]
@@ -99,7 +95,7 @@ name = "backtrace-sys"
 version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -132,7 +128,7 @@ name = "bootstrap"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -195,7 +191,7 @@ dependencies = [
  "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jobserver 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "libgit2-sys 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -221,6 +217,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "cargo_metadata"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "cargotest"
 version = "0.1.0"
 dependencies = [
@@ -242,7 +248,7 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -267,26 +273,55 @@ dependencies = [
 ]
 
 [[package]]
-name = "cmake"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+name = "clippy"
+version = "0.0.166"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy-mini-macro-test 0.1.0",
+ "clippy_lints 0.0.166",
+ "compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
-name = "collections"
-version = "0.0.0"
+name = "clippy-mini-macro-test"
+version = "0.1.0"
+
+[[package]]
+name = "clippy_lints"
+version = "0.0.166"
 dependencies = [
- "alloc 0.0.0",
- "core 0.0.0",
+ "itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "compiler_builtins"
 version = "0.0.0"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core 0.0.0",
 ]
 
@@ -304,6 +339,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "compiletest_rs"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "completion"
 version = "0.1.0"
 
@@ -403,7 +447,7 @@ name = "curl-sys"
 version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "libz-sys 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "openssl-sys 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -466,6 +510,22 @@ version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "duct"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "either"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "enum_primitive"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -493,6 +553,14 @@ dependencies = [
 
 [[package]]
 name = "error-chain"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "error-chain"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -737,13 +805,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "itertools"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "itoa"
 version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "jobserver"
-version = "0.1.6"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -801,6 +877,11 @@ version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "lazycell"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "libc"
 version = "0.0.0"
 dependencies = [
@@ -817,7 +898,7 @@ name = "libgit2-sys"
 version = "0.6.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
  "curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -844,7 +925,7 @@ name = "libz-sys"
 version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -864,7 +945,7 @@ name = "lzma-sys"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -952,7 +1033,7 @@ name = "miniz-sys"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -984,6 +1065,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "nix"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "num"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1084,13 +1176,23 @@ name = "openssl-sys"
 version = "0.9.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
  "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
+name = "os_pipe"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "owning_ref"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1188,7 +1290,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "profiler_builtins"
 version = "0.0.0"
 dependencies = [
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "core 0.0.0",
 ]
 
@@ -1211,6 +1313,15 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
+version = "0.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pulldown-cmark"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1224,6 +1335,11 @@ version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "quine-mc_cluskey"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "quote"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1405,7 +1521,7 @@ dependencies = [
  "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
  "fmt_macros 0.0.0",
  "graphviz 0.0.0",
- "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jobserver 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_back 0.0.0",
@@ -1480,6 +1596,7 @@ dependencies = [
  "graphviz 0.0.0",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
+ "rustc_back 0.0.0",
  "rustc_errors 0.0.0",
  "rustc_mir 0.0.0",
  "syntax 0.0.0",
@@ -1587,7 +1704,6 @@ version = "0.0.0"
 dependencies = [
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
- "rustc_back 0.0.0",
  "rustc_const_eval 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
@@ -1599,7 +1715,7 @@ version = "0.0.0"
 dependencies = [
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc_cratesio_shim 0.0.0",
 ]
 
@@ -1731,9 +1847,9 @@ name = "rustc_trans"
 version = "0.0.0"
 dependencies = [
  "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
- "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jobserver 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1763,6 +1879,7 @@ dependencies = [
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
+ "rustc_data_structures 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
@@ -1800,7 +1917,7 @@ name = "rustdoc"
 version = "0.0.0"
 dependencies = [
  "build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1871,6 +1988,14 @@ dependencies = [
 
 [[package]]
 name = "semver"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
@@ -1931,6 +2056,16 @@ name = "serialize"
 version = "0.0.0"
 
 [[package]]
+name = "shared_child"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "shell-escape"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1970,8 +2105,6 @@ dependencies = [
  "alloc_jemalloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
- "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "collections 0.0.0",
  "compiler_builtins 0.0.0",
  "core 0.0.0",
  "libc 0.0.0",
@@ -2414,6 +2547,10 @@ dependencies = [
 ]
 
 [[package]]
+name = "workspace_symbol"
+version = "0.1.0"
+
+[[package]]
 name = "ws2_32-sys"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2457,10 +2594,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
 "checksum bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5cde24d1b2e2216a726368b2363a273739c91f4e3eb4e0dd12d672d396ad989"
 "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1"
+"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
+"checksum cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c674f0870e3dbd4105184ea035acb1c32c8ae69939c9e228d2b11bbfe29efad"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
 "checksum cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "357c07e7a1fc95732793c1edb5901e1a1f305cfcf63a90eb12dbd22bdb6b789d"
+"checksum compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2741d378feb7a434dba54228c89a70b4e427fee521de67cdda3750b8a0265f5a"
 "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
 "checksum core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5909502e547762013619f4c4e01cc7393c20fe2d52d7fa471c1210adb2320dc7"
 "checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387"
@@ -2477,10 +2616,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472"
 "checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
 "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
+"checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c"
+"checksum either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e311a7479512fbdf858fb54d91ec59f3b9f85bc0113659f46bba12b199d273ce"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
 "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
+"checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46"
 "checksum filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6ab199bf38537c6f38792669e081e0bb278b9b7405bba2642e4e5d15bf732c0e"
 "checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
@@ -2501,13 +2643,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum html5ever 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a49d5001dd1bddf042ea41ed4e0a671d50b1bf187e66b349d7ec613bdce4ad90"
 "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
 "checksum ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b3fcaf2365eb14b28ec7603c98c06cc531f19de9eb283d89a3dff8417c8c99f5"
+"checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21"
 "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
-"checksum jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "443ae8bc0af6c106e6e8b77e04684faecc1a5ce94e058f4c2b0a037b0ea1b133"
+"checksum jobserver 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "931b04e5e57d88cc909528f0d701db36a870b72a052648ded8baf80f9f445e0f"
 "checksum jsonrpc-core 7.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1acd0f9934da94466d2370f36832b9b19271b4abdfdb5e69f0bcd991ebcd515"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum kuchiki 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ef2ea4f2f7883cd7c6772b06c14abca01a2cc1f75c426cebffcf6b3b925ef9fc"
 "checksum languageserver-types 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d52e477b23bf52cd3ca0f9fc6c5d14be954eec97e3b9cdfbd962d911bd533caf"
 "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
+"checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b"
 "checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c"
 "checksum libgit2-sys 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "205fc37e829c5b36de63d14c8dc8b62c5a6a2519b16318ed0977079ca97256a9"
 "checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75"
@@ -2525,6 +2669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
 "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
 "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
+"checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487"
 "checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525"
 "checksum num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "8fd0f8dbb4c0960998958a796281d88c16fbe68d87b1baa6f31e2979e81fd0bd"
 "checksum num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "503e668405c5492d67cf662a81e05be40efe2e6bcf10f7794a07bd9865e704e6"
@@ -2537,6 +2682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum openssl 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "816914b22eb15671d62c73442a51978f311e911d6a6f6cbdafa6abce1b5038fc"
 "checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf"
 "checksum openssl-sys 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4c63a7d559c1e5afa6d6a9e6fa34bbc5f800ffc9ae08b72c605420b0c4f5e8"
+"checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1"
 "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
 "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
 "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
@@ -2549,8 +2695,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum procedural-masquerade 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c93cdc1fb30af9ddf3debc4afbdb0f35126cbd99daa229dd76cdd5349b41d989"
 "checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478"
 "checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973"
+"checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b"
 "checksum pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a656fdb8b6848f896df5e478a0eb9083681663e37dcb77dd16981ff65329fe8b"
 "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
+"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
 "checksum quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5cf478fe1006dbcc72567121d23dbdae5f1632386068c5c86ff4f645628504"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f120c7510ef7aff254aeb06067fb6fac573ec96a1660e194787cf9dced412bf0"
@@ -2571,6 +2719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
 "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57"
 "checksum selectors 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c89b1c6a3c029c82263f7dd2d44d0005ee7374eb09e254ab59dede4353a8c0"
+"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
 "checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 "checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799"
@@ -2578,6 +2727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58"
 "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
 "checksum serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d243424e06f9f9c39e3cd36147470fd340db785825e367625f79298a6ac6b7ac"
+"checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc"
 "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
 "checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
diff --git a/src/Cargo.toml b/src/Cargo.toml
index b703b2d7d29..39904927ca6 100644
--- a/src/Cargo.toml
+++ b/src/Cargo.toml
@@ -5,6 +5,7 @@ members = [
   "libstd",
   "libtest",
   "tools/cargotest",
+  "tools/clippy",
   "tools/compiletest",
   "tools/error_index_generator",
   "tools/linkchecker",
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 3f1d03b1872..bbbbf0e1915 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -34,7 +34,7 @@ cmake = "0.1.23"
 filetime = "0.1"
 num_cpus = "1.0"
 getopts = "0.2"
-cc = "1.0"
+cc = "1.0.1"
 libc = "0.2"
 serde = "1.0.8"
 serde_derive = "1.0.8"
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index e543b8c070b..9ff681ac680 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -39,7 +39,7 @@ The script accepts commands, flags, and arguments to determine what to do:
   ```
 
   If files are dirty that would normally be rebuilt from stage 0, that can be
-  overidden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps
+  overridden using `--keep-stage 0`. Using `--keep-stage n` will skip all steps
   that belong to stage n or earlier:
 
   ```
@@ -126,17 +126,17 @@ install a nightly, presumably using `rustup`. You will then want to
 configure your directory to use this build, like so:
 
 ```
-# configure to use local rust instead of downloding a beta.
+# configure to use local rust instead of downloading a beta.
 # `--local-rust-root` is optional here. If elided, we will
 # use whatever rustc we find on your PATH.
-> configure --enable-rustbuild --local-rust-root=~/.cargo/ --enable-local-rebuild
+> ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
 ```
 
 After that, you can use the `--incremental` flag to actually do
 incremental builds:
 
 ```
-> ../x.py build --incremental
+> ./x.py build --incremental
 ```
 
 The `--incremental` flag will store incremental compilation artifacts
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 848b10d312c..16a23eb364a 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -31,8 +31,6 @@ extern crate bootstrap;
 
 use std::env;
 use std::ffi::OsString;
-use std::io;
-use std::io::prelude::*;
 use std::str::FromStr;
 use std::path::PathBuf;
 use std::process::{Command, ExitStatus};
@@ -122,19 +120,14 @@ fn main() {
             cmd.arg("-L").arg(&root);
         }
 
-        // Pass down extra flags, commonly used to configure `-Clinker` when
-        // cross compiling.
-        if let Ok(s) = env::var("RUSTC_FLAGS") {
-            cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>());
+        // Override linker if necessary.
+        if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") {
+            cmd.arg(format!("-Clinker={}", target_linker));
         }
 
         // Pass down incremental directory, if any.
         if let Ok(dir) = env::var("RUSTC_INCREMENTAL") {
             cmd.arg(format!("-Zincremental={}", dir));
-
-            if verbose > 0 {
-                cmd.arg("-Zincremental-info");
-            }
         }
 
         let crate_name = args.windows(2)
@@ -182,6 +175,9 @@ fn main() {
         if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") {
             cmd.arg("-C").arg(format!("codegen-units={}", s));
         }
+        if stage != "0" && env::var("RUSTC_THINLTO").is_ok() {
+            cmd.arg("-Ccodegen-units=16").arg("-Zthinlto");
+        }
 
         // Emit save-analysis info.
         if env::var("RUSTC_SAVE_ANALYSIS") == Ok("api".to_string()) {
@@ -258,6 +254,11 @@ fn main() {
         if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
             cmd.arg("-Z").arg("force-unstable-if-unmarked");
         }
+    } else {
+        // Override linker if necessary.
+        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
+            cmd.arg(format!("-Clinker={}", host_linker));
+        }
     }
 
     let color = match env::var("RUSTC_COLOR") {
@@ -270,7 +271,7 @@ fn main() {
     }
 
     if verbose > 1 {
-        writeln!(&mut io::stderr(), "rustc command: {:?}", cmd).unwrap();
+        eprintln!("rustc command: {:?}", cmd);
     }
 
     // Actually run the compiler!
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs
index d7d72d5dd56..4e975adc972 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/bin/rustdoc.rs
@@ -47,6 +47,17 @@ fn main() {
     if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
         cmd.arg("-Z").arg("force-unstable-if-unmarked");
     }
+    if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") {
+        cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options");
+    }
+
+    // Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick
+    // it up so we can make rustdoc print this into the docs
+    if let Some(version) = env::var_os("RUSTDOC_CRATE_VERSION") {
+        // This "unstable-options" can be removed when `--crate-version` is stabilized
+        cmd.arg("-Z").arg("unstable-options")
+           .arg("--crate-version").arg(version);
+    }
 
     std::process::exit(match cmd.status() {
         Ok(s) => s.code().unwrap_or(1),
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 4a8c3dcebcb..0ab4c79e3b2 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -8,7 +8,7 @@
 # option. This file may not be copied, modified, or distributed
 # except according to those terms.
 
-from __future__ import print_function
+from __future__ import absolute_import, division, print_function
 import argparse
 import contextlib
 import datetime
@@ -302,6 +302,7 @@ def default_build_triple():
 
     return "{}-{}".format(cputype, ostype)
 
+
 class RustBuild(object):
     """Provide all the methods required to build Rust"""
     def __init__(self):
@@ -498,7 +499,7 @@ class RustBuild(object):
 
         If the key does not exists, the result is None:
 
-        >>> rb.get_toml("key3") == None
+        >>> rb.get_toml("key3") is None
         True
         """
         for line in self.config_toml.splitlines():
@@ -531,7 +532,7 @@ class RustBuild(object):
         """
         config = self.get_toml(program)
         if config:
-            return config
+            return os.path.expanduser(config)
         return os.path.join(self.bin_root(), "bin", "{}{}".format(
             program, self.exe_suffix()))
 
@@ -647,7 +648,8 @@ class RustBuild(object):
                       if not ((module.endswith("llvm") and
                                self.get_toml('llvm-config')) or
                               (module.endswith("jemalloc") and
-                               self.get_toml('jemalloc')))]
+                               (self.get_toml('use-jemalloc') == "false" or
+                                self.get_toml('jemalloc'))))]
         run(["git", "submodule", "update",
              "--init", "--recursive"] + submodules,
             cwd=self.rust_root, verbose=self.verbose)
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 32ea4b4abe6..4db7e2ec016 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -10,6 +10,7 @@
 
 """Bootstrap tests"""
 
+from __future__ import absolute_import, division, print_function
 import os
 import doctest
 import unittest
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index e7a5196178c..0dca395fa1f 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -413,12 +413,15 @@ impl<'a> Builder<'a> {
     pub fn rustdoc_cmd(&self, host: Interned<String>) -> Command {
         let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
         let compiler = self.compiler(self.top_stage, host);
-        cmd
-            .env("RUSTC_STAGE", compiler.stage.to_string())
-            .env("RUSTC_SYSROOT", self.sysroot(compiler))
-            .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
-            .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
-            .env("RUSTDOC_REAL", self.rustdoc(host));
+        cmd.env("RUSTC_STAGE", compiler.stage.to_string())
+           .env("RUSTC_SYSROOT", self.sysroot(compiler))
+           .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
+           .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
+           .env("RUSTDOC_REAL", self.rustdoc(host))
+           .env("RUSTDOC_CRATE_VERSION", self.build.rust_version());
+        if let Some(linker) = self.build.linker(host) {
+            cmd.env("RUSTC_TARGET_LINKER", linker);
+        }
         cmd
     }
 
@@ -468,8 +471,6 @@ impl<'a> Builder<'a> {
              .env("RUSTC", self.out.join("bootstrap/debug/rustc"))
              .env("RUSTC_REAL", self.rustc(compiler))
              .env("RUSTC_STAGE", stage.to_string())
-             .env("RUSTC_CODEGEN_UNITS",
-                  self.config.rust_codegen_units.to_string())
              .env("RUSTC_DEBUG_ASSERTIONS",
                   self.config.rust_debug_assertions.to_string())
              .env("RUSTC_SYSROOT", self.sysroot(compiler))
@@ -481,8 +482,18 @@ impl<'a> Builder<'a> {
              } else {
                  PathBuf::from("/path/to/nowhere/rustdoc/not/required")
              })
-             .env("TEST_MIRI", self.config.test_miri.to_string())
-             .env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
+             .env("TEST_MIRI", self.config.test_miri.to_string());
+
+        if let Some(n) = self.config.rust_codegen_units {
+            cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
+        }
+
+        if let Some(host_linker) = self.build.linker(compiler.host) {
+            cargo.env("RUSTC_HOST_LINKER", host_linker);
+        }
+        if let Some(target_linker) = self.build.linker(target) {
+            cargo.env("RUSTC_TARGET_LINKER", target_linker);
+        }
 
         if mode != Mode::Tool {
             // Tools don't get debuginfo right now, e.g. cargo and rls don't
@@ -556,17 +567,35 @@ impl<'a> Builder<'a> {
 
         cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity));
 
-        // Specify some various options for build scripts used throughout
-        // the build.
+        // Throughout the build Cargo can execute a number of build scripts
+        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
+        // obtained previously to those build scripts.
+        // Build scripts use either the `cc` crate or `configure/make` so we pass
+        // the options through environment variables that are fetched and understood by both.
         //
         // FIXME: the guard against msvc shouldn't need to be here
         if !target.contains("msvc") {
-            cargo.env(format!("CC_{}", target), self.cc(target))
-                 .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None
-                 .env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
+            let cc = self.cc(target);
+            cargo.env(format!("CC_{}", target), cc)
+                 .env("CC", cc);
+
+            let cflags = self.cflags(target).join(" ");
+            cargo.env(format!("CFLAGS_{}", target), cflags.clone())
+                 .env("CFLAGS", cflags.clone());
+
+            if let Some(ar) = self.ar(target) {
+                let ranlib = format!("{} s", ar.display());
+                cargo.env(format!("AR_{}", target), ar)
+                     .env("AR", ar)
+                     .env(format!("RANLIB_{}", target), ranlib.clone())
+                     .env("RANLIB", ranlib);
+            }
 
             if let Ok(cxx) = self.cxx(target) {
-                 cargo.env(format!("CXX_{}", target), cxx);
+                cargo.env(format!("CXX_{}", target), cxx)
+                     .env("CXX", cxx)
+                     .env(format!("CXXFLAGS_{}", target), cflags.clone())
+                     .env("CXXFLAGS", cflags);
             }
         }
 
@@ -574,6 +603,9 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
         }
 
+        // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
+        cargo.env("RUSTDOC_CRATE_VERSION", self.build.rust_version());
+
         // Environment variables *required* throughout the build
         //
         // FIXME: should update code to not require this env var
@@ -582,12 +614,20 @@ impl<'a> Builder<'a> {
         // Set this for all builds to make sure doc builds also get it.
         cargo.env("CFG_RELEASE_CHANNEL", &self.build.config.channel);
 
-        if self.is_verbose() {
+        if self.is_very_verbose() {
             cargo.arg("-v");
         }
         // FIXME: cargo bench does not accept `--release`
         if self.config.rust_optimize && cmd != "bench" {
             cargo.arg("--release");
+
+            if mode != Mode::Libstd &&
+               self.config.rust_codegen_units.is_none() &&
+               self.build.is_rust_llvm(compiler.host)
+
+            {
+                cargo.env("RUSTC_THINLTO", "1");
+            }
         }
         if self.config.locked_deps {
             cargo.arg("--locked");
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs
index 08df65c7611..6e3e3c92029 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/cc_detect.rs
@@ -31,20 +31,51 @@
 //! ever be probed for. Instead the compilers found here will be used for
 //! everything.
 
+use std::collections::HashSet;
+use std::{env, iter};
+use std::path::{Path, PathBuf};
 use std::process::Command;
-use std::iter;
 
-use build_helper::{cc2ar, output};
+use build_helper::output;
 use cc;
 
 use Build;
 use config::Target;
 use cache::Interned;
 
+// The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
+// so use some simplified logic here. First we respect the environment variable `AR`, then
+// try to infer the archiver path from the C compiler path.
+// In the future this logic should be replaced by calling into the `cc` crate.
+fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
+    if let Some(ar) = env::var_os("AR") {
+        Some(PathBuf::from(ar))
+    } else if target.contains("msvc") {
+        None
+    } else if target.contains("musl") {
+        Some(PathBuf::from("ar"))
+    } else if target.contains("openbsd") {
+        Some(PathBuf::from("ar"))
+    } else {
+        let parent = cc.parent().unwrap();
+        let file = cc.file_name().unwrap().to_str().unwrap();
+        for suffix in &["gcc", "cc", "clang"] {
+            if let Some(idx) = file.rfind(suffix) {
+                let mut file = file[..idx].to_owned();
+                file.push_str("ar");
+                return Some(parent.join(&file));
+            }
+        }
+        Some(parent.join(file))
+    }
+}
+
 pub fn find(build: &mut Build) {
     // For all targets we're going to need a C compiler for building some shims
     // and such as well as for being a linker for Rust code.
-    for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) {
+    let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build))
+                               .collect::<HashSet<_>>();
+    for target in targets.into_iter() {
         let mut cfg = cc::Build::new();
         cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false)
            .target(&target).host(&build.build);
@@ -57,16 +88,23 @@ pub fn find(build: &mut Build) {
         }
 
         let compiler = cfg.get_compiler();
-        let ar = cc2ar(compiler.path(), &target);
+        let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
+            ar
+        } else {
+            cc2ar(compiler.path(), &target)
+        };
+
         build.verbose(&format!("CC_{} = {:?}", &target, compiler.path()));
-        if let Some(ref ar) = ar {
+        build.cc.insert(target, compiler);
+        if let Some(ar) = ar {
             build.verbose(&format!("AR_{} = {:?}", &target, ar));
+            build.ar.insert(target, ar);
         }
-        build.cc.insert(target, (compiler, ar));
     }
 
     // For all host triples we need to find a C++ compiler as well
-    for host in build.hosts.iter().cloned().chain(iter::once(build.build)) {
+    let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::<HashSet<_>>();
+    for host in hosts.into_iter() {
         let mut cfg = cc::Build::new();
         cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true)
            .target(&host).host(&build.build);
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 6e276f44668..11bc9f7d217 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -246,8 +246,11 @@ impl Step for Rls {
         let compiler = builder.compiler(stage, host);
 
         builder.ensure(tool::Rls { compiler, target: self.host });
-        let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
-        cargo.arg("--manifest-path").arg(build.src.join("src/tools/rls/Cargo.toml"));
+        let mut cargo = tool::prepare_tool_cargo(builder,
+                                                 compiler,
+                                                 host,
+                                                 "test",
+                                                 "src/tools/rls");
 
         // Don't build tests dynamically, just a pain to work with
         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
@@ -291,8 +294,11 @@ impl Step for Rustfmt {
         let compiler = builder.compiler(stage, host);
 
         builder.ensure(tool::Rustfmt { compiler, target: self.host });
-        let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
-        cargo.arg("--manifest-path").arg(build.src.join("src/tools/rustfmt/Cargo.toml"));
+        let mut cargo = tool::prepare_tool_cargo(builder,
+                                                 compiler,
+                                                 host,
+                                                 "test",
+                                                 "src/tools/rustfmt");
 
         // Don't build tests dynamically, just a pain to work with
         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
@@ -334,30 +340,34 @@ impl Step for Miri {
         let host = self.host;
         let compiler = builder.compiler(1, host);
 
-        let miri = builder.ensure(tool::Miri { compiler, target: self.host });
-        let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
-        cargo.arg("--manifest-path").arg(build.src.join("src/tools/miri/Cargo.toml"));
-
-        // Don't build tests dynamically, just a pain to work with
-        cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
-        // miri tests need to know about the stage sysroot
-        cargo.env("MIRI_SYSROOT", builder.sysroot(compiler));
-        cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
-        cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
-        cargo.env("MIRI_PATH", miri);
-
-        builder.add_rustc_lib_path(compiler, &mut cargo);
-
-        try_run_expecting(
-            build,
-            &mut cargo,
-            builder.build.config.toolstate.miri.passes(ToolState::Testing),
-        );
+        if let Some(miri) = builder.ensure(tool::Miri { compiler, target: self.host }) {
+            let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
+            cargo.arg("--manifest-path").arg(build.src.join("src/tools/miri/Cargo.toml"));
+
+            // Don't build tests dynamically, just a pain to work with
+            cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
+            // miri tests need to know about the stage sysroot
+            cargo.env("MIRI_SYSROOT", builder.sysroot(compiler));
+            cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
+            cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
+            cargo.env("MIRI_PATH", miri);
+
+            builder.add_rustc_lib_path(compiler, &mut cargo);
+
+            try_run_expecting(
+                build,
+                &mut cargo,
+                builder.build.config.toolstate.miri.passes(ToolState::Testing),
+            );
+        } else {
+            eprintln!("failed to test miri: could not build");
+        }
     }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Clippy {
+    stage: u32,
     host: Interned<String>,
 }
 
@@ -372,6 +382,7 @@ impl Step for Clippy {
 
     fn make_run(run: RunConfig) {
         run.builder.ensure(Clippy {
+            stage: run.builder.top_stage,
             host: run.target,
         });
     }
@@ -379,25 +390,31 @@ impl Step for Clippy {
     /// Runs `cargo test` for clippy.
     fn run(self, builder: &Builder) {
         let build = builder.build;
+        let stage = self.stage;
         let host = self.host;
-        let compiler = builder.compiler(1, host);
+        let compiler = builder.compiler(stage, host);
 
-        let _clippy = builder.ensure(tool::Clippy { compiler, target: self.host });
-        let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
-        cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml"));
+        if let Some(clippy) = builder.ensure(tool::Clippy { compiler, target: self.host }) {
+            let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
+            cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml"));
 
-        // Don't build tests dynamically, just a pain to work with
-        cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
-        // clippy tests need to know about the stage sysroot
-        cargo.env("SYSROOT", builder.sysroot(compiler));
+            // Don't build tests dynamically, just a pain to work with
+            cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
+            // clippy tests need to know about the stage sysroot
+            cargo.env("SYSROOT", builder.sysroot(compiler));
+            // clippy tests need to find the driver
+            cargo.env("CLIPPY_DRIVER_PATH", clippy);
 
-        builder.add_rustc_lib_path(compiler, &mut cargo);
+            builder.add_rustc_lib_path(compiler, &mut cargo);
 
-        try_run_expecting(
-            build,
-            &mut cargo,
-            builder.build.config.toolstate.clippy.passes(ToolState::Testing),
-        );
+            try_run_expecting(
+                build,
+                &mut cargo,
+                builder.build.config.toolstate.clippy.passes(ToolState::Testing),
+            );
+        } else {
+            eprintln!("failed to test clippy: could not build");
+        }
     }
 }
 
@@ -736,12 +753,14 @@ impl Step for Compiletest {
             flags.push("-g".to_string());
         }
 
-        let mut hostflags = build.rustc_flags(compiler.host);
-        hostflags.extend(flags.clone());
+        if let Some(linker) = build.linker(target) {
+            cmd.arg("--linker").arg(linker);
+        }
+
+        let hostflags = flags.clone();
         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
 
-        let mut targetflags = build.rustc_flags(target);
-        targetflags.extend(flags);
+        let mut targetflags = flags.clone();
         targetflags.push(format!("-Lnative={}",
                                  build.test_helpers_out(target).display()));
         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
@@ -795,6 +814,9 @@ impl Step for Compiletest {
                 .arg("--cflags").arg(build.cflags(target).join(" "))
                 .arg("--llvm-components").arg(llvm_components.trim())
                 .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim());
+                if let Some(ar) = build.ar(target) {
+                    cmd.arg("--ar").arg(ar);
+                }
             }
         }
         if suite == "run-make" && !build.config.llvm_enabled {
@@ -820,7 +842,7 @@ impl Step for Compiletest {
         // Note that if we encounter `PATH` we make sure to append to our own `PATH`
         // rather than stomp over it.
         if target.contains("msvc") {
-            for &(ref k, ref v) in build.cc[&target].0.env() {
+            for &(ref k, ref v) in build.cc[&target].env() {
                 if k != "PATH" {
                     cmd.env(k, v);
                 }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 335e1690a2e..a8162f0a92f 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -29,7 +29,7 @@ use build_helper::{output, mtime, up_to_date};
 use filetime::FileTime;
 use serde_json;
 
-use util::{exe, libdir, is_dylib, copy};
+use util::{exe, libdir, is_dylib, copy, read_stamp_file, CiEnv};
 use {Build, Compiler, Mode};
 use native;
 use tool;
@@ -102,7 +102,7 @@ impl Step for Std {
             copy_musl_third_party_objects(build, target, &libdir);
         }
 
-        let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
+        let out_dir = build.stage_out(compiler, Mode::Libstd);
         build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
         let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
         std_cargo(build, &compiler, target, &mut cargo);
@@ -354,7 +354,7 @@ impl Step for Test {
         let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
         println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
                 &compiler.host, target);
-        let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
+        let out_dir = build.stage_out(compiler, Mode::Libtest);
         build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
         let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build");
         test_cargo(build, &compiler, target, &mut cargo);
@@ -480,8 +480,9 @@ impl Step for Rustc {
         println!("Building stage{} compiler artifacts ({} -> {})",
                  compiler.stage, &compiler.host, target);
 
-        let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
-        build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target));
+        let stage_out = builder.stage_out(compiler, Mode::Librustc);
+        build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
+        build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
 
         let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
         rustc_cargo(build, &compiler, target, &mut cargo);
@@ -560,9 +561,6 @@ pub fn rustc_cargo(build: &Build,
     if let Some(ref s) = build.config.rustc_default_linker {
         cargo.env("CFG_DEFAULT_LINKER", s);
     }
-    if let Some(ref s) = build.config.rustc_default_ar {
-        cargo.env("CFG_DEFAULT_AR", s);
-    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -760,15 +758,7 @@ impl Step for Assemble {
 /// `sysroot_dst` provided.
 fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
     t!(fs::create_dir_all(&sysroot_dst));
-    let mut contents = Vec::new();
-    t!(t!(File::open(stamp)).read_to_end(&mut contents));
-    // This is the method we use for extracting paths from the stamp file passed to us. See
-    // run_cargo for more information (in this file).
-    for part in contents.split(|b| *b == 0) {
-        if part.is_empty() {
-            continue
-        }
-        let path = Path::new(t!(str::from_utf8(part)));
+    for path in read_stamp_file(stamp) {
         copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
     }
 }
@@ -802,7 +792,7 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) {
     cargo.arg("--message-format").arg("json")
          .stdout(Stdio::piped());
 
-    if stderr_isatty() {
+    if stderr_isatty() && build.ci_env == CiEnv::None {
         // since we pass message-format=json to cargo, we need to tell the rustc
         // wrapper to give us colored output if necessary. This is because we
         // only want Cargo's JSON output, not rustcs.
@@ -941,6 +931,8 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) {
     let max = max.unwrap();
     let max_path = max_path.unwrap();
     if stamp_contents == new_contents && max <= stamp_mtime {
+        build.verbose(&format!("not updating {:?}; contents equal and {} <= {}",
+                stamp, max, stamp_mtime));
         return
     }
     if max > stamp_mtime {
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index c8b2ed042c1..66e5efcea4e 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -81,14 +81,13 @@ pub struct Config {
 
     // rust codegen options
     pub rust_optimize: bool,
-    pub rust_codegen_units: u32,
+    pub rust_codegen_units: Option<u32>,
     pub rust_debug_assertions: bool,
     pub rust_debuginfo: bool,
     pub rust_debuginfo_lines: bool,
     pub rust_debuginfo_only_std: bool,
     pub rust_rpath: bool,
     pub rustc_default_linker: Option<String>,
-    pub rustc_default_ar: Option<String>,
     pub rust_optimize_tests: bool,
     pub rust_debuginfo_tests: bool,
     pub rust_dist_src: bool,
@@ -144,6 +143,8 @@ pub struct Target {
     pub jemalloc: Option<PathBuf>,
     pub cc: Option<PathBuf>,
     pub cxx: Option<PathBuf>,
+    pub ar: Option<PathBuf>,
+    pub linker: Option<PathBuf>,
     pub ndk: Option<PathBuf>,
     pub crt_static: Option<bool>,
     pub musl_root: Option<PathBuf>,
@@ -262,7 +263,6 @@ struct Rust {
     use_jemalloc: Option<bool>,
     backtrace: Option<bool>,
     default_linker: Option<String>,
-    default_ar: Option<String>,
     channel: Option<String>,
     musl_root: Option<String>,
     rpath: Option<bool>,
@@ -284,6 +284,8 @@ struct TomlTarget {
     jemalloc: Option<String>,
     cc: Option<String>,
     cxx: Option<String>,
+    ar: Option<String>,
+    linker: Option<String>,
     android_ndk: Option<String>,
     crt_static: Option<bool>,
     musl_root: Option<String>,
@@ -297,6 +299,7 @@ impl Config {
         let mut config = Config::default();
         config.llvm_enabled = true;
         config.llvm_optimize = true;
+        config.llvm_version_check = true;
         config.use_jemalloc = true;
         config.backtrace = true;
         config.rust_optimize = true;
@@ -304,7 +307,6 @@ impl Config {
         config.submodules = true;
         config.docs = true;
         config.rust_rpath = true;
-        config.rust_codegen_units = 1;
         config.channel = "dev".to_string();
         config.codegen_tests = true;
         config.ignore_git = false;
@@ -464,12 +466,11 @@ impl Config {
             set(&mut config.quiet_tests, rust.quiet_tests);
             set(&mut config.test_miri, rust.test_miri);
             config.rustc_default_linker = rust.default_linker.clone();
-            config.rustc_default_ar = rust.default_ar.clone();
             config.musl_root = rust.musl_root.clone().map(PathBuf::from);
 
             match rust.codegen_units {
-                Some(0) => config.rust_codegen_units = num_cpus::get() as u32,
-                Some(n) => config.rust_codegen_units = n,
+                Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32),
+                Some(n) => config.rust_codegen_units = Some(n),
                 None => {}
             }
         }
@@ -487,8 +488,10 @@ impl Config {
                 if let Some(ref s) = cfg.android_ndk {
                     target.ndk = Some(env::current_dir().unwrap().join(s));
                 }
-                target.cxx = cfg.cxx.clone().map(PathBuf::from);
                 target.cc = cfg.cc.clone().map(PathBuf::from);
+                target.cxx = cfg.cxx.clone().map(PathBuf::from);
+                target.ar = cfg.ar.clone().map(PathBuf::from);
+                target.linker = cfg.linker.clone().map(PathBuf::from);
                 target.crt_static = cfg.crt_static.clone();
                 target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
                 target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 67337bf4421..42425a164a2 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -11,6 +11,7 @@
 
 # ignore-tidy-linelength
 
+from __future__ import absolute_import, division, print_function
 import sys
 import os
 rust_dir = os.path.dirname(os.path.abspath(__file__))
@@ -19,21 +20,26 @@ rust_dir = os.path.dirname(rust_dir)
 sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))
 import bootstrap
 
-class Option:
+
+class Option(object):
     def __init__(self, name, rustbuild, desc, value):
         self.name = name
         self.rustbuild = rustbuild
         self.desc = desc
         self.value = value
 
+
 options = []
 
+
 def o(*args):
     options.append(Option(*args, value=False))
 
+
 def v(*args):
     options.append(Option(*args, value=True))
 
+
 o("debug", "rust.debug", "debug mode; disables optimization unless `--enable-optimize` given")
 o("docs", "build.docs", "build standard library documentation")
 o("compiler-docs", "build.compiler-docs", "build compiler documentation")
@@ -119,9 +125,8 @@ v("experimental-targets", "llvm.experimental-targets",
   "experimental LLVM targets to build")
 v("release-channel", "rust.channel", "the name of the release channel to build")
 
-# Used on systems where "cc" and "ar" are unavailable
+# Used on systems where "cc" is unavailable
 v("default-linker", "rust.default-linker", "the default linker")
-v("default-ar", "rust.default-ar", "the default ar")
 
 # Many of these are saved below during the "writing configuration" step
 # (others are conditionally saved).
@@ -136,13 +141,16 @@ v("target", None, "GNUs ./configure syntax LLVM target triples")
 
 v("set", None, "set arbitrary key/value pairs in TOML configuration")
 
+
 def p(msg):
     print("configure: " + msg)
 
+
 def err(msg):
     print("configure: error: " + msg)
     sys.exit(1)
 
+
 if '--help' in sys.argv or '-h' in sys.argv:
     print('Usage: ./configure [options]')
     print('')
@@ -208,7 +216,7 @@ while i < len(sys.argv):
                 continue
 
         found = True
-        if not option.name in known_args:
+        if option.name not in known_args:
             known_args[option.name] = []
         known_args[option.name].append((option, value))
         break
@@ -227,27 +235,30 @@ if 'option-checking' not in known_args or known_args['option-checking'][1]:
 # TOML we're going to write out
 config = {}
 
+
 def build():
     if 'build' in known_args:
         return known_args['build'][0][1]
     return bootstrap.default_build_triple()
 
+
 def set(key, value):
-      s = "{:20} := {}".format(key, value)
-      if len(s) < 70:
-          p(s)
-      else:
-          p(s[:70] + " ...")
-
-      arr = config
-      parts = key.split('.')
-      for i, part in enumerate(parts):
-          if i == len(parts) - 1:
-              arr[part] = value
-          else:
-              if not part in arr:
-                  arr[part] = {}
-              arr = arr[part]
+    s = "{:20} := {}".format(key, value)
+    if len(s) < 70:
+        p(s)
+    else:
+        p(s[:70] + " ...")
+
+    arr = config
+    parts = key.split('.')
+    for i, part in enumerate(parts):
+        if i == len(parts) - 1:
+            arr[part] = value
+        else:
+            if part not in arr:
+                arr[part] = {}
+            arr = arr[part]
+
 
 for key in known_args:
     # The `set` option is special and can be passed a bunch of times
@@ -345,8 +356,9 @@ for target in configured_targets:
     targets[target] = sections['target'][:]
     targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", target)
 
+
 # Here we walk through the constructed configuration we have from the parsed
-# command line arguemnts. We then apply each piece of configuration by
+# command line arguments. We then apply each piece of configuration by
 # basically just doing a `sed` to change the various configuration line to what
 # we've got configure.
 def to_toml(value):
@@ -360,7 +372,8 @@ def to_toml(value):
     elif isinstance(value, str):
         return "'" + value + "'"
     else:
-        raise 'no toml'
+        raise RuntimeError('no toml')
+
 
 def configure_section(lines, config):
     for key in config:
@@ -375,10 +388,11 @@ def configure_section(lines, config):
         if not found:
             raise RuntimeError("failed to find config line for {}".format(key))
 
+
 for section_key in config:
     section_config = config[section_key]
-    if not section_key in sections:
-        raise RuntimeError("config key {} not in sections".format(key))
+    if section_key not in sections:
+        raise RuntimeError("config key {} not in sections".format(section_key))
 
     if section_key == 'target':
         for target in section_config:
@@ -407,11 +421,6 @@ with open('Makefile', 'w') as f:
     contents = contents.replace("$(CFG_PYTHON)", sys.executable)
     f.write(contents)
 
-# Finally, clean up with a bit of a help message
-relpath = os.path.dirname(__file__)
-if relpath == '':
-    relpath = '.'
-
 p("")
-p("run `python {}/x.py --help`".format(relpath))
+p("run `python {}/x.py --help`".format(rust_dir))
 p("")
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 3d4aa0413db..e79f6e086ae 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -176,7 +176,7 @@ fn make_win_dist(
         }
     }
 
-    let target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"];
+    let target_tools = ["gcc.exe", "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
     let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"];
     if target_triple.starts_with("i686-") {
         rustc_dlls.push("libgcc_s_dw2-1.dll");
@@ -630,7 +630,7 @@ impl Step for Analysis {
         let image = tmpdir(build).join(format!("{}-{}-image", name, target));
 
         let src = build.stage_out(compiler, Mode::Libstd)
-            .join(target).join("release").join("deps");
+            .join(target).join(build.cargo_dir()).join("deps");
 
         let image_src = src.join("save-analysis");
         let dst = image.join("lib/rustlib").join(target).join("analysis");
@@ -738,7 +738,6 @@ impl Step for Src {
             "src/liballoc_jemalloc",
             "src/liballoc_system",
             "src/libbacktrace",
-            "src/libcollections",
             "src/libcompiler_builtins",
             "src/libcore",
             "src/liblibc",
@@ -1035,7 +1034,7 @@ pub struct Rls {
 }
 
 impl Step for Rls {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const ONLY_BUILD_TARGETS: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -1050,12 +1049,17 @@ impl Step for Rls {
         });
     }
 
-    fn run(self, builder: &Builder) -> PathBuf {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         let build = builder.build;
         let stage = self.stage;
         let target = self.target;
         assert!(build.config.extended);
 
+        if !builder.config.toolstate.rls.testing() {
+            println!("skipping Dist RLS stage{} ({})", stage, target);
+            return None
+        }
+
         println!("Dist RLS stage{} ({})", stage, target);
         let src = build.src.join("src/tools/rls");
         let release_num = build.release_num("rls");
@@ -1068,10 +1072,12 @@ impl Step for Rls {
         t!(fs::create_dir_all(&image));
 
         // Prepare the image directory
+        // We expect RLS to build, because we've exited this step above if tool
+        // state for RLS isn't testing.
         let rls = builder.ensure(tool::Rls {
             compiler: builder.compiler(stage, build.build),
             target
-        });
+        }).expect("Rls to build: toolstate is testing");
         install(&rls, &image.join("bin"), 0o755);
         let doc = image.join("share/doc/rls");
         install(&src.join("README.md"), &doc, 0o644);
@@ -1102,7 +1108,7 @@ impl Step for Rls {
            .arg("--component-name=rls-preview");
 
         build.run(&mut cmd);
-        distdir(build).join(format!("{}-{}.tar.gz", name, target))
+        Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
     }
 }
 
@@ -1202,8 +1208,12 @@ impl Step for Extended {
         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
         // the std files during uninstall. To do this ensure that rustc comes
         // before rust-std in the list below.
-        let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
-                                analysis_installer, std_installer];
+        let mut tarballs = Vec::new();
+        tarballs.push(rustc_installer);
+        tarballs.push(cargo_installer);
+        tarballs.extend(rls_installer.clone());
+        tarballs.push(analysis_installer);
+        tarballs.push(std_installer);
         if build.config.docs {
             tarballs.push(docs_installer);
         }
@@ -1245,35 +1255,38 @@ impl Step for Extended {
         }
         rtf.push_str("}");
 
+        fn filter(contents: &str, marker: &str) -> String {
+            let start = format!("tool-{}-start", marker);
+            let end = format!("tool-{}-end", marker);
+            let mut lines = Vec::new();
+            let mut omitted = false;
+            for line in contents.lines() {
+                if line.contains(&start) {
+                    omitted = true;
+                } else if line.contains(&end) {
+                    omitted = false;
+                } else if !omitted {
+                    lines.push(line);
+                }
+            }
+
+            lines.join("\n")
+        }
+
+        let xform = |p: &Path| {
+            let mut contents = String::new();
+            t!(t!(File::open(p)).read_to_string(&mut contents));
+            if rls_installer.is_none() {
+                contents = filter(&contents, "rls");
+            }
+            let ret = tmp.join(p.file_name().unwrap());
+            t!(t!(File::create(&ret)).write_all(contents.as_bytes()));
+            return ret
+        };
+
         if target.contains("apple-darwin") {
             let pkg = tmp.join("pkg");
             let _ = fs::remove_dir_all(&pkg);
-            t!(fs::create_dir_all(pkg.join("rustc")));
-            t!(fs::create_dir_all(pkg.join("cargo")));
-            t!(fs::create_dir_all(pkg.join("rust-docs")));
-            t!(fs::create_dir_all(pkg.join("rust-std")));
-            t!(fs::create_dir_all(pkg.join("rls")));
-            t!(fs::create_dir_all(pkg.join("rust-analysis")));
-
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)),
-                    &pkg.join("rustc"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)),
-                    &pkg.join("cargo"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)),
-                    &pkg.join("rust-docs"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)),
-                    &pkg.join("rust-std"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)),
-                    &pkg.join("rls"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)),
-                    &pkg.join("rust-analysis"));
-
-            install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755);
-            install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755);
-            install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755);
-            install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755);
-            install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755);
-            install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755);
 
             let pkgbuild = |component: &str| {
                 let mut cmd = Command::new("pkgbuild");
@@ -1283,12 +1296,23 @@ impl Step for Extended {
                     .arg(pkg.join(component).with_extension("pkg"));
                 build.run(&mut cmd);
             };
-            pkgbuild("rustc");
-            pkgbuild("cargo");
-            pkgbuild("rust-docs");
-            pkgbuild("rust-std");
-            pkgbuild("rls");
-            pkgbuild("rust-analysis");
+
+            let prepare = |name: &str| {
+                t!(fs::create_dir_all(pkg.join(name)));
+                cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
+                        &pkg.join(name));
+                install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
+                pkgbuild(name);
+            };
+            prepare("rustc");
+            prepare("cargo");
+            prepare("rust-docs");
+            prepare("rust-std");
+            prepare("rust-analysis");
+
+            if rls_installer.is_some() {
+                prepare("rls");
+            }
 
             // create an 'uninstall' package
             install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
@@ -1298,7 +1322,7 @@ impl Step for Extended {
             t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
             install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
             let mut cmd = Command::new("productbuild");
-            cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml"))
+            cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
                 .arg("--resources").arg(pkg.join("res"))
                 .arg(distdir(build).join(format!("{}-{}.pkg",
                                                     pkgname(build, "rust"),
@@ -1310,46 +1334,34 @@ impl Step for Extended {
         if target.contains("windows") {
             let exe = tmp.join("exe");
             let _ = fs::remove_dir_all(&exe);
-            t!(fs::create_dir_all(exe.join("rustc")));
-            t!(fs::create_dir_all(exe.join("cargo")));
-            t!(fs::create_dir_all(exe.join("rls")));
-            t!(fs::create_dir_all(exe.join("rust-analysis")));
-            t!(fs::create_dir_all(exe.join("rust-docs")));
-            t!(fs::create_dir_all(exe.join("rust-std")));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target))
-                        .join("rustc"),
-                    &exe.join("rustc"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target))
-                        .join("cargo"),
-                    &exe.join("cargo"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target))
-                        .join("rust-docs"),
-                    &exe.join("rust-docs"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
-                        .join(format!("rust-std-{}", target)),
-                    &exe.join("rust-std"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview"),
-                 &exe.join("rls"));
-            cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
-                        .join(format!("rust-analysis-{}", target)),
-                    &exe.join("rust-analysis"));
-
-            t!(fs::remove_file(exe.join("rustc/manifest.in")));
-            t!(fs::remove_file(exe.join("cargo/manifest.in")));
-            t!(fs::remove_file(exe.join("rust-docs/manifest.in")));
-            t!(fs::remove_file(exe.join("rust-std/manifest.in")));
-            t!(fs::remove_file(exe.join("rls/manifest.in")));
-            t!(fs::remove_file(exe.join("rust-analysis/manifest.in")));
 
+            let prepare = |name: &str| {
+                t!(fs::create_dir_all(exe.join(name)));
+                let dir = if name == "rust-std" || name == "rust-analysis" {
+                    format!("{}-{}", name, target)
+                } else if name == "rls" {
+                    "rls-preview".to_string()
+                } else {
+                    name.to_string()
+                };
+                cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
+                            .join(dir),
+                        &exe.join(name));
+                t!(fs::remove_file(exe.join(name).join("manifest.in")));
+            };
+            prepare("rustc");
+            prepare("cargo");
+            prepare("rust-analysis");
+            prepare("rust-docs");
+            prepare("rust-std");
+            if rls_installer.is_some() {
+                prepare("rls");
+            }
             if target.contains("windows-gnu") {
-                t!(fs::create_dir_all(exe.join("rust-mingw")));
-                cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target))
-                            .join("rust-mingw"),
-                        &exe.join("rust-mingw"));
-                t!(fs::remove_file(exe.join("rust-mingw/manifest.in")));
+                prepare("rust-mingw");
             }
 
-            install(&etc.join("exe/rust.iss"), &exe, 0o644);
+            install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
             install(&etc.join("exe/modpath.iss"), &exe, 0o644);
             install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
             install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
@@ -1413,16 +1425,18 @@ impl Step for Extended {
                             .arg("-dr").arg("Std")
                             .arg("-var").arg("var.StdDir")
                             .arg("-out").arg(exe.join("StdGroup.wxs")));
-            build.run(Command::new(&heat)
-                            .current_dir(&exe)
-                            .arg("dir")
-                            .arg("rls")
-                            .args(&heat_flags)
-                            .arg("-cg").arg("RlsGroup")
-                            .arg("-dr").arg("Rls")
-                            .arg("-var").arg("var.RlsDir")
-                            .arg("-out").arg(exe.join("RlsGroup.wxs"))
-                            .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
+            if rls_installer.is_some() {
+                build.run(Command::new(&heat)
+                                .current_dir(&exe)
+                                .arg("dir")
+                                .arg("rls")
+                                .args(&heat_flags)
+                                .arg("-cg").arg("RlsGroup")
+                                .arg("-dr").arg("Rls")
+                                .arg("-var").arg("var.RlsDir")
+                                .arg("-out").arg(exe.join("RlsGroup.wxs"))
+                                .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
+            }
             build.run(Command::new(&heat)
                             .current_dir(&exe)
                             .arg("dir")
@@ -1456,26 +1470,30 @@ impl Step for Extended {
                     .arg("-dDocsDir=rust-docs")
                     .arg("-dCargoDir=cargo")
                     .arg("-dStdDir=rust-std")
-                    .arg("-dRlsDir=rls")
                     .arg("-dAnalysisDir=rust-analysis")
                     .arg("-arch").arg(&arch)
                     .arg("-out").arg(&output)
                     .arg(&input);
                 add_env(build, &mut cmd, target);
 
+                if rls_installer.is_some() {
+                    cmd.arg("-dRlsDir=rls");
+                }
                 if target.contains("windows-gnu") {
                     cmd.arg("-dGccDir=rust-mingw");
                 }
                 build.run(&mut cmd);
             };
-            candle(&etc.join("msi/rust.wxs"));
+            candle(&xform(&etc.join("msi/rust.wxs")));
             candle(&etc.join("msi/ui.wxs"));
             candle(&etc.join("msi/rustwelcomedlg.wxs"));
             candle("RustcGroup.wxs".as_ref());
             candle("DocsGroup.wxs".as_ref());
             candle("CargoGroup.wxs".as_ref());
             candle("StdGroup.wxs".as_ref());
-            candle("RlsGroup.wxs".as_ref());
+            if rls_installer.is_some() {
+                candle("RlsGroup.wxs".as_ref());
+            }
             candle("AnalysisGroup.wxs".as_ref());
 
             if target.contains("windows-gnu") {
@@ -1499,10 +1517,13 @@ impl Step for Extended {
                 .arg("DocsGroup.wixobj")
                 .arg("CargoGroup.wixobj")
                 .arg("StdGroup.wixobj")
-                .arg("RlsGroup.wixobj")
                 .arg("AnalysisGroup.wixobj")
                 .current_dir(&exe);
 
+            if rls_installer.is_some() {
+                cmd.arg("RlsGroup.wixobj");
+            }
+
             if target.contains("windows-gnu") {
                 cmd.arg("GccGroup.wixobj");
             }
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index b9a52a66793..16e8ee182bd 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -66,7 +66,7 @@ macro_rules! book {
 }
 
 book!(
-    Nomicon, "src/doc/book", "nomicon";
+    Nomicon, "src/doc/nomicon", "nomicon";
     Reference, "src/doc/reference", "reference";
     Rustdoc, "src/doc/rustdoc", "rustdoc";
 );
@@ -490,7 +490,7 @@ impl Step for Std {
         // for which docs must be built.
         if !build.config.compiler_docs {
             cargo.arg("--no-deps");
-            for krate in &["alloc", "collections", "core", "std", "std_unicode"] {
+            for krate in &["alloc", "core", "std", "std_unicode"] {
                 cargo.arg("-p").arg(krate);
                 // Create all crate output directories first to make sure rustdoc uses
                 // relative links.
@@ -623,11 +623,9 @@ impl Step for Rustc {
         compile::rustc_cargo(build, &compiler, target, &mut cargo);
 
         if build.config.compiler_docs {
-            // src/rustc/Cargo.toml contains bin crates called rustc and rustdoc
-            // which would otherwise overwrite the docs for the real rustc and
-            // rustdoc lib crates.
-            cargo.arg("-p").arg("rustc_driver")
-                 .arg("-p").arg("rustdoc");
+            // src/rustc/Cargo.toml contains a bin crate called rustc which
+            // would otherwise overwrite the docs for the real rustc lib crate.
+            cargo.arg("-p").arg("rustc_driver");
         } else {
             // Like with libstd above if compiler docs aren't enabled then we're not
             // documenting internal dependencies, so we have a whitelist.
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 2d721f45578..479283b3595 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -240,10 +240,11 @@ pub struct Build {
     lldb_python_dir: Option<String>,
 
     // Runtime state filled in later on
-    // target -> (cc, ar)
-    cc: HashMap<Interned<String>, (cc::Tool, Option<PathBuf>)>,
-    // host -> (cc, ar)
+    // C/C++ compilers and archiver for all targets
+    cc: HashMap<Interned<String>, cc::Tool>,
     cxx: HashMap<Interned<String>, cc::Tool>,
+    ar: HashMap<Interned<String>, PathBuf>,
+    // Misc
     crates: HashMap<Interned<String>, Crate>,
     is_sudo: bool,
     ci_env: CiEnv,
@@ -324,6 +325,7 @@ impl Build {
             rls_info,
             cc: HashMap::new(),
             cxx: HashMap::new(),
+            ar: HashMap::new(),
             crates: HashMap::new(),
             lldb_version: None,
             lldb_python_dir: None,
@@ -383,16 +385,19 @@ impl Build {
     /// Clear out `dir` if `input` is newer.
     ///
     /// After this executes, it will also ensure that `dir` exists.
-    fn clear_if_dirty(&self, dir: &Path, input: &Path) {
+    fn clear_if_dirty(&self, dir: &Path, input: &Path) -> bool {
         let stamp = dir.join(".stamp");
+        let mut cleared = false;
         if mtime(&stamp) < mtime(input) {
             self.verbose(&format!("Dirty - {}", dir.display()));
             let _ = fs::remove_dir_all(dir);
+            cleared = true;
         } else if stamp.exists() {
-            return
+            return cleared;
         }
         t!(fs::create_dir_all(dir));
         t!(File::create(stamp));
+        cleared
     }
 
     /// Get the space-separated set of activated features for the standard
@@ -433,6 +438,12 @@ impl Build {
         if self.config.rust_optimize {"release"} else {"debug"}
     }
 
+    fn tools_dir(&self, compiler: Compiler) -> PathBuf {
+        let out = self.out.join(&*compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
+        t!(fs::create_dir_all(&out));
+        out
+    }
+
     /// Get the directory for incremental by-products when using the
     /// given compiler.
     fn incremental_dir(&self, compiler: Compiler) -> PathBuf {
@@ -612,7 +623,7 @@ impl Build {
 
     /// Returns the path to the C compiler for the target specified.
     fn cc(&self, target: Interned<String>) -> &Path {
-        self.cc[&target].0.path()
+        self.cc[&target].path()
     }
 
     /// Returns a list of flags to pass to the C compiler for the target
@@ -620,7 +631,7 @@ impl Build {
     fn cflags(&self, target: Interned<String>) -> Vec<String> {
         // Filter out -O and /O (the optimization flags) that we picked up from
         // cc-rs because the build scripts will determine that for themselves.
-        let mut base = self.cc[&target].0.args().iter()
+        let mut base = self.cc[&target].args().iter()
                            .map(|s| s.to_string_lossy().into_owned())
                            .filter(|s| !s.starts_with("-O") && !s.starts_with("/O"))
                            .collect::<Vec<_>>();
@@ -644,7 +655,7 @@ impl Build {
 
     /// Returns the path to the `ar` archive utility for the target specified.
     fn ar(&self, target: Interned<String>) -> Option<&Path> {
-        self.cc[&target].1.as_ref().map(|p| &**p)
+        self.ar.get(&target).map(|p| &**p)
     }
 
     /// Returns the path to the C++ compiler for the target specified.
@@ -657,21 +668,17 @@ impl Build {
         }
     }
 
-    /// Returns flags to pass to the compiler to generate code for `target`.
-    fn rustc_flags(&self, target: Interned<String>) -> Vec<String> {
-        // New flags should be added here with great caution!
-        //
-        // It's quite unfortunate to **require** flags to generate code for a
-        // target, so it should only be passed here if absolutely necessary!
-        // Most default configuration should be done through target specs rather
-        // than an entry here.
-
-        let mut base = Vec::new();
-        if target != self.config.build && !target.contains("msvc") &&
-            !target.contains("emscripten") {
-            base.push(format!("-Clinker={}", self.cc(target).display()));
+    /// Returns the path to the linker for the given target if it needs to be overriden.
+    fn linker(&self, target: Interned<String>) -> Option<&Path> {
+        if let Some(linker) = self.config.target_config.get(&target)
+                                                       .and_then(|c| c.linker.as_ref()) {
+            Some(linker)
+        } else if target != self.config.build &&
+                  !target.contains("msvc") && !target.contains("emscripten") {
+            Some(self.cc(target))
+        } else {
+            None
         }
-        base
     }
 
     /// Returns if this target should statically link the C runtime, if specified
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index c4e80630315..c37b1dad4c6 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -227,6 +227,13 @@ impl Step for Llvm {
             cfg.build_arg("-j").build_arg(build.jobs().to_string());
             cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
             cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" "));
+            if let Some(ar) = build.ar(target) {
+                if ar.is_absolute() {
+                    // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
+                    // tries to resolve this path in the LLVM build directory.
+                    cfg.define("CMAKE_AR", sanitize_cc(ar));
+                }
+            }
         };
 
         configure_compilers(&mut cfg);
@@ -252,11 +259,14 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
 
     let mut cmd = Command::new(llvm_config);
     let version = output(cmd.arg("--version"));
-    if version.starts_with("3.5") || version.starts_with("3.6") ||
-       version.starts_with("3.7") {
-        return
+    let mut parts = version.split('.').take(2)
+        .filter_map(|s| s.parse::<u32>().ok());
+    if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
+        if major > 3 || (major == 3 && minor >= 9) {
+            return
+        }
     }
-    panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
+    panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version)
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -352,34 +362,51 @@ impl Step for Openssl {
             // originally from https://www.openssl.org/source/...
             let url = format!("https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/{}",
                               name);
-            let mut ok = false;
+            let mut last_error = None;
             for _ in 0..3 {
                 let status = Command::new("curl")
                                 .arg("-o").arg(&tmp)
+                                .arg("-f")  // make curl fail if the URL does not return HTTP 200
                                 .arg(&url)
                                 .status()
                                 .expect("failed to spawn curl");
-                if status.success() {
-                    ok = true;
-                    break
+
+                // Retry if download failed.
+                if !status.success() {
+                    last_error = Some(status.to_string());
+                    continue;
                 }
+
+                // Ensure the hash is correct.
+                let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
+                    let mut cmd = Command::new("shasum");
+                    cmd.arg("-a").arg("256");
+                    cmd
+                } else {
+                    Command::new("sha256sum")
+                };
+                let output = output(&mut shasum.arg(&tmp));
+                let found = output.split_whitespace().next().unwrap();
+
+                // If the hash is wrong, probably the download is incomplete or S3 served an error
+                // page. In any case, retry.
+                if found != OPENSSL_SHA256 {
+                    last_error = Some(format!(
+                        "downloaded openssl sha256 different\n\
+                         expected: {}\n\
+                         found:    {}\n",
+                        OPENSSL_SHA256,
+                        found
+                    ));
+                    continue;
+                }
+
+                // Everything is fine, so exit the retry loop.
+                last_error = None;
+                break;
             }
-            if !ok {
-                panic!("failed to download openssl source")
-            }
-            let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
-                let mut cmd = Command::new("shasum");
-                cmd.arg("-a").arg("256");
-                cmd
-            } else {
-                Command::new("sha256sum")
-            };
-            let output = output(&mut shasum.arg(&tmp));
-            let found = output.split_whitespace().next().unwrap();
-            if found != OPENSSL_SHA256 {
-                panic!("downloaded openssl sha256 different\n\
-                        expected: {}\n\
-                        found:    {}\n", OPENSSL_SHA256, found);
+            if let Some(error) = last_error {
+                panic!("failed to download openssl source: {}", error);
             }
             t!(fs::rename(&tmp, &tarball));
         }
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index a05e58e6a22..688ee6ba295 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -38,24 +38,40 @@ impl Step for CleanTools {
         run.never()
     }
 
-    /// Build a tool in `src/tools`
-    ///
-    /// This will build the specified tool with the specified `host` compiler in
-    /// `stage` into the normal cargo output directory.
     fn run(self, builder: &Builder) {
         let build = builder.build;
         let compiler = self.compiler;
         let target = self.target;
         let mode = self.mode;
 
-        let stamp = match mode {
-            Mode::Libstd => libstd_stamp(build, compiler, target),
-            Mode::Libtest => libtest_stamp(build, compiler, target),
-            Mode::Librustc => librustc_stamp(build, compiler, target),
-            _ => panic!(),
+        // This is for the original compiler, but if we're forced to use stage 1, then
+        // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
+        // we copy the libs forward.
+        let tools_dir = build.stage_out(compiler, Mode::Tool);
+        let compiler = if builder.force_use_stage1(compiler, target) {
+            builder.compiler(1, compiler.host)
+        } else {
+            compiler
         };
-        let out_dir = build.cargo_out(compiler, Mode::Tool, target);
-        build.clear_if_dirty(&out_dir, &stamp);
+
+        for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] {
+            let stamp = match cur_mode {
+                Mode::Libstd => libstd_stamp(build, compiler, target),
+                Mode::Libtest => libtest_stamp(build, compiler, target),
+                Mode::Librustc => librustc_stamp(build, compiler, target),
+                _ => panic!(),
+            };
+
+            if build.clear_if_dirty(&tools_dir, &stamp) {
+                break;
+            }
+
+            // If we are a rustc tool, and std changed, we also need to clear ourselves out -- our
+            // dependencies depend on std. Therefore, we iterate up until our own mode.
+            if mode == cur_mode {
+                break;
+            }
+        }
     }
 }
 
@@ -70,7 +86,7 @@ struct ToolBuild {
 }
 
 impl Step for ToolBuild {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
 
     fn should_run(run: ShouldRun) -> ShouldRun {
         run.never()
@@ -80,7 +96,7 @@ impl Step for ToolBuild {
     ///
     /// This will build the specified tool with the specified `host` compiler in
     /// `stage` into the normal cargo output directory.
-    fn run(self, builder: &Builder) -> PathBuf {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         let build = builder.build;
         let compiler = self.compiler;
         let target = self.target;
@@ -100,7 +116,15 @@ impl Step for ToolBuild {
 
         let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
         build.run_expecting(&mut cargo, expectation);
-        build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
+        if expectation == BuildExpectation::Succeeding || expectation == BuildExpectation::None {
+            let cargo_out = build.cargo_out(compiler, Mode::Tool, target)
+                .join(exe(tool, &compiler.host));
+            let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host));
+            copy(&cargo_out, &bin);
+            Some(bin)
+        } else {
+            None
+        }
     }
 }
 
@@ -169,12 +193,12 @@ macro_rules! tool {
             }
 
             pub fn tool_default_stage(&self, tool: Tool) -> u32 {
-                // Compile the error-index in the top stage as it depends on
-                // rustdoc, so we want to avoid recompiling rustdoc twice if we
-                // can. Otherwise compile everything else in stage0 as there's
-                // no need to rebootstrap everything
+                // Compile the error-index in the same stage as rustdoc to avoid
+                // recompiling rustdoc twice if we can. Otherwise compile
+                // everything else in stage0 as there's no need to rebootstrap
+                // everything.
                 match tool {
-                    Tool::ErrorIndex => self.top_stage,
+                    Tool::ErrorIndex if self.top_stage >= 2 => self.top_stage,
                     _ => 0,
                 }
             }
@@ -209,7 +233,7 @@ macro_rules! tool {
                     mode: $mode,
                     path: $path,
                     expectation: BuildExpectation::None,
-                })
+                }).expect("expected to build -- BuildExpectation::None")
             }
         }
         )+
@@ -257,7 +281,7 @@ impl Step for RemoteTestServer {
             mode: Mode::Libstd,
             path: "src/tools/remote-test-server",
             expectation: BuildExpectation::None,
-        })
+        }).expect("expected to build -- BuildExpectation::None")
     }
 }
 
@@ -375,7 +399,7 @@ impl Step for Cargo {
             mode: Mode::Librustc,
             path: "src/tools/cargo",
             expectation: BuildExpectation::None,
-        })
+        }).expect("BuildExpectation::None - expected to build")
     }
 }
 
@@ -386,8 +410,8 @@ pub struct Clippy {
 }
 
 impl Step for Clippy {
-    type Output = PathBuf;
-    const DEFAULT: bool = false;
+    type Output = Option<PathBuf>;
+    const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun) -> ShouldRun {
@@ -401,7 +425,7 @@ impl Step for Clippy {
         });
     }
 
-    fn run(self, builder: &Builder) -> PathBuf {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         // Clippy depends on procedural macros (serde), which requires a full host
         // compiler to be available, so we need to depend on that.
         builder.ensure(compile::Rustc {
@@ -411,7 +435,7 @@ impl Step for Clippy {
         builder.ensure(ToolBuild {
             compiler: self.compiler,
             target: self.target,
-            tool: "clippy",
+            tool: "clippy-driver",
             mode: Mode::Librustc,
             path: "src/tools/clippy",
             expectation: builder.build.config.toolstate.clippy.passes(ToolState::Compiling),
@@ -426,7 +450,7 @@ pub struct Rls {
 }
 
 impl Step for Rls {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -442,7 +466,7 @@ impl Step for Rls {
         });
     }
 
-    fn run(self, builder: &Builder) -> PathBuf {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         builder.ensure(native::Openssl {
             target: self.target,
         });
@@ -470,7 +494,7 @@ pub struct Rustfmt {
 }
 
 impl Step for Rustfmt {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -486,7 +510,7 @@ impl Step for Rustfmt {
         });
     }
 
-    fn run(self, builder: &Builder) -> PathBuf {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         builder.ensure(ToolBuild {
             compiler: self.compiler,
             target: self.target,
@@ -506,7 +530,7 @@ pub struct Miri {
 }
 
 impl Step for Miri {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -522,7 +546,7 @@ impl Step for Miri {
         });
     }
 
-    fn run(self, builder: &Builder) -> PathBuf {
+    fn run(self, builder: &Builder) -> Option<PathBuf> {
         builder.ensure(ToolBuild {
             compiler: self.compiler,
             target: self.target,
@@ -561,7 +585,7 @@ impl<'a> Builder<'a> {
         if compiler.host.contains("msvc") {
             let curpaths = env::var_os("PATH").unwrap_or_default();
             let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
-            for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
+            for &(ref k, ref v) in self.cc[&compiler.host].env() {
                 if k != "PATH" {
                     continue
                 }
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 8a113f6b4d2..328cbf0e5d7 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -31,6 +31,13 @@ impl ToolState {
             BuildExpectation::Failing
         }
     }
+
+    pub fn testing(&self) -> bool {
+        match *self {
+            ToolState::Testing => true,
+            _ => false,
+        }
+    }
 }
 
 impl Default for ToolState {
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index a521dd09453..2506048858f 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -14,8 +14,9 @@
 //! not a lot of interesting happenings here unfortunately.
 
 use std::env;
-use std::fs;
-use std::io::{self, Write};
+use std::str;
+use std::fs::{self, File};
+use std::io::{self, Read, Write};
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::time::{SystemTime, Instant};
@@ -50,6 +51,22 @@ pub fn copy(src: &Path, dst: &Path) {
     t!(filetime::set_file_times(dst, atime, mtime));
 }
 
+pub fn read_stamp_file(stamp: &Path) -> Vec<PathBuf> {
+    let mut paths = Vec::new();
+    let mut contents = Vec::new();
+    t!(t!(File::open(stamp)).read_to_end(&mut contents));
+    // This is the method we use for extracting paths from the stamp file passed to us. See
+    // run_cargo for more information (in compile.rs).
+    for part in contents.split(|b| *b == 0) {
+        if part.is_empty() {
+            continue
+        }
+        let path = PathBuf::from(t!(str::from_utf8(part)));
+        paths.push(path);
+    }
+    paths
+}
+
 /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
 /// when this function is called.
 pub fn cp_r(src: &Path, dst: &Path) {
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index e81dab70b43..97723e260f6 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -138,27 +138,6 @@ pub fn gnu_target(target: &str) -> String {
     }
 }
 
-pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
-    if target.contains("msvc") {
-        None
-    } else if target.contains("musl") {
-        Some(PathBuf::from("ar"))
-    } else if target.contains("openbsd") {
-        Some(PathBuf::from("ar"))
-    } else {
-        let parent = cc.parent().unwrap();
-        let file = cc.file_name().unwrap().to_str().unwrap();
-        for suffix in &["gcc", "cc", "clang"] {
-            if let Some(idx) = file.rfind(suffix) {
-                let mut file = file[..idx].to_owned();
-                file.push_str("ar");
-                return Some(parent.join(&file));
-            }
-        }
-        Some(parent.join(file))
-    }
-}
-
 pub fn make(host: &str) -> PathBuf {
     if host.contains("bitrig") || host.contains("dragonfly") ||
         host.contains("freebsd") || host.contains("netbsd") ||
diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile
index 28caf1fb57a..c0bf689e39d 100644
--- a/src/ci/docker/asmjs/Dockerfile
+++ b/src/ci/docker/asmjs/Dockerfile
@@ -16,6 +16,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/emscripten.sh /scripts/
 RUN bash /scripts/emscripten.sh
 
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
 ENV PATH=$PATH:/emsdk-portable
 ENV PATH=$PATH:/emsdk-portable/clang/e1.37.13_64bit/
 ENV PATH=$PATH:/emsdk-portable/emscripten/1.37.13/
@@ -28,7 +31,4 @@ ENV TARGETS=asmjs-unknown-emscripten
 
 ENV RUST_CONFIGURE_ARGS --target=$TARGETS
 
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS src/test/run-pass
diff --git a/src/ci/docker/cross/build-arm-musl.sh b/src/ci/docker/cross/build-arm-musl.sh
index 780099e2ec1..567e5d9ac98 100755
--- a/src/ci/docker/cross/build-arm-musl.sh
+++ b/src/ci/docker/cross/build-arm-musl.sh
@@ -11,7 +11,7 @@
 
 set -ex
 
-MUSL=1.1.16
+MUSL=1.1.17
 
 hide_output() {
   set +x
diff --git a/src/ci/docker/cross2/Dockerfile b/src/ci/docker/cross2/Dockerfile
new file mode 100644
index 00000000000..cc260382f49
--- /dev/null
+++ b/src/ci/docker/cross2/Dockerfile
@@ -0,0 +1,54 @@
+FROM ubuntu:16.04
+
+COPY scripts/cross-apt-packages.sh /scripts/
+RUN sh /scripts/cross-apt-packages.sh
+
+RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \
+  build-essential \
+  gcc-multilib \
+  libedit-dev \
+  libgmp-dev \
+  libisl-dev \
+  libmpc-dev \
+  libmpfr-dev \
+  ninja-build \
+  nodejs \
+  python2.7-dev \
+  software-properties-common \
+  unzip
+
+RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486
+RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2-testing main'
+
+WORKDIR /tmp
+COPY cross2/shared.sh cross2/build-fuchsia-toolchain.sh /tmp/
+COPY cross2/build-solaris-toolchain.sh /tmp/
+RUN /tmp/build-fuchsia-toolchain.sh
+RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
+RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV \
+    AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
+    CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
+    CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
+    AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
+    CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
+    CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \
+    AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
+    CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
+    CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
+    AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
+    CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
+    CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++
+
+ENV TARGETS=x86_64-unknown-fuchsia
+ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
+ENV TARGETS=$TARGETS,sparcv9-sun-solaris
+ENV TARGETS=$TARGETS,x86_64-sun-solaris
+ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
+
+ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/cross2/build-fuchsia-toolchain.sh
index 756013a235c..756013a235c 100755
--- a/src/ci/docker/dist-fuchsia/build-toolchain.sh
+++ b/src/ci/docker/cross2/build-fuchsia-toolchain.sh
diff --git a/src/ci/docker/cross2/build-solaris-toolchain.sh b/src/ci/docker/cross2/build-solaris-toolchain.sh
new file mode 100755
index 00000000000..71ab998aab2
--- /dev/null
+++ b/src/ci/docker/cross2/build-solaris-toolchain.sh
@@ -0,0 +1,107 @@
+#!/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
+source shared.sh
+
+ARCH=$1
+LIB_ARCH=$2
+APT_ARCH=$3
+BINUTILS=2.28.1
+GCC=6.4.0
+
+# First up, build binutils
+mkdir binutils
+cd binutils
+
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf -
+mkdir binutils-build
+cd binutils-build
+hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.10
+hide_output make -j10
+hide_output make install
+
+cd ../..
+rm -rf binutils
+
+# Next, download and install the relevant solaris packages
+mkdir solaris
+cd solaris
+
+dpkg --add-architecture $APT_ARCH
+apt-get update
+apt-get download $(apt-cache depends --recurse --no-replaces \
+  libc-dev:$APT_ARCH       \
+  libm-dev:$APT_ARCH       \
+  libpthread-dev:$APT_ARCH \
+  libresolv-dev:$APT_ARCH  \
+  librt-dev:$APT_ARCH      \
+  libsocket-dev:$APT_ARCH  \
+  system-crt:$APT_ARCH     \
+  system-header:$APT_ARCH  \
+  | grep "^\w")
+
+for deb in *$APT_ARCH.deb; do
+  dpkg -x $deb .
+done
+
+# Remove Solaris 11 functions that are optionally used by libbacktrace.
+# This is for Solaris 10 compatibility.
+rm usr/include/link.h
+patch -p0  << 'EOF'
+--- usr/include/string.h
++++ usr/include/string10.h
+@@ -93 +92,0 @@
+-extern size_t strnlen(const char *, size_t);
+EOF
+
+mkdir                  /usr/local/$ARCH-sun-solaris2.10/usr
+mv usr/include         /usr/local/$ARCH-sun-solaris2.10/usr/include
+mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib
+mv     lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib
+
+ln -s usr/include /usr/local/$ARCH-sun-solaris2.10/sys-include
+ln -s usr/include /usr/local/$ARCH-sun-solaris2.10/include
+
+cd ..
+rm -rf solaris
+
+# Finally, download and build gcc to target solaris
+mkdir gcc
+cd gcc
+
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | tar xJf -
+cd gcc-$GCC
+
+mkdir ../gcc-build
+cd ../gcc-build
+hide_output ../gcc-$GCC/configure \
+  --enable-languages=c,c++        \
+  --target=$ARCH-sun-solaris2.10  \
+  --with-gnu-as                   \
+  --with-gnu-ld                   \
+  --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-fuchsia/shared.sh b/src/ci/docker/cross2/shared.sh
index e26c6eb6645..e26c6eb6645 100644
--- a/src/ci/docker/dist-fuchsia/shared.sh
+++ b/src/ci/docker/cross2/shared.sh
diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile
deleted file mode 100644
index bcd95924b42..00000000000
--- a/src/ci/docker/dist-fuchsia/Dockerfile
+++ /dev/null
@@ -1,41 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y \
-  build-essential \
-  bzip2 \
-  ca-certificates \
-  cmake \
-  curl \
-  file \
-  g++ \
-  gdb \
-  git \
-  libedit-dev \
-  make \
-  ninja-build \
-  nodejs \
-  python2.7-dev \
-  sudo \
-  xz-utils \
-  unzip
-
-WORKDIR /tmp
-COPY dist-fuchsia/shared.sh dist-fuchsia/build-toolchain.sh /tmp/
-RUN /tmp/build-toolchain.sh
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV \
-    AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \
-    CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \
-    CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \
-    AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \
-    CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \
-    CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++
-
-ENV TARGETS=x86_64-unknown-fuchsia
-ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia
-
-ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended
-ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
\ No newline at end of file
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 ad285a57a84..883859d1fa6 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,7 +15,7 @@ set -ex
 export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
 export CXXFLAGS="-Wa,-mrelax-relocations=no"
 
-MUSL=musl-1.1.16
+MUSL=musl-1.1.17
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
 CC=gcc \
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 776da009397..9be8d001149 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.16
+MUSL=musl-1.1.17
 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/scripts/android-sdk.sh b/src/ci/docker/scripts/android-sdk.sh
index d343aae9dfb..3aa2b9d58d5 100644
--- a/src/ci/docker/scripts/android-sdk.sh
+++ b/src/ci/docker/scripts/android-sdk.sh
@@ -31,7 +31,7 @@ download_sysimage() {
     # Keep printing yes to accept the licenses
     while true; do echo yes; sleep 10; done | \
         /android/sdk/tools/android update sdk -a --no-ui \
-            --filter "$filter"
+            --filter "$filter" --no-https
 }
 
 create_avd() {
diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile
index e832a2445ba..6b818604898 100644
--- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile
@@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
-  llvm-3.7-tools \
+  llvm-3.9-tools \
   libedit-dev \
   zlib1g-dev \
   xz-utils
@@ -19,7 +19,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+# using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
-      --llvm-root=/usr/lib/llvm-3.7
+      --llvm-root=/usr/lib/llvm-3.9 \
+      --enable-llvm-link-shared
 ENV RUST_CHECK_TARGET check
diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1
index 6c80f11fa72..0bb41cee2c5 100644
--- a/src/doc/man/rustc.1
+++ b/src/doc/man/rustc.1
@@ -153,9 +153,6 @@ never colorize output.
 .SH CODEGEN OPTIONS
 
 .TP
-\fBar\fR=\fI/path/to/ar\fR
-Path to the archive utility to use when assembling archives.
-.TP
 \fBlinker\fR=\fI/path/to/cc\fR
 Path to the linker utility to use when linking libraries, executables, and
 objects.
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index 0f0bda65ce3..8e8e2a7ff1d 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -96,11 +96,11 @@ Using this flag looks like this:
 $ rustdoc src/lib.rs --crate-name mycrate
 ```
 
-By default, `rustodc` assumes that the name of your crate is the same name
+By default, `rustdoc` assumes that the name of your crate is the same name
 as the `.rs` file. `--crate-name` lets you override this assumption with
 whatever name you choose.
 
-## `-L`/`--library-path`: 
+## `-L`/`--library-path`: where to look for dependencies
 
 Using this flag looks like this:
 
@@ -186,7 +186,7 @@ on documentation tests](documentation-tests.html).
 
 See also `--test-args`.
 
-## `--test-args`: 
+## `--test-args`: pass options to test runner
 
 Using this flag looks like this:
 
@@ -199,7 +199,7 @@ For more, see [the chapter on documentation tests](documentation-tests.html).
 
 See also `--test`.
 
-## `--target`: 
+## `--target`: generate documentation for the specified target triple
 
 Using this flag looks like this:
 
@@ -253,7 +253,7 @@ $ rustdoc README.md --html-before-content extra.html
 ```
 
 This flag takes a list of files, and inserts them inside the `<body>` tag but
-before the other content `rustodc` would normally produce in the rendered
+before the other content `rustdoc` would normally produce in the rendered
 documentation.
 
 ## `--html-after-content`: include more HTML after the content
@@ -266,7 +266,7 @@ $ rustdoc README.md --html-after-content extra.html
 ```
 
 This flag takes a list of files, and inserts them before the `</body>` tag but
-after the other content `rustodc` would normally produce in the rendered
+after the other content `rustdoc` would normally produce in the rendered
 documentation.
 
 
diff --git a/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md b/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md
new file mode 100644
index 00000000000..11b3ee8edf0
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md
@@ -0,0 +1,20 @@
+# `crate_visibility_modifier`
+
+The tracking issue for this feature is: [#45388]
+
+[#45388]: https://github.com/rust-lang/rust/issues/45388
+
+-----
+
+The `crate_visibility_modifier` feature allows the `crate` keyword to be used
+as a visibility modifier synonymous to `pub(crate)`, indicating that a type
+(function, _&c._) is to be visible to the entire enclosing crate, but not to
+other crates.
+
+```rust
+#![feature(crate_visibility_modifier)]
+
+crate struct Foo {
+    bar: usize,
+}
+```
diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md
index ecbc860e25c..0137a052a62 100644
--- a/src/doc/unstable-book/src/language-features/lang-items.md
+++ b/src/doc/unstable-book/src/language-features/lang-items.md
@@ -227,3 +227,95 @@ A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_
 flag is set in the options of the compilation target. It allows customizing the
 process of resuming unwind at the end of the landing pads. The language item's name
 is `eh_unwind_resume`.
+
+## List of all language items
+
+This is a list of all language items in Rust along with where they are located in
+the source code.
+
+- Primitives
+  - `i8`: `libcore/num/mod.rs`
+  - `i16`: `libcore/num/mod.rs`
+  - `i32`: `libcore/num/mod.rs`
+  - `i64`: `libcore/num/mod.rs`
+  - `i128`: `libcore/num/mod.rs`
+  - `isize`: `libcore/num/mod.rs`
+  - `u8`: `libcore/num/mod.rs`
+  - `u16`: `libcore/num/mod.rs`
+  - `u32`: `libcore/num/mod.rs`
+  - `u64`: `libcore/num/mod.rs`
+  - `u128`: `libcore/num/mod.rs`
+  - `usize`: `libcore/num/mod.rs`
+  - `f32`: `libstd/f32.rs`
+  - `f64`: `libstd/f64.rs`
+  - `char`: `libstd_unicode/char.rs`
+  - `slice`: `liballoc/slice.rs`
+  - `str`: `liballoc/str.rs`
+  - `const_ptr`: `libcore/ptr.rs`
+  - `mut_ptr`: `libcore/ptr.rs`
+  - `unsafe_cell`: `libcore/cell.rs`
+- Runtime
+  - `start`: `libstd/rt.rs`
+  - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)
+  - `eh_personality`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
+  - `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
+  - `eh_unwind_resume`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
+  - `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
+  - `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
+  - `panic`: `libcore/panicking.rs`
+  - `panic_bounds_check`: `libcore/panicking.rs`
+  - `panic_fmt`: `libcore/panicking.rs`
+  - `panic_fmt`: `libstd/panicking.rs`
+- Allocations
+  - `owned_box`: `liballoc/boxed.rs`
+  - `exchange_malloc`: `liballoc/heap.rs`
+  - `box_free`: `liballoc/heap.rs`
+- Operands
+  - `not`: `libcore/ops/bit.rs`
+  - `bitand`: `libcore/ops/bit.rs`
+  - `bitor`: `libcore/ops/bit.rs`
+  - `bitxor`: `libcore/ops/bit.rs`
+  - `shl`: `libcore/ops/bit.rs`
+  - `shr`: `libcore/ops/bit.rs`
+  - `bitand_assign`: `libcore/ops/bit.rs`
+  - `bitor_assign`: `libcore/ops/bit.rs`
+  - `bitxor_assign`: `libcore/ops/bit.rs`
+  - `shl_assign`: `libcore/ops/bit.rs`
+  - `shr_assign`: `libcore/ops/bit.rs`
+  - `deref`: `libcore/ops/deref.rs`
+  - `deref_mut`: `libcore/ops/deref.rs`
+  - `index`: `libcore/ops/index.rs`
+  - `index_mut`: `libcore/ops/index.rs`
+  - `add`: `libcore/ops/arith.rs`
+  - `sub`: `libcore/ops/arith.rs`
+  - `mul`: `libcore/ops/arith.rs`
+  - `div`: `libcore/ops/arith.rs`
+  - `rem`: `libcore/ops/arith.rs`
+  - `neg`: `libcore/ops/arith.rs`
+  - `add_assign`: `libcore/ops/arith.rs`
+  - `sub_assign`: `libcore/ops/arith.rs`
+  - `mul_assign`: `libcore/ops/arith.rs`
+  - `div_assign`: `libcore/ops/arith.rs`
+  - `rem_assign`: `libcore/ops/arith.rs`
+  - `eq`: `libcore/cmp.rs`
+  - `ord`: `libcore/cmp.rs`
+- Functions
+  - `fn`: `libcore/ops/function.rs`
+  - `fn_mut`: `libcore/ops/function.rs`
+  - `fn_once`: `libcore/ops/function.rs`
+  - `generator_state`: `libcore/ops/generator.rs`
+  - `generator`: `libcore/ops/generator.rs`
+- Other
+  - `coerce_unsized`: `libcore/ops/unsize.rs`
+  - `drop`: `libcore/ops/drop.rs`
+  - `drop_in_place`: `libcore/ptr.rs`
+  - `clone`: `libcore/clone.rs`
+  - `copy`: `libcore/marker.rs`
+  - `send`: `libcore/marker.rs`
+  - `sized`: `libcore/marker.rs`
+  - `unsize`: `libcore/marker.rs`
+  - `sync`: `libcore/marker.rs`
+  - `phantom_data`: `libcore/marker.rs`
+  - `freeze`: `libcore/marker.rs`
+  - `debug_trait`: `libcore/fmt/mod.rs`
+  - `non_zero`: `libcore/nonzero.rs`
\ No newline at end of file
diff --git a/src/doc/unstable-book/src/language-features/non-ascii-idents.md b/src/doc/unstable-book/src/language-features/non-ascii-idents.md
index d5600c58fd9..efb5495fe26 100644
--- a/src/doc/unstable-book/src/language-features/non-ascii-idents.md
+++ b/src/doc/unstable-book/src/language-features/non-ascii-idents.md
@@ -15,4 +15,34 @@ The `non_ascii_idents` feature adds support for non-ASCII identifiers.
 
 const ε: f64 = 0.00001f64;
 const Π: f64 = 3.14f64;
-```
\ No newline at end of file
+```
+
+## Changes to the language reference
+
+> **<sup>Lexer:<sup>**  
+> IDENTIFIER :  
+> &nbsp;&nbsp; &nbsp;&nbsp; XID_start XID_continue<sup>\*</sup>  
+> &nbsp;&nbsp; | `_` XID_continue<sup>+</sup>  
+
+An identifier is any nonempty Unicode string of the following form:
+
+Either
+
+   * The first character has property [`XID_start`]
+   * The remaining characters have property [`XID_continue`]
+
+Or
+
+   * The first character is `_`
+   * The identifier is more than one character, `_` alone is not an identifier
+   * The remaining characters have property [`XID_continue`]
+
+that does _not_ occur in the set of [strict keywords].
+
+> **Note**: [`XID_start`] and [`XID_continue`] as character properties cover the
+> character ranges used to form the more familiar C and Java language-family
+> identifiers.
+
+[`XID_start`]:  http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=
+[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=
+[strict keywords]: ../reference/keywords.html#strict-keywords
diff --git a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md
new file mode 100644
index 00000000000..ee24dd87d90
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md
@@ -0,0 +1,47 @@
+# `optin_builtin_traits`
+
+The tracking issue for this feature is [#13231] 
+
+[#13231]: https://github.com/rust-lang/rust/issues/13231
+
+----
+
+The `optin_builtin_traits` feature gate allows you to define auto traits.
+
+Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits
+that are automatically implemented for every type, unless the type, or a type it contains, 
+has explictly opted out via a negative impl. 
+
+[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
+[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
+
+```rust,ignore
+impl !Type for Trait
+```
+
+Example:
+
+```rust
+#![feature(optin_builtin_traits)]
+
+trait Valid {}
+
+impl Valid for .. {}
+
+struct True;
+struct False;
+
+impl !Valid for False {}
+
+struct MaybeValid<T>(T);
+
+fn must_be_valid<T: Valid>(_t: T) { }
+
+fn main() {
+    // works
+    must_be_valid( MaybeValid(True) );
+                
+    // compiler error - trait bound not satisfied
+    // must_be_valid( MaybeValid(False) );
+}
+```
diff --git a/src/doc/unstable-book/src/language-features/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md
new file mode 100644
index 00000000000..0eaed7a1989
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/unboxed-closures.md
@@ -0,0 +1,25 @@
+# `unboxed_closures`
+
+The tracking issue for this feature is [#29625]
+
+See Also: [`fn_traits`](library-features/fn-traits.html)
+
+[#29625]: https://github.com/rust-lang/rust/issues/29625
+
+----
+
+The `unboxed_closures` feature allows you to write functions using the `"rust-call"` ABI,
+required for implmenting the [`Fn*`] family of traits. `"rust-call"` functions must have 
+exactly one (non self) argument, a tuple representing the argument list.
+
+[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
+
+```rust
+#![feature(unboxed_closures)]
+
+extern "rust-call" fn add_args(args: (u32, u32)) -> u32 {
+    args.0 + args.1
+}
+
+fn main() {}
+```
diff --git a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md
index 18ff838dd32..425d4cb79b2 100644
--- a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md
+++ b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md
@@ -8,55 +8,6 @@ See also [`alloc_system`](library-features/alloc-system.html).
 
 ------------------------
 
-The compiler currently ships two default allocators: `alloc_system` and
-`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
-are normal Rust crates and contain an implementation of the routines to
-allocate and deallocate memory. The standard library is not compiled assuming
-either one, and the compiler will decide which allocator is in use at
-compile-time depending on the type of output artifact being produced.
-
-Binaries generated by the compiler will use `alloc_jemalloc` by default (where
-available). In this situation the compiler "controls the world" in the sense of
-it has power over the final link. Primarily this means that the allocator
-decision can be left up the compiler.
-
-Dynamic and static libraries, however, will use `alloc_system` by default. Here
-Rust is typically a 'guest' in another application or another world where it
-cannot authoritatively decide what allocator is in use. As a result it resorts
-back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
-memory.
-
-# Switching Allocators
-
-Although the compiler's default choices may work most of the time, it's often
-necessary to tweak certain aspects. Overriding the compiler's decision about
-which allocator is in use is done simply by linking to the desired allocator:
-
-```rust,no_run
-#![feature(alloc_system)]
-
-extern crate alloc_system;
-
-fn main() {
-    let a = Box::new(4); // Allocates from the system allocator.
-    println!("{}", a);
-}
-```
-
-In this example the binary generated will not link to jemalloc by default but
-instead use the system allocator. Conversely to generate a dynamic library which
-uses jemalloc by default one would write:
-
-```rust,ignore
-#![feature(alloc_jemalloc)]
-#![crate_type = "dylib"]
-
-extern crate alloc_jemalloc;
-
-pub fn foo() {
-    let a = Box::new(4); // Allocates from jemalloc.
-    println!("{}", a);
-}
-# fn main() {}
-```
+This feature has been replaced by [the `jemallocator` crate on crates.io.][jemallocator].
 
+[jemallocator]: https://crates.io/crates/jemallocator
diff --git a/src/doc/unstable-book/src/library-features/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md
index 1d261db6ba1..9effab202ca 100644
--- a/src/doc/unstable-book/src/library-features/alloc-system.md
+++ b/src/doc/unstable-book/src/library-features/alloc-system.md
@@ -1,10 +1,10 @@
 # `alloc_system`
 
-The tracking issue for this feature is: [#33082]
+The tracking issue for this feature is: [#32838]
 
-[#33082]: https://github.com/rust-lang/rust/issues/33082
+[#32838]: https://github.com/rust-lang/rust/issues/32838
 
-See also [`alloc_jemalloc`](library-features/alloc-jemalloc.html).
+See also [`global_allocator`](language-features/global-allocator.html).
 
 ------------------------
 
@@ -30,13 +30,18 @@ memory.
 
 Although the compiler's default choices may work most of the time, it's often
 necessary to tweak certain aspects. Overriding the compiler's decision about
-which allocator is in use is done simply by linking to the desired allocator:
+which allocator is in use is done through the `#[global_allocator]` attribute:
 
 ```rust,no_run
-#![feature(alloc_system)]
+#![feature(alloc_system, global_allocator, allocator_api)]
 
 extern crate alloc_system;
 
+use alloc_system::System;
+
+#[global_allocator]
+static A: System = System;
+
 fn main() {
     let a = Box::new(4); // Allocates from the system allocator.
     println!("{}", a);
@@ -47,11 +52,22 @@ In this example the binary generated will not link to jemalloc by default but
 instead use the system allocator. Conversely to generate a dynamic library which
 uses jemalloc by default one would write:
 
+(The `alloc_jemalloc` crate cannot be used to control the global allocator,
+crate.io’s `jemallocator` crate provides equivalent functionality.)
+
+```toml
+# Cargo.toml
+[dependencies]
+jemallocator = "0.1"
+```
 ```rust,ignore
-#![feature(alloc_jemalloc)]
+#![feature(global_allocator)]
 #![crate_type = "dylib"]
 
-extern crate alloc_jemalloc;
+extern crate jemallocator;
+
+#[global_allocator]
+static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
 
 pub fn foo() {
     let a = Box::new(4); // Allocates from jemalloc.
@@ -59,4 +75,3 @@ pub fn foo() {
 }
 # fn main() {}
 ```
-
diff --git a/src/doc/unstable-book/src/library-features/collections.md b/src/doc/unstable-book/src/library-features/collections.md
deleted file mode 100644
index 5c937833c9e..00000000000
--- a/src/doc/unstable-book/src/library-features/collections.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# `collections`
-
-This feature is internal to the Rust compiler and is not intended for general use.
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/fn-traits.md b/src/doc/unstable-book/src/library-features/fn-traits.md
new file mode 100644
index 00000000000..72a3f36c10b
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/fn-traits.md
@@ -0,0 +1,35 @@
+# `fn_traits`
+
+The tracking issue for this feature is [#29625]
+
+See Also: [`unboxed_closures`](language-features/unboxed-closures.html)
+
+[#29625]: https://github.com/rust-lang/rust/issues/29625
+
+----
+
+The `fn_traits` feature allows for implementation of the [`Fn*`] traits
+for creating custom closure-like types.
+
+[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
+
+```rust
+#![feature(unboxed_closures)]
+#![feature(fn_traits)]
+
+struct Adder {
+    a: u32
+}
+
+impl FnOnce<(u32, )> for Adder {
+    type Output = u32;
+    extern "rust-call" fn call_once(self, b: (u32, )) -> Self::Output {
+        self.a + b.0
+    }
+}
+
+fn main() {
+    let adder = Adder { a: 3 };
+    assert_eq!(adder(2), 5);
+}
+```
diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py
index 822dc581404..0612873e281 100755
--- a/src/etc/gdb_rust_pretty_printing.py
+++ b/src/etc/gdb_rust_pretty_printing.py
@@ -248,7 +248,10 @@ class RustStringSlicePrinter(object):
     def to_string(self):
         (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
         raw_ptr = data_ptr.get_wrapped_value()
-        return '"%s"' % raw_ptr.string(encoding="utf-8", length=length)
+        return raw_ptr.lazy_string(encoding="utf-8", length=length)
+
+    def display_hint(self):
+        return "string"
 
 
 class RustStdVecPrinter(object):
@@ -278,9 +281,11 @@ class RustStdStringPrinter(object):
     def to_string(self):
         vec = self.__val.get_child_at_index(0)
         (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
-        return '"%s"' % data_ptr.get_wrapped_value().string(encoding="utf-8",
-                                                            length=length)
+        return data_ptr.get_wrapped_value().lazy_string(encoding="utf-8",
+                                                        length=length)
 
+    def display_hint(self):
+        return "string"
 
 class RustOsStringPrinter(object):
     def __init__(self, val):
@@ -294,8 +299,10 @@ class RustOsStringPrinter(object):
 
         (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(
             vec)
-        return '"%s"' % data_ptr.get_wrapped_value().string(length=length)
+        return data_ptr.get_wrapped_value().lazy_string(length=length)
 
+    def display_hint(self):
+        return "string"
 
 class RustCStyleVariantPrinter(object):
     def __init__(self, val):
diff --git a/src/etc/installer/exe/rust.iss b/src/etc/installer/exe/rust.iss
index e7d4ec61946..c22d60b6c5d 100644
--- a/src/etc/installer/exe/rust.iss
+++ b/src/etc/installer/exe/rust.iss
@@ -46,7 +46,9 @@ Name: gcc; Description: "Linker and platform libraries"; Types: full
 Name: docs; Description: "HTML documentation"; Types: full
 Name: cargo; Description: "Cargo, the Rust package manager"; Types: full
 Name: std; Description: "The Rust Standard Library"; Types: full
+// tool-rls-start
 Name: rls; Description: "RLS, the Rust Language Server"
+// tool-rls-end
 
 [Files]
 Source: "rustc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust
@@ -56,8 +58,10 @@ Source: "rust-mingw/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs;
 Source: "rust-docs/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: docs
 Source: "cargo/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: cargo
 Source: "rust-std/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: std
+// tool-rls-start
 Source: "rls/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls
 Source: "rust-analysis/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls
+// tool-rls-end
 
 [Code]
 const
diff --git a/src/etc/installer/msi/rust.wxs b/src/etc/installer/msi/rust.wxs
index 258291cbb72..d95b096d732 100644
--- a/src/etc/installer/msi/rust.wxs
+++ b/src/etc/installer/msi/rust.wxs
@@ -170,8 +170,10 @@
                     <Directory Id="Docs" Name="." />
                     <Directory Id="Cargo" Name="." />
                     <Directory Id="Std" Name="." />
+                    <!-- tool-rls-start -->
                     <Directory Id="Rls" Name="." />
                     <Directory Id="Analysis" Name="." />
+                    <!-- tool-rls-end -->
                 </Directory>
             </Directory>
 
@@ -275,6 +277,7 @@
                  <ComponentRef Id="PathEnvPerMachine" />
                  <ComponentRef Id="PathEnvPerUser" />
         </Feature>
+        <!-- tool-rls-start -->
         <Feature Id="RLS"
                  Title="RLS, the Rust Language Server"
                  Display="7"
@@ -283,6 +286,7 @@
                  <ComponentGroupRef Id="RlsGroup" />
                  <ComponentGroupRef Id="AnalysisGroup" />
         </Feature>
+        <!-- tool-rls-end -->
 
         <UIRef Id="RustUI" />
     </Product>
diff --git a/src/etc/installer/pkg/Distribution.xml b/src/etc/installer/pkg/Distribution.xml
index f138a1a3154..077ee175116 100644
--- a/src/etc/installer/pkg/Distribution.xml
+++ b/src/etc/installer/pkg/Distribution.xml
@@ -16,7 +16,9 @@
       <line choice="rust-std"/>
       <line choice="cargo"/>
       <line choice="rust-docs"/>
+      <!-- tool-rls-start -->
       <line choice="rls"/>
+      <!-- tool-rls-end -->
       </line>
       <line choice="uninstall" />
     </choices-outline>
@@ -62,6 +64,7 @@
         >
         <pkg-ref id="org.rust-lang.rust-docs"/>
     </choice>
+    <!-- tool-rls-start -->
     <choice id="rls" visible="true"
         title="RLS" description="RLS, the Rust Language Server"
         selected="(!choices.uninstall.selected &amp;&amp; choices['rls'].selected) || (choices.uninstall.selected &amp;&amp; choices.install.selected)"
@@ -70,11 +73,14 @@
         <pkg-ref id="org.rust-lang.rls"/>
         <pkg-ref id="org.rust-lang.rust-analysis"/>
     </choice>
+    <!-- tool-rls-end -->
     <pkg-ref id="org.rust-lang.rustc" version="0" onConclusion="none">rustc.pkg</pkg-ref>
     <pkg-ref id="org.rust-lang.cargo" version="0" onConclusion="none">cargo.pkg</pkg-ref>
     <pkg-ref id="org.rust-lang.rust-docs" version="0" onConclusion="none">rust-docs.pkg</pkg-ref>
     <pkg-ref id="org.rust-lang.rust-std" version="0" onConclusion="none">rust-std.pkg</pkg-ref>
+    <!-- tool-rls-start -->
     <pkg-ref id="org.rust-lang.rls" version="0" onConclusion="none">rls.pkg</pkg-ref>
+    <!-- tool-rls-end -->
     <pkg-ref id="org.rust-lang.rust-analysis" version="0" onConclusion="none">rust-analysis.pkg</pkg-ref>
     <pkg-ref id="org.rust-lang.uninstall" version="0" onConclusion="none">uninstall.pkg</pkg-ref>
     <background file="rust-logo.png" mime-type="image/png"
diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py
index 4952cf4f82c..24a0ce0ac36 100644
--- a/src/etc/lldb_batchmode.py
+++ b/src/etc/lldb_batchmode.py
@@ -81,7 +81,7 @@ def execute_command(command_interpreter, command):
 
     if res.Succeeded():
         if res.HasResult():
-            print(normalize_whitespace(res.GetOutput()), end='\n')
+            print(normalize_whitespace(res.GetOutput() or ''), end='\n')
 
         # If the command introduced any breakpoints, make sure to register
         # them with the breakpoint
diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l
index 91652bfdf24..2f282c8281d 100644
--- a/src/grammar/lexer.l
+++ b/src/grammar/lexer.l
@@ -85,16 +85,23 @@ ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]*
 <blockcomment>(.|\n)   { }
 
 _        { return UNDERSCORE; }
+abstract { return ABSTRACT; }
+alignof  { return ALIGNOF; }
 as       { return AS; }
+become   { return BECOME; }
 box      { return BOX; }
 break    { return BREAK; }
+catch    { return CATCH; }
 const    { return CONST; }
 continue { return CONTINUE; }
 crate    { return CRATE; }
+default  { return DEFAULT; }
+do       { return DO; }
 else     { return ELSE; }
 enum     { return ENUM; }
 extern   { return EXTERN; }
 false    { return FALSE; }
+final    { return FINAL; }
 fn       { return FN; }
 for      { return FOR; }
 if       { return IF; }
@@ -102,26 +109,36 @@ impl     { return IMPL; }
 in       { return IN; }
 let      { return LET; }
 loop     { return LOOP; }
+macro    { return MACRO; }
 match    { return MATCH; }
 mod      { return MOD; }
 move     { return MOVE; }
 mut      { return MUT; }
+offsetof { return OFFSETOF; }
+override { return OVERRIDE; }
 priv     { return PRIV; }
 proc     { return PROC; }
+pure     { return PURE; }
 pub      { return PUB; }
 ref      { return REF; }
 return   { return RETURN; }
 self     { return SELF; }
+sizeof   { return SIZEOF; }
 static   { return STATIC; }
 struct   { return STRUCT; }
+super    { return SUPER; }
 trait    { return TRAIT; }
 true     { return TRUE; }
 type     { return TYPE; }
 typeof   { return TYPEOF; }
+union    { return UNION; }
 unsafe   { return UNSAFE; }
+unsized  { return UNSIZED; }
 use      { return USE; }
+virtual  { return VIRTUAL; }
 where    { return WHERE; }
 while    { return WHILE; }
+yield    { return YIELD; }
 
 {ident}  { return IDENT; }
 
@@ -189,25 +206,25 @@ while    { return WHILE; }
 \>\>= { return SHREQ; }
 \>    { return '>'; }
 
-\x27                                  { BEGIN(ltorchar); yymore(); }
-<ltorchar>static                      { BEGIN(INITIAL); return STATIC_LIFETIME; }
-<ltorchar>{ident}                     { BEGIN(INITIAL); return LIFETIME; }
-<ltorchar>\\[nrt\\\x27\x220]\x27      { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>\\x[0-9a-fA-F]{2}\x27       { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>\\u\{[0-9a-fA-F]?{6}\}\x27  { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>.\x27                       { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar>[\x80-\xff]{2,4}\x27        { BEGIN(suffix); return LIT_CHAR; }
-<ltorchar><<EOF>>                     { BEGIN(INITIAL); return -1; }
+\x27                                      { BEGIN(ltorchar); yymore(); }
+<ltorchar>static                          { BEGIN(INITIAL); return STATIC_LIFETIME; }
+<ltorchar>{ident}                         { BEGIN(INITIAL); return LIFETIME; }
+<ltorchar>\\[nrt\\\x27\x220]\x27          { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>\\x[0-9a-fA-F]{2}\x27           { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>\\u\{([0-9a-fA-F]_*){1,6}\}\x27 { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>.\x27                           { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar>[\x80-\xff]{2,4}\x27            { BEGIN(suffix); return LIT_CHAR; }
+<ltorchar><<EOF>>                         { BEGIN(INITIAL); return -1; }
 
 b\x22              { BEGIN(bytestr); yymore(); }
 <bytestr>\x22      { BEGIN(suffix); return LIT_BYTE_STR; }
 
-<bytestr><<EOF>>                { return -1; }
-<bytestr>\\[n\nrt\\\x27\x220]   { yymore(); }
-<bytestr>\\x[0-9a-fA-F]{2}      { yymore(); }
-<bytestr>\\u\{[0-9a-fA-F]?{6}\} { yymore(); }
-<bytestr>\\[^n\nrt\\\x27\x220]  { return -1; }
-<bytestr>(.|\n)                 { yymore(); }
+<bytestr><<EOF>>                     { return -1; }
+<bytestr>\\[n\nrt\\\x27\x220]        { yymore(); }
+<bytestr>\\x[0-9a-fA-F]{2}           { yymore(); }
+<bytestr>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); }
+<bytestr>\\[^n\nrt\\\x27\x220]       { return -1; }
+<bytestr>(.|\n)                      { yymore(); }
 
 br\x22                      { BEGIN(rawbytestr_nohash); yymore(); }
 <rawbytestr_nohash>\x22     { BEGIN(suffix); return LIT_BYTE_STR_RAW; }
@@ -252,13 +269,13 @@ br/# {
 }
 <rawbytestr><<EOF>> { return -1; }
 
-b\x27                        { BEGIN(byte); yymore(); }
-<byte>\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>\\x[0-9a-fA-F]{2}\x27  { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>\\u[0-9a-fA-F]{4}\x27  { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>\\U[0-9a-fA-F]{8}\x27  { BEGIN(INITIAL); return LIT_BYTE; }
-<byte>.\x27                  { BEGIN(INITIAL); return LIT_BYTE; }
-<byte><<EOF>>                { BEGIN(INITIAL); return -1; }
+b\x27                           { BEGIN(byte); yymore(); }
+<byte>\\[nrt\\\x27\x220]\x27    { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>\\x[0-9a-fA-F]{2}\x27     { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>\\u([0-9a-fA-F]_*){4}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>\\U([0-9a-fA-F]_*){8}\x27 { BEGIN(INITIAL); return LIT_BYTE; }
+<byte>.\x27                     { BEGIN(INITIAL); return LIT_BYTE; }
+<byte><<EOF>>                   { BEGIN(INITIAL); return -1; }
 
 r\x22           { BEGIN(rawstr); yymore(); }
 <rawstr>\x22    { BEGIN(suffix); return LIT_STR_RAW; }
@@ -310,12 +327,12 @@ r/#             {
 \x22                     { BEGIN(str); yymore(); }
 <str>\x22                { BEGIN(suffix); return LIT_STR; }
 
-<str><<EOF>>                { return -1; }
-<str>\\[n\nr\rt\\\x27\x220] { yymore(); }
-<str>\\x[0-9a-fA-F]{2}      { yymore(); }
-<str>\\u\{[0-9a-fA-F]?{6}\} { yymore(); }
-<str>\\[^n\nrt\\\x27\x220]  { return -1; }
-<str>(.|\n)                 { yymore(); }
+<str><<EOF>>                     { return -1; }
+<str>\\[n\nr\rt\\\x27\x220]      { yymore(); }
+<str>\\x[0-9a-fA-F]{2}           { yymore(); }
+<str>\\u\{([0-9a-fA-F]_*){1,6}\} { yymore(); }
+<str>\\[^n\nrt\\\x27\x220]       { return -1; }
+<str>(.|\n)                      { yymore(); }
 
 \<-  { return LARROW; }
 -\>  { return RARROW; }
diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y
index c9fcdf7647b..de1f96aac50 100644
--- a/src/grammar/parser-lalr.y
+++ b/src/grammar/parser-lalr.y
@@ -62,13 +62,19 @@ extern char *yytext;
 // keywords
 %token SELF
 %token STATIC
+%token ABSTRACT
+%token ALIGNOF
 %token AS
+%token BECOME
 %token BREAK
+%token CATCH
 %token CRATE
+%token DO
 %token ELSE
 %token ENUM
 %token EXTERN
 %token FALSE
+%token FINAL
 %token FN
 %token FOR
 %token IF
@@ -76,19 +82,29 @@ extern char *yytext;
 %token IN
 %token LET
 %token LOOP
+%token MACRO
 %token MATCH
 %token MOD
 %token MOVE
 %token MUT
+%token OFFSETOF
+%token OVERRIDE
 %token PRIV
 %token PUB
+%token PURE
 %token REF
 %token RETURN
+%token SIZEOF
 %token STRUCT
+%token SUPER
+%token UNION
+%token UNSIZED
 %token TRUE
 %token TRAIT
 %token TYPE
 %token UNSAFE
+%token VIRTUAL
+%token YIELD
 %token DEFAULT
 %token USE
 %token WHILE
@@ -141,6 +157,10 @@ extern char *yytext;
 // 'foo:bar . <' is shifted (in a trait reference occurring in a
 // bounds list), parsing as foo:(bar<baz>) rather than (foo:bar)<baz>.
 %precedence IDENT
+ // Put the weak keywords that can be used as idents here as well
+%precedence CATCH
+%precedence DEFAULT
+%precedence UNION
 
 // A couple fake-precedence symbols to use in rules associated with +
 // and < in trailing type contexts. These come up when you have a type
@@ -161,13 +181,13 @@ extern char *yytext;
 %precedence FOR
 
 // Binops & unops, and their precedences
+%precedence '?'
 %precedence BOX
-%precedence BOXPLACE
 %nonassoc DOTDOT
 
 // RETURN needs to be lower-precedence than tokens that start
 // prefix_exprs
-%precedence RETURN
+%precedence RETURN YIELD
 
 %right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ
 %right LARROW
@@ -321,6 +341,8 @@ view_path
 | path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); }
 |                       MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); }
 | path_no_types_allowed MOD_SEP '*'                        { $$ = mk_node("ViewPathGlob", 1, $1); }
+|                       MOD_SEP '*'                        { $$ = mk_atom("ViewPathGlob"); }
+|                               '*'                        { $$ = mk_atom("ViewPathGlob"); }
 |                               '{'                '}'     { $$ = mk_atom("ViewPathListEmpty"); }
 |                               '{' idents_or_self '}'     { $$ = mk_node("ViewPathList", 1, $2); }
 |                               '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); }
@@ -334,6 +356,7 @@ block_item
 | item_foreign_mod          { $$ = mk_node("ItemForeignMod", 1, $1); }
 | item_struct
 | item_enum
+| item_union
 | item_trait
 | item_impl
 ;
@@ -387,6 +410,7 @@ struct_decl_field
 struct_tuple_fields
 : struct_tuple_field                          { $$ = mk_node("StructFields", 1, $1); }
 | struct_tuple_fields ',' struct_tuple_field  { $$ = ext_node($1, 1, $3); }
+| %empty                                      { $$ = mk_none(); }
 ;
 
 struct_tuple_field
@@ -417,6 +441,11 @@ enum_args
 | %empty                         { $$ = mk_none(); }
 ;
 
+// unions
+item_union
+: UNION ident generic_params maybe_where_clause '{' struct_decl_fields '}'     { $$ = mk_node("ItemUnion", 0); }
+| UNION ident generic_params maybe_where_clause '{' struct_decl_fields ',' '}' { $$ = mk_node("ItemUnion", 0); }
+
 item_mod
 : MOD ident ';'                                 { $$ = mk_node("ItemMod", 1, $2); }
 | MOD ident '{' maybe_mod_items '}'             { $$ = mk_node("ItemMod", 2, $2, $4); }
@@ -475,7 +504,7 @@ visibility
 
 idents_or_self
 : ident_or_self                    { $$ = mk_node("IdentsOrSelf", 1, $1); }
-| ident_or_self AS ident           { $$ = mk_node("IdentsOrSelf", 2, $1, $3); }
+| idents_or_self AS ident          { $$ = mk_node("IdentsOrSelf", 2, $1, $3); }
 | idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); }
 ;
 
@@ -515,6 +544,7 @@ trait_item
 : trait_const
 | trait_type
 | trait_method
+| maybe_outer_attrs item_macro { $$ = mk_node("TraitMacroItem", 2, $1, $2); }
 ;
 
 trait_const
@@ -547,36 +577,48 @@ trait_method
 ;
 
 type_method
-: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
+: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
 {
   $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7);
 }
-| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
+| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
+{
+  $$ = mk_node("TypeMethod", 6, $1, $3, $5, $6, $7, $8);
+}
+| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';'
 {
   $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9);
 }
 ;
 
 method
-: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
+: maybe_outer_attrs maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
 {
   $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8);
 }
-| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
+| maybe_outer_attrs CONST maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
+{
+  $$ = mk_node("Method", 7, $1, $3, $5, $6, $7, $8, $9);
+}
+| maybe_outer_attrs maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block
 {
   $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10);
 }
 ;
 
 impl_method
-: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
+: attrs_and_vis maybe_default maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
 {
-  $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8);
+  $$ = mk_node("Method", 8, $1, $2, $3, $5, $6, $7, $8, $9);
 }
-| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
+| attrs_and_vis maybe_default CONST maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
 {
   $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10);
 }
+| attrs_and_vis maybe_default maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block
+{
+  $$ = mk_node("Method", 9, $1, $2, $3, $5, $7, $8, $9, $10, $11);
+}
 ;
 
 // There are two forms of impl:
@@ -638,12 +680,17 @@ impl_item
 | impl_type
 ;
 
+maybe_default
+: DEFAULT { $$ = mk_atom("Default"); }
+| %empty { $$ = mk_none(); }
+;
+
 impl_const
-: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
+: attrs_and_vis maybe_default item_const { $$ = mk_node("ImplConst", 3, $1, $2, $3); }
 ;
 
 impl_type
-: attrs_and_vis TYPE ident generic_params '=' ty_sum ';'  { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
+: attrs_and_vis maybe_default TYPE ident generic_params '=' ty_sum ';'  { $$ = mk_node("ImplType", 5, $1, $2, $4, $5, $7); }
 ;
 
 item_fn
@@ -651,6 +698,10 @@ item_fn
 {
   $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6);
 }
+| CONST FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
+{
+  $$ = mk_node("ItemFn", 5, $3, $4, $5, $6, $7);
+}
 ;
 
 item_unsafe_fn
@@ -658,6 +709,10 @@ item_unsafe_fn
 {
   $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7);
 }
+| CONST UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
+{
+  $$ = mk_node("ItemUnsafeFn", 5, $4, $5, $6, $7, $8);
+}
 | UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block
 {
   $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9);
@@ -723,12 +778,6 @@ inferrable_param
 : pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); }
 ;
 
-maybe_unboxed_closure_kind
-: %empty
-| ':'
-| '&' maybe_mut ':'
-;
-
 maybe_comma_params
 : ','            { $$ = mk_none(); }
 | ',' params     { $$ = $2; }
@@ -784,7 +833,8 @@ ret_ty
 ;
 
 generic_params
-: '<' lifetimes '>'                   { $$ = mk_node("Generics", 2, $2, mk_none()); }
+: '<' '>'                             { $$ = mk_node("Generics", 2, mk_none(), mk_none()); }
+| '<' lifetimes '>'                   { $$ = mk_node("Generics", 2, $2, mk_none()); }
 | '<' lifetimes ',' '>'               { $$ = mk_node("Generics", 2, $2, mk_none()); }
 | '<' lifetimes SHR                   { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); }
 | '<' lifetimes ',' SHR               { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); }
@@ -837,6 +887,8 @@ path_no_types_allowed
 | MOD_SEP ident                       { $$ = mk_node("ViewPath", 1, $2); }
 | SELF                                { $$ = mk_node("ViewPath", 1, mk_atom("Self")); }
 | MOD_SEP SELF                        { $$ = mk_node("ViewPath", 1, mk_atom("Self")); }
+| SUPER                               { $$ = mk_node("ViewPath", 1, mk_atom("Super")); }
+| MOD_SEP SUPER                       { $$ = mk_node("ViewPath", 1, mk_atom("Super")); }
 | path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); }
 ;
 
@@ -882,7 +934,7 @@ generic_args
 ;
 
 generic_values
-: maybe_lifetimes maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 2, $1, $2); }
+: maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 1, $1); }
 ;
 
 maybe_ty_sums_and_or_bindings
@@ -910,12 +962,11 @@ pat
 | ANDAND pat                                      { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); }
 | '(' ')'                                         { $$ = mk_atom("PatUnit"); }
 | '(' pat_tup ')'                                 { $$ = mk_node("PatTup", 1, $2); }
-| '(' pat_tup ',' ')'                             { $$ = mk_node("PatTup", 1, $2); }
 | '[' pat_vec ']'                                 { $$ = mk_node("PatVec", 1, $2); }
 | lit_or_path
 | lit_or_path DOTDOTDOT lit_or_path               { $$ = mk_node("PatRange", 2, $1, $3); }
 | path_expr '{' pat_struct '}'                    { $$ = mk_node("PatStruct", 2, $1, $3); }
-| path_expr '(' DOTDOT ')'                        { $$ = mk_node("PatEnum", 1, $1); }
+| path_expr '(' ')'                               { $$ = mk_node("PatEnum", 2, $1, mk_none()); }
 | path_expr '(' pat_tup ')'                       { $$ = mk_node("PatEnum", 2, $1, $3); }
 | path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); }
 | binding_mode ident                              { $$ = mk_node("PatIdent", 2, $1, $2); }
@@ -953,6 +1004,7 @@ pat_field
 | BOX binding_mode ident        { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); }
 |              ident ':' pat    { $$ = mk_node("PatField", 2, $1, $3); }
 | binding_mode ident ':' pat    { $$ = mk_node("PatField", 3, $1, $2, $4); }
+|        LIT_INTEGER ':' pat    { $$ = mk_node("PatField", 2, mk_atom(yytext), $3); }
 ;
 
 pat_fields
@@ -965,11 +1017,26 @@ pat_struct
 | pat_fields ','             { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); }
 | pat_fields ',' DOTDOT      { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); }
 | DOTDOT                     { $$ = mk_node("PatStruct", 1, mk_atom("true")); }
+| %empty                     { $$ = mk_node("PatStruct", 1, mk_none()); }
 ;
 
 pat_tup
-: pat               { $$ = mk_node("pat_tup", 1, $1); }
-| pat_tup ',' pat   { $$ = ext_node($1, 1, $3); }
+: pat_tup_elts                                  { $$ = mk_node("PatTup", 2, $1, mk_none()); }
+| pat_tup_elts                             ','  { $$ = mk_node("PatTup", 2, $1, mk_none()); }
+| pat_tup_elts     DOTDOT                       { $$ = mk_node("PatTup", 2, $1, mk_none()); }
+| pat_tup_elts ',' DOTDOT                       { $$ = mk_node("PatTup", 2, $1, mk_none()); }
+| pat_tup_elts     DOTDOT ',' pat_tup_elts      { $$ = mk_node("PatTup", 2, $1, $4); }
+| pat_tup_elts     DOTDOT ',' pat_tup_elts ','  { $$ = mk_node("PatTup", 2, $1, $4); }
+| pat_tup_elts ',' DOTDOT ',' pat_tup_elts      { $$ = mk_node("PatTup", 2, $1, $5); }
+| pat_tup_elts ',' DOTDOT ',' pat_tup_elts ','  { $$ = mk_node("PatTup", 2, $1, $5); }
+|                  DOTDOT ',' pat_tup_elts      { $$ = mk_node("PatTup", 2, mk_none(), $3); }
+|                  DOTDOT ',' pat_tup_elts ','  { $$ = mk_node("PatTup", 2, mk_none(), $3); }
+|                  DOTDOT                       { $$ = mk_node("PatTup", 2, mk_none(), mk_none()); }
+;
+
+pat_tup_elts
+: pat                    { $$ = mk_node("PatTupElts", 1, $1); }
+| pat_tup_elts ',' pat   { $$ = ext_node($1, 1, $3); }
 ;
 
 pat_vec
@@ -1007,24 +1074,25 @@ ty
 ;
 
 ty_prim
-: %prec IDENT path_generic_args_without_colons              { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); }
-| %prec IDENT MOD_SEP path_generic_args_without_colons      { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); }
-| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); }
-| BOX ty                                                    { $$ = mk_node("TyBox", 1, $2); }
-| '*' maybe_mut_or_const ty                                 { $$ = mk_node("TyPtr", 2, $2, $3); }
-| '&' ty                                                    { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); }
-| '&' MUT ty                                                { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); }
-| ANDAND ty                                                 { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); }
-| ANDAND MUT ty                                             { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); }
-| '&' lifetime maybe_mut ty                                 { $$ = mk_node("TyRptr", 3, $2, $3, $4); }
-| ANDAND lifetime maybe_mut ty                              { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); }
-| '[' ty ']'                                                { $$ = mk_node("TyVec", 1, $2); }
-| '[' ty ',' DOTDOT expr ']'                                { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); }
-| '[' ty ';' expr ']'                                       { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); }
-| TYPEOF '(' expr ')'                                       { $$ = mk_node("TyTypeof", 1, $3); }
-| UNDERSCORE                                                { $$ = mk_atom("TyInfer"); }
+: %prec IDENT path_generic_args_without_colons                                               { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); }
+| %prec IDENT MOD_SEP path_generic_args_without_colons                                       { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); }
+| %prec IDENT SELF MOD_SEP path_generic_args_without_colons                                  { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); }
+| %prec IDENT path_generic_args_without_colons '!' maybe_ident delimited_token_trees         { $$ = mk_node("TyMacro", 3, $1, $3, $4); }
+| %prec IDENT MOD_SEP path_generic_args_without_colons '!' maybe_ident delimited_token_trees { $$ = mk_node("TyMacro", 3, $2, $4, $5); }
+| BOX ty                                                                                     { $$ = mk_node("TyBox", 1, $2); }
+| '*' maybe_mut_or_const ty                                                                  { $$ = mk_node("TyPtr", 2, $2, $3); }
+| '&' ty                                                                                     { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); }
+| '&' MUT ty                                                                                 { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); }
+| ANDAND ty                                                                                  { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); }
+| ANDAND MUT ty                                                                              { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); }
+| '&' lifetime maybe_mut ty                                                                  { $$ = mk_node("TyRptr", 3, $2, $3, $4); }
+| ANDAND lifetime maybe_mut ty                                                               { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); }
+| '[' ty ']'                                                                                 { $$ = mk_node("TyVec", 1, $2); }
+| '[' ty ',' DOTDOT expr ']'                                                                 { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); }
+| '[' ty ';' expr ']'                                                                        { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); }
+| TYPEOF '(' expr ')'                                                                        { $$ = mk_node("TyTypeof", 1, $3); }
+| UNDERSCORE                                                                                 { $$ = mk_atom("TyInfer"); }
 | ty_bare_fn
-| ty_proc
 | for_in_type
 ;
 
@@ -1046,17 +1114,12 @@ ty_closure
 |        OROR maybe_bounds ret_ty                { $$ = mk_node("TyClosure", 2, $2, $3); }
 ;
 
-ty_proc
-: PROC generic_params fn_params maybe_bounds ret_ty { $$ = mk_node("TyProc", 4, $2, $3, $4, $5); }
-;
-
 for_in_type
 : FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); }
 ;
 
 for_in_type_suffix
-: ty_proc
-| ty_bare_fn
+: ty_bare_fn
 | trait_ref
 | ty_closure
 ;
@@ -1100,13 +1163,23 @@ ty_sums
 ;
 
 ty_sum
-: ty                     { $$ = mk_node("TySum", 1, $1); }
-| ty '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); }
+: ty_sum_elt            { $$ = mk_node("TySum", 1, $1); }
+| ty_sum '+' ty_sum_elt { $$ = ext_node($1, 1, $3); }
+;
+
+ty_sum_elt
+: ty
+| lifetime
 ;
 
 ty_prim_sum
-: ty_prim                     { $$ = mk_node("TySum", 1, $1); }
-| ty_prim '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); }
+: ty_prim_sum_elt                 { $$ = mk_node("TySum", 1, $1); }
+| ty_prim_sum '+' ty_prim_sum_elt { $$ = ext_node($1, 1, $3); }
+;
+
+ty_prim_sum_elt
+: ty_prim
+| lifetime
 ;
 
 maybe_ty_param_bounds
@@ -1127,6 +1200,7 @@ boundseq
 polybound
 : FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); }
 | bound
+| '?' FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $4, $6); }
 | '?' bound { $$ = $2; }
 ;
 
@@ -1244,11 +1318,6 @@ maybe_stmts
 // block, nonblock-prefix, and nonblock-nonprefix.
 //
 // In non-stmts contexts, expr can relax this trichotomy.
-//
-// There is also one other expr subtype: nonparen_expr disallows exprs
-// surrounded by parens (including tuple expressions), this is
-// necessary for BOX (place) expressions, so a parens expr following
-// the BOX is always parsed as the place.
 
 stmts
 : stmt           { $$ = mk_node("stmts", 1, $1); }
@@ -1256,14 +1325,15 @@ stmts
 ;
 
 stmt
-: let
+: maybe_outer_attrs let     { $$ = $2; }
 |                 stmt_item
 |             PUB stmt_item { $$ = $2; }
 | outer_attrs     stmt_item { $$ = $2; }
 | outer_attrs PUB stmt_item { $$ = $3; }
 | full_block_expr
-| block
-| nonblock_expr ';'
+| maybe_outer_attrs block   { $$ = $2; }
+|             nonblock_expr ';'
+| outer_attrs nonblock_expr ';' { $$ = $2; }
 | ';'                   { $$ = mk_none(); }
 ;
 
@@ -1296,7 +1366,9 @@ path_expr
 // expressions.
 path_generic_args_with_colons
 : ident                                              { $$ = mk_node("components", 1, $1); }
+| SUPER                                              { $$ = mk_atom("Super"); }
 | path_generic_args_with_colons MOD_SEP ident        { $$ = ext_node($1, 1, $3); }
+| path_generic_args_with_colons MOD_SEP SUPER        { $$ = ext_node($1, 1, mk_atom("Super")); }
 | path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); }
 ;
 
@@ -1313,6 +1385,7 @@ nonblock_expr
 | SELF                                                          { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
 | macro_expr                                                    { $$ = mk_node("ExprMac", 1, $1); }
 | path_expr '{' struct_expr_fields '}'                          { $$ = mk_node("ExprStruct", 2, $1, $3); }
+| nonblock_expr '?'                                             { $$ = mk_node("ExprTry", 1, $1); }
 | nonblock_expr '.' path_generic_args_with_colons               { $$ = mk_node("ExprField", 2, $1, $3); }
 | nonblock_expr '.' LIT_INTEGER                                 { $$ = mk_node("ExprTupleIndex", 1, $1); }
 | nonblock_expr '[' maybe_expr ']'                              { $$ = mk_node("ExprIndex", 2, $1, $3); }
@@ -1325,6 +1398,8 @@ nonblock_expr
 | RETURN expr                                                   { $$ = mk_node("ExprRet", 1, $2); }
 | BREAK                                                         { $$ = mk_node("ExprBreak", 0); }
 | BREAK lifetime                                                { $$ = mk_node("ExprBreak", 1, $2); }
+| YIELD                                                         { $$ = mk_node("ExprYield", 0); }
+| YIELD expr                                                    { $$ = mk_node("ExprYield", 1, $2); }
 | nonblock_expr LARROW expr                                     { $$ = mk_node("ExprInPlace", 2, $1, $3); }
 | nonblock_expr '=' expr                                        { $$ = mk_node("ExprAssign", 2, $1, $3); }
 | nonblock_expr SHLEQ expr                                      { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
@@ -1360,8 +1435,8 @@ nonblock_expr
 |               DOTDOT expr                                     { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
 |               DOTDOT                                          { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
 | nonblock_expr AS ty                                           { $$ = mk_node("ExprCast", 2, $1, $3); }
-| BOX nonparen_expr                                             { $$ = mk_node("ExprBox", 1, $2); }
-| %prec BOXPLACE BOX '(' maybe_expr ')' nonblock_expr           { $$ = mk_node("ExprBox", 2, $3, $5); }
+| nonblock_expr ':' ty                                          { $$ = mk_node("ExprTypeAscr", 2, $1, $3); }
+| BOX expr                                                      { $$ = mk_node("ExprBox", 1, $2); }
 | expr_qualified_path
 | nonblock_prefix_expr
 ;
@@ -1373,6 +1448,7 @@ expr
 | SELF                                                { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
 | macro_expr                                          { $$ = mk_node("ExprMac", 1, $1); }
 | path_expr '{' struct_expr_fields '}'                { $$ = mk_node("ExprStruct", 2, $1, $3); }
+| expr '?'                                            { $$ = mk_node("ExprTry", 1, $1); }
 | expr '.' path_generic_args_with_colons              { $$ = mk_node("ExprField", 2, $1, $3); }
 | expr '.' LIT_INTEGER                                { $$ = mk_node("ExprTupleIndex", 1, $1); }
 | expr '[' maybe_expr ']'                             { $$ = mk_node("ExprIndex", 2, $1, $3); }
@@ -1385,6 +1461,8 @@ expr
 | RETURN expr                                         { $$ = mk_node("ExprRet", 1, $2); }
 | BREAK                                               { $$ = mk_node("ExprBreak", 0); }
 | BREAK ident                                         { $$ = mk_node("ExprBreak", 1, $2); }
+| YIELD                                               { $$ = mk_node("ExprYield", 0); }
+| YIELD expr                                          { $$ = mk_node("ExprYield", 1, $2); }
 | expr LARROW expr                                    { $$ = mk_node("ExprInPlace", 2, $1, $3); }
 | expr '=' expr                                       { $$ = mk_node("ExprAssign", 2, $1, $3); }
 | expr SHLEQ expr                                     { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
@@ -1420,69 +1498,8 @@ expr
 |      DOTDOT expr                                    { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
 |      DOTDOT                                         { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
 | expr AS ty                                          { $$ = mk_node("ExprCast", 2, $1, $3); }
-| BOX nonparen_expr                                   { $$ = mk_node("ExprBox", 1, $2); }
-| %prec BOXPLACE BOX '(' maybe_expr ')' expr          { $$ = mk_node("ExprBox", 2, $3, $5); }
-| expr_qualified_path
-| block_expr
-| block
-| nonblock_prefix_expr
-;
-
-nonparen_expr
-: lit                                                 { $$ = mk_node("ExprLit", 1, $1); }
-| %prec IDENT
-  path_expr                                           { $$ = mk_node("ExprPath", 1, $1); }
-| SELF                                                { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
-| macro_expr                                          { $$ = mk_node("ExprMac", 1, $1); }
-| path_expr '{' struct_expr_fields '}'                { $$ = mk_node("ExprStruct", 2, $1, $3); }
-| nonparen_expr '.' path_generic_args_with_colons     { $$ = mk_node("ExprField", 2, $1, $3); }
-| nonparen_expr '.' LIT_INTEGER                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
-| nonparen_expr '[' maybe_expr ']'                    { $$ = mk_node("ExprIndex", 2, $1, $3); }
-| nonparen_expr '(' maybe_exprs ')'                   { $$ = mk_node("ExprCall", 2, $1, $3); }
-| '[' vec_expr ']'                                    { $$ = mk_node("ExprVec", 1, $2); }
-| CONTINUE                                            { $$ = mk_node("ExprAgain", 0); }
-| CONTINUE ident                                      { $$ = mk_node("ExprAgain", 1, $2); }
-| RETURN                                              { $$ = mk_node("ExprRet", 0); }
-| RETURN expr                                         { $$ = mk_node("ExprRet", 1, $2); }
-| BREAK                                               { $$ = mk_node("ExprBreak", 0); }
-| BREAK ident                                         { $$ = mk_node("ExprBreak", 1, $2); }
-| nonparen_expr LARROW nonparen_expr                  { $$ = mk_node("ExprInPlace", 2, $1, $3); }
-| nonparen_expr '=' nonparen_expr                     { $$ = mk_node("ExprAssign", 2, $1, $3); }
-| nonparen_expr SHLEQ nonparen_expr                   { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
-| nonparen_expr SHREQ nonparen_expr                   { $$ = mk_node("ExprAssignShr", 2, $1, $3); }
-| nonparen_expr MINUSEQ nonparen_expr                 { $$ = mk_node("ExprAssignSub", 2, $1, $3); }
-| nonparen_expr ANDEQ nonparen_expr                   { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); }
-| nonparen_expr OREQ nonparen_expr                    { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); }
-| nonparen_expr PLUSEQ nonparen_expr                  { $$ = mk_node("ExprAssignAdd", 2, $1, $3); }
-| nonparen_expr STAREQ nonparen_expr                  { $$ = mk_node("ExprAssignMul", 2, $1, $3); }
-| nonparen_expr SLASHEQ nonparen_expr                 { $$ = mk_node("ExprAssignDiv", 2, $1, $3); }
-| nonparen_expr CARETEQ nonparen_expr                 { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); }
-| nonparen_expr PERCENTEQ nonparen_expr               { $$ = mk_node("ExprAssignRem", 2, $1, $3); }
-| nonparen_expr OROR nonparen_expr                    { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); }
-| nonparen_expr ANDAND nonparen_expr                  { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); }
-| nonparen_expr EQEQ nonparen_expr                    { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); }
-| nonparen_expr NE nonparen_expr                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); }
-| nonparen_expr '<' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); }
-| nonparen_expr '>' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); }
-| nonparen_expr LE nonparen_expr                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); }
-| nonparen_expr GE nonparen_expr                      { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); }
-| nonparen_expr '|' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); }
-| nonparen_expr '^' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); }
-| nonparen_expr '&' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); }
-| nonparen_expr SHL nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); }
-| nonparen_expr SHR nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); }
-| nonparen_expr '+' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); }
-| nonparen_expr '-' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); }
-| nonparen_expr '*' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); }
-| nonparen_expr '/' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); }
-| nonparen_expr '%' nonparen_expr                     { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); }
-| nonparen_expr DOTDOT                                { $$ = mk_node("ExprRange", 2, $1, mk_none()); }
-| nonparen_expr DOTDOT nonparen_expr                  { $$ = mk_node("ExprRange", 2, $1, $3); }
-|               DOTDOT nonparen_expr                  { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
-|               DOTDOT                                { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
-| nonparen_expr AS ty                                 { $$ = mk_node("ExprCast", 2, $1, $3); }
-| BOX nonparen_expr                                   { $$ = mk_node("ExprBox", 1, $2); }
-| %prec BOXPLACE BOX '(' maybe_expr ')' expr          { $$ = mk_node("ExprBox", 1, $3, $5); }
+| expr ':' ty                                         { $$ = mk_node("ExprTypeAscr", 2, $1, $3); }
+| BOX expr                                            { $$ = mk_node("ExprBox", 1, $2); }
 | expr_qualified_path
 | block_expr
 | block
@@ -1495,6 +1512,7 @@ expr_nostruct
   path_expr                                           { $$ = mk_node("ExprPath", 1, $1); }
 | SELF                                                { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); }
 | macro_expr                                          { $$ = mk_node("ExprMac", 1, $1); }
+| expr_nostruct '?'                                   { $$ = mk_node("ExprTry", 1, $1); }
 | expr_nostruct '.' path_generic_args_with_colons     { $$ = mk_node("ExprField", 2, $1, $3); }
 | expr_nostruct '.' LIT_INTEGER                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
 | expr_nostruct '[' maybe_expr ']'                    { $$ = mk_node("ExprIndex", 2, $1, $3); }
@@ -1507,6 +1525,8 @@ expr_nostruct
 | RETURN expr                                         { $$ = mk_node("ExprRet", 1, $2); }
 | BREAK                                               { $$ = mk_node("ExprBreak", 0); }
 | BREAK ident                                         { $$ = mk_node("ExprBreak", 1, $2); }
+| YIELD                                               { $$ = mk_node("ExprYield", 0); }
+| YIELD expr                                          { $$ = mk_node("ExprYield", 1, $2); }
 | expr_nostruct LARROW expr_nostruct                  { $$ = mk_node("ExprInPlace", 2, $1, $3); }
 | expr_nostruct '=' expr_nostruct                     { $$ = mk_node("ExprAssign", 2, $1, $3); }
 | expr_nostruct SHLEQ expr_nostruct                   { $$ = mk_node("ExprAssignShl", 2, $1, $3); }
@@ -1542,8 +1562,8 @@ expr_nostruct
 |               DOTDOT expr_nostruct                  { $$ = mk_node("ExprRange", 2, mk_none(), $2); }
 |               DOTDOT                                { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); }
 | expr_nostruct AS ty                                 { $$ = mk_node("ExprCast", 2, $1, $3); }
-| BOX nonparen_expr                                   { $$ = mk_node("ExprBox", 1, $2); }
-| %prec BOXPLACE BOX '(' maybe_expr ')' expr_nostruct { $$ = mk_node("ExprBox", 1, $3, $5); }
+| expr_nostruct ':' ty                                { $$ = mk_node("ExprTypeAscr", 2, $1, $3); }
+| BOX expr                                            { $$ = mk_node("ExprBox", 1, $2); }
 | expr_qualified_path
 | block_expr
 | block
@@ -1558,7 +1578,6 @@ nonblock_prefix_expr_nostruct
 | ANDAND maybe_mut expr_nostruct            { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); }
 | lambda_expr_nostruct
 | MOVE lambda_expr_nostruct                 { $$ = $2; }
-| proc_expr_nostruct
 ;
 
 nonblock_prefix_expr
@@ -1569,7 +1588,6 @@ nonblock_prefix_expr
 | ANDAND maybe_mut expr            { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); }
 | lambda_expr
 | MOVE lambda_expr                 { $$ = $2; }
-| proc_expr
 ;
 
 expr_qualified_path
@@ -1606,43 +1624,42 @@ maybe_as_trait_ref
 
 lambda_expr
 : %prec LAMBDA
-  OROR ret_ty expr                                        { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
-| %prec LAMBDA
-  '|' maybe_unboxed_closure_kind '|' ret_ty expr          { $$ = mk_node("ExprFnBlock", 3, mk_none(), $4, $5); }
+  OROR ret_ty expr                                    { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
 | %prec LAMBDA
-  '|' inferrable_params '|' ret_ty expr                   { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); }
+  '|' '|' ret_ty expr                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); }
 | %prec LAMBDA
-  '|' '&' maybe_mut ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $5, $7, $8); }
+  '|' inferrable_params '|' ret_ty expr               { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); }
 | %prec LAMBDA
-  '|' ':' inferrable_params '|' ret_ty expr               { $$ = mk_node("ExprFnBlock", 3, $3, $5, $6); }
+  '|' inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); }
 ;
 
-lambda_expr_nostruct
+lambda_expr_no_first_bar
 : %prec LAMBDA
-  OROR expr_nostruct                                        { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); }
-| %prec LAMBDA
-  '|' maybe_unboxed_closure_kind '|'  expr_nostruct         { $$ = mk_node("ExprFnBlock", 2, mk_none(), $4); }
+  '|' ret_ty expr                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
 | %prec LAMBDA
-  '|' inferrable_params '|' expr_nostruct                   { $$ = mk_node("ExprFnBlock", 2, $2, $4); }
+  inferrable_params '|' ret_ty expr               { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); }
 | %prec LAMBDA
-  '|' '&' maybe_mut ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $5, $7); }
-| %prec LAMBDA
-  '|' ':' inferrable_params '|' expr_nostruct               { $$ = mk_node("ExprFnBlock", 2, $3, $5); }
-
+  inferrable_params OROR lambda_expr_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); }
 ;
 
-proc_expr
+lambda_expr_nostruct
 : %prec LAMBDA
-  PROC '(' ')' expr                         { $$ = mk_node("ExprProc", 2, mk_none(), $4); }
+  OROR expr_nostruct                                           { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); }
+| %prec LAMBDA
+  '|' '|' ret_ty expr_nostruct                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $3, $4); }
 | %prec LAMBDA
-  PROC '(' inferrable_params ')' expr       { $$ = mk_node("ExprProc", 2, $3, $5); }
+  '|' inferrable_params '|' expr_nostruct                      { $$ = mk_node("ExprFnBlock", 2, $2, $4); }
+| %prec LAMBDA
+  '|' inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $2, mk_none(), $4); }
 ;
 
-proc_expr_nostruct
+lambda_expr_nostruct_no_first_bar
 : %prec LAMBDA
-  PROC '(' ')' expr_nostruct                     { $$ = mk_node("ExprProc", 2, mk_none(), $4); }
+  '|' ret_ty expr_nostruct                                 { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); }
+| %prec LAMBDA
+  inferrable_params '|' ret_ty expr_nostruct               { $$ = mk_node("ExprFnBlock", 3, $1, $3, $4); }
 | %prec LAMBDA
-  PROC '(' inferrable_params ')' expr_nostruct   { $$ = mk_node("ExprProc", 2, $3, $5); }
+  inferrable_params OROR lambda_expr_nostruct_no_first_bar { $$ = mk_node("ExprFnBlock", 3, $1, mk_none(), $3); }
 ;
 
 vec_expr
@@ -1654,6 +1671,7 @@ struct_expr_fields
 : field_inits
 | field_inits ','
 | maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); }
+| %empty                               { $$ = mk_none(); }
 ;
 
 maybe_field_inits
@@ -1668,7 +1686,9 @@ field_inits
 ;
 
 field_init
-: ident ':' expr   { $$ = mk_node("FieldInit", 2, $1, $3); }
+: ident                { $$ = mk_node("FieldInit", 1, $1); }
+| ident ':' expr       { $$ = mk_node("FieldInit", 2, $1, $3); }
+| LIT_INTEGER ':' expr { $$ = mk_node("FieldInit", 2, mk_atom(yytext), $3); }
 ;
 
 default_field_init
@@ -1689,10 +1709,18 @@ block_expr
 
 full_block_expr
 : block_expr
-| full_block_expr '.' path_generic_args_with_colons %prec IDENT         { $$ = mk_node("ExprField", 2, $1, $3); }
-| full_block_expr '.' path_generic_args_with_colons '[' maybe_expr ']'  { $$ = mk_node("ExprIndex", 3, $1, $3, $5); }
-| full_block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); }
-| full_block_expr '.' LIT_INTEGER                                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
+| block_expr_dot
+;
+
+block_expr_dot
+: block_expr     '.' path_generic_args_with_colons %prec IDENT         { $$ = mk_node("ExprField", 2, $1, $3); }
+| block_expr_dot '.' path_generic_args_with_colons %prec IDENT         { $$ = mk_node("ExprField", 2, $1, $3); }
+| block_expr     '.' path_generic_args_with_colons '[' maybe_expr ']'  { $$ = mk_node("ExprIndex", 3, $1, $3, $5); }
+| block_expr_dot '.' path_generic_args_with_colons '[' maybe_expr ']'  { $$ = mk_node("ExprIndex", 3, $1, $3, $5); }
+| block_expr     '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); }
+| block_expr_dot '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); }
+| block_expr     '.' LIT_INTEGER                                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
+| block_expr_dot '.' LIT_INTEGER                                       { $$ = mk_node("ExprTupleIndex", 1, $1); }
 ;
 
 expr_match
@@ -1714,12 +1742,13 @@ match_clause
 ;
 
 nonblock_match_clause
-: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr   { $$ = mk_node("Arm", 4, $1, $2, $3, $5); }
-| maybe_outer_attrs pats_or maybe_guard FAT_ARROW full_block_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); }
+: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr  { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); }
+| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr_dot { $$ = mk_node("ArmNonblock", 4, $1, $2, $3, $5); }
 ;
 
 block_match_clause
-: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("Arm", 4, $1, $2, $3, $5); }
+: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block      { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); }
+| maybe_outer_attrs pats_or maybe_guard FAT_ARROW block_expr { $$ = mk_node("ArmBlock", 4, $1, $2, $3, $5); }
 ;
 
 maybe_guard
@@ -1796,6 +1825,10 @@ maybe_ident
 
 ident
 : IDENT                      { $$ = mk_node("ident", 1, mk_atom(yytext)); }
+// Weak keywords that can be used as identifiers
+| CATCH                      { $$ = mk_node("ident", 1, mk_atom(yytext)); }
+| DEFAULT                    { $$ = mk_node("ident", 1, mk_atom(yytext)); }
+| UNION                      { $$ = mk_node("ident", 1, mk_atom(yytext)); }
 ;
 
 unpaired_token
@@ -1836,13 +1869,20 @@ unpaired_token
 | LIFETIME                   { $$ = mk_atom(yytext); }
 | SELF                       { $$ = mk_atom(yytext); }
 | STATIC                     { $$ = mk_atom(yytext); }
+| ABSTRACT                   { $$ = mk_atom(yytext); }
+| ALIGNOF                    { $$ = mk_atom(yytext); }
 | AS                         { $$ = mk_atom(yytext); }
+| BECOME                     { $$ = mk_atom(yytext); }
 | BREAK                      { $$ = mk_atom(yytext); }
+| CATCH                      { $$ = mk_atom(yytext); }
 | CRATE                      { $$ = mk_atom(yytext); }
+| DEFAULT                    { $$ = mk_atom(yytext); }
+| DO                         { $$ = mk_atom(yytext); }
 | ELSE                       { $$ = mk_atom(yytext); }
 | ENUM                       { $$ = mk_atom(yytext); }
 | EXTERN                     { $$ = mk_atom(yytext); }
 | FALSE                      { $$ = mk_atom(yytext); }
+| FINAL                      { $$ = mk_atom(yytext); }
 | FN                         { $$ = mk_atom(yytext); }
 | FOR                        { $$ = mk_atom(yytext); }
 | IF                         { $$ = mk_atom(yytext); }
@@ -1850,21 +1890,31 @@ unpaired_token
 | IN                         { $$ = mk_atom(yytext); }
 | LET                        { $$ = mk_atom(yytext); }
 | LOOP                       { $$ = mk_atom(yytext); }
+| MACRO                      { $$ = mk_atom(yytext); }
 | MATCH                      { $$ = mk_atom(yytext); }
 | MOD                        { $$ = mk_atom(yytext); }
 | MOVE                       { $$ = mk_atom(yytext); }
 | MUT                        { $$ = mk_atom(yytext); }
+| OFFSETOF                   { $$ = mk_atom(yytext); }
+| OVERRIDE                   { $$ = mk_atom(yytext); }
 | PRIV                       { $$ = mk_atom(yytext); }
 | PUB                        { $$ = mk_atom(yytext); }
+| PURE                       { $$ = mk_atom(yytext); }
 | REF                        { $$ = mk_atom(yytext); }
 | RETURN                     { $$ = mk_atom(yytext); }
 | STRUCT                     { $$ = mk_atom(yytext); }
+| SIZEOF                     { $$ = mk_atom(yytext); }
+| SUPER                      { $$ = mk_atom(yytext); }
 | TRUE                       { $$ = mk_atom(yytext); }
 | TRAIT                      { $$ = mk_atom(yytext); }
 | TYPE                       { $$ = mk_atom(yytext); }
+| UNION                      { $$ = mk_atom(yytext); }
 | UNSAFE                     { $$ = mk_atom(yytext); }
+| UNSIZED                    { $$ = mk_atom(yytext); }
 | USE                        { $$ = mk_atom(yytext); }
+| VIRTUAL                    { $$ = mk_atom(yytext); }
 | WHILE                      { $$ = mk_atom(yytext); }
+| YIELD                      { $$ = mk_atom(yytext); }
 | CONTINUE                   { $$ = mk_atom(yytext); }
 | PROC                       { $$ = mk_atom(yytext); }
 | BOX                        { $$ = mk_atom(yytext); }
@@ -1942,4 +1992,4 @@ brackets_delimited_token_trees
                $2,
                mk_node("TTTok", 1, mk_atom("]")));
 }
-;
\ No newline at end of file
+;
diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h
index 081bd050259..15ea738ed00 100644
--- a/src/grammar/tokens.h
+++ b/src/grammar/tokens.h
@@ -30,6 +30,7 @@ enum Token {
   DOTDOT,
   DOTDOTDOT,
   MOD_SEP,
+  LARROW,
   RARROW,
   FAT_ARROW,
   LIT_BYTE,
@@ -47,13 +48,20 @@ enum Token {
   // keywords
   SELF,
   STATIC,
+  ABSTRACT,
+  ALIGNOF,
   AS,
+  BECOME,
   BREAK,
+  CATCH,
   CRATE,
+  DEFAULT,
+  DO,
   ELSE,
   ENUM,
   EXTERN,
   FALSE,
+  FINAL,
   FN,
   FOR,
   IF,
@@ -61,21 +69,31 @@ enum Token {
   IN,
   LET,
   LOOP,
+  MACRO,
   MATCH,
   MOD,
   MOVE,
   MUT,
+  OFFSETOF,
+  OVERRIDE,
   PRIV,
   PUB,
+  PURE,
   REF,
   RETURN,
+  SIZEOF,
   STRUCT,
+  SUPER,
+  UNION,
   TRUE,
   TRAIT,
   TYPE,
   UNSAFE,
+  UNSIZED,
   USE,
+  VIRTUAL,
   WHILE,
+  YIELD,
   CONTINUE,
   PROC,
   BOX,
diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs
index 5a9cd82b9d1..3a2022ad429 100644
--- a/src/liballoc/allocator.rs
+++ b/src/liballoc/allocator.rs
@@ -70,7 +70,7 @@ impl Layout {
     ///
     /// * `align` must be a power of two,
     ///
-    /// * `align` must not exceed 2^31 (i.e. `1 << 31`),
+    /// * `align` must not exceed 2<sup>31</sup> (i.e. `1 << 31`),
     ///
     /// * `size`, when rounded up to the nearest multiple of `align`,
     ///    must not overflow (i.e. the rounded value must be less than
@@ -113,7 +113,7 @@ impl Layout {
     /// # Safety
     ///
     /// This function is unsafe as it does not verify that `align` is
-    /// a power-of-two that is also less than or equal to 2^31, nor
+    /// a power-of-two that is also less than or equal to 2<sup>31</sup>, nor
     /// that `size` aligned to `align` fits within the address space
     /// (i.e. the `Layout::from_size_align` preconditions).
     #[inline]
@@ -227,7 +227,7 @@ impl Layout {
         };
 
         // We can assume that `self.align` is a power-of-two that does
-        // not exceed 2^31. Furthermore, `alloc_size` has already been
+        // not exceed 2<sup>31</sup>. Furthermore, `alloc_size` has already been
         // rounded up to a multiple of `self.align`; therefore, the
         // call to `Layout::from_size_align` below should never panic.
         Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size))
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 3b7dbd813cf..9481cd4e1a4 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -52,8 +52,10 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 /// also destroyed.
 ///
 /// Shared references in Rust disallow mutation by default, and `Arc` is no
-/// exception. If you need to mutate through an `Arc`, use [`Mutex`][mutex],
-/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types.
+/// exception: you cannot generally obtain a mutable reference to something
+/// inside an `Arc`. If you need to mutate through an `Arc`, use
+/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic]
+/// types.
 ///
 /// ## Thread Safety
 ///
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 35c8530b4dd..79292d390e5 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -269,7 +269,38 @@ impl<T: ?Sized> Box<T> {
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
     pub unsafe fn from_raw(raw: *mut T) -> Self {
-        mem::transmute(raw)
+        Box::from_unique(Unique::new_unchecked(raw))
+    }
+
+    /// Constructs a `Box` from a `Unique<T>` pointer.
+    ///
+    /// After calling this function, the memory is owned by a `Box` and `T` can
+    /// then be destroyed and released upon drop.
+    ///
+    /// # Safety
+    ///
+    /// A `Unique<T>` can be safely created via [`Unique::new`] and thus doesn't
+    /// necessarily own the data pointed to nor is the data guaranteed to live
+    /// as long as the pointer.
+    ///
+    /// [`Unique::new`]: ../../core/ptr/struct.Unique.html#method.new
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(unique)]
+    ///
+    /// fn main() {
+    ///     let x = Box::new(5);
+    ///     let ptr = Box::into_unique(x);
+    ///     let x = unsafe { Box::from_unique(ptr) };
+    /// }
+    /// ```
+    #[unstable(feature = "unique", reason = "needs an RFC to flesh out design",
+               issue = "27730")]
+    #[inline]
+    pub unsafe fn from_unique(u: Unique<T>) -> Self {
+        mem::transmute(u)
     }
 
     /// Consumes the `Box`, returning the wrapped raw pointer.
@@ -295,7 +326,7 @@ impl<T: ?Sized> Box<T> {
     #[stable(feature = "box_raw", since = "1.4.0")]
     #[inline]
     pub fn into_raw(b: Box<T>) -> *mut T {
-        unsafe { mem::transmute(b) }
+        Box::into_unique(b).as_ptr()
     }
 
     /// Consumes the `Box`, returning the wrapped pointer as `Unique<T>`.
@@ -303,13 +334,18 @@ impl<T: ?Sized> Box<T> {
     /// After calling this function, the caller is responsible for the
     /// memory previously managed by the `Box`. In particular, the
     /// caller should properly destroy `T` and release the memory. The
-    /// proper way to do so is to convert the raw pointer back into a
-    /// `Box` with the [`Box::from_raw`] function.
+    /// proper way to do so is to either convert the `Unique<T>` pointer:
+    ///
+    /// - Into a `Box` with the [`Box::from_unique`] function.
+    ///
+    /// - Into a raw pointer and back into a `Box` with the [`Box::from_raw`]
+    ///   function.
     ///
     /// Note: this is an associated function, which means that you have
     /// to call it as `Box::into_unique(b)` instead of `b.into_unique()`. This
     /// is so that there is no conflict with a method on the inner type.
     ///
+    /// [`Box::from_unique`]: struct.Box.html#method.from_unique
     /// [`Box::from_raw`]: struct.Box.html#method.from_raw
     ///
     /// # Examples
diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs
index 578d90c5ba9..58299d5d836 100644
--- a/src/liballoc/fmt.rs
+++ b/src/liballoc/fmt.rs
@@ -475,7 +475,6 @@
 //! them with the same character. For example, the `{` character is escaped with
 //! `{{` and the `}` character is escaped with `}}`.
 //!
-//! [`format!`]: ../../macro.format.html
 //! [`usize`]: ../../std/primitive.usize.html
 //! [`isize`]: ../../std/primitive.isize.html
 //! [`i8`]: ../../std/primitive.i8.html
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index d51aaa23c6a..0cbfc9e9dac 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -121,6 +121,7 @@
 #![feature(unique)]
 #![feature(unsize)]
 #![feature(allocator_internals)]
+#![feature(on_unimplemented)]
 
 #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))]
 #![cfg_attr(test, feature(test, box_heap))]
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 553980d463f..2f8620cc750 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -19,7 +19,7 @@
 //! given value is destroyed, the pointed-to value is also destroyed.
 //!
 //! Shared references in Rust disallow mutation by default, and [`Rc`]
-//! is no exception: you cannot obtain a mutable reference to
+//! is no exception: you cannot generally obtain a mutable reference to
 //! something inside an [`Rc`]. If you need mutability, put a [`Cell`]
 //! or [`RefCell`] inside the [`Rc`]; see [an example of mutability
 //! inside an Rc][mutability].
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index 830128f2b9f..895607ff8d4 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -959,13 +959,15 @@ impl str {
     /// assert_eq!(s.find("Léopard"), Some(13));
     /// ```
     ///
-    /// More complex patterns with closures:
+    /// More complex patterns using point-free style and closures:
     ///
     /// ```
     /// let s = "Löwe 老虎 Léopard";
     ///
     /// assert_eq!(s.find(char::is_whitespace), Some(5));
     /// assert_eq!(s.find(char::is_lowercase), Some(1));
+    /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1));
+    /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4));
     /// ```
     ///
     /// Not finding the pattern:
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 861291194f3..cf34e195dea 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -1543,6 +1543,7 @@ impl<T: Hash> Hash for Vec<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> Index<usize> for Vec<T> {
     type Output = T;
 
@@ -1554,6 +1555,7 @@ impl<T> Index<usize> for Vec<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> IndexMut<usize> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, index: usize) -> &mut T {
@@ -1562,8 +1564,8 @@ impl<T> IndexMut<usize> for Vec<T> {
     }
 }
 
-
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::Index<ops::Range<usize>> for Vec<T> {
     type Output = [T];
 
@@ -1572,7 +1574,9 @@ impl<T> ops::Index<ops::Range<usize>> for Vec<T> {
         Index::index(&**self, index)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::Index<ops::RangeTo<usize>> for Vec<T> {
     type Output = [T];
 
@@ -1581,7 +1585,9 @@ impl<T> ops::Index<ops::RangeTo<usize>> for Vec<T> {
         Index::index(&**self, index)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::Index<ops::RangeFrom<usize>> for Vec<T> {
     type Output = [T];
 
@@ -1590,7 +1596,9 @@ impl<T> ops::Index<ops::RangeFrom<usize>> for Vec<T> {
         Index::index(&**self, index)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::Index<ops::RangeFull> for Vec<T> {
     type Output = [T];
 
@@ -1599,7 +1607,9 @@ impl<T> ops::Index<ops::RangeFull> for Vec<T> {
         self
     }
 }
+
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
     type Output = [T];
 
@@ -1608,7 +1618,9 @@ impl<T> ops::Index<ops::RangeInclusive<usize>> for Vec<T> {
         Index::index(&**self, index)
     }
 }
+
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
     type Output = [T];
 
@@ -1619,41 +1631,52 @@ impl<T> ops::Index<ops::RangeToInclusive<usize>> for Vec<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::IndexMut<ops::Range<usize>> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::IndexMut<ops::RangeTo<usize>> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::IndexMut<ops::RangeFrom<usize>> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::IndexMut<ops::RangeFull> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, _index: ops::RangeFull) -> &mut [T] {
         self
     }
 }
+
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
         IndexMut::index_mut(&mut **self, index)
     }
 }
+
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"]
 impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for Vec<T> {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml
index 4042c4d2d4e..6d7d83dd993 100644
--- a/src/liballoc_jemalloc/Cargo.toml
+++ b/src/liballoc_jemalloc/Cargo.toml
@@ -19,7 +19,7 @@ libc = { path = "../rustc/libc_shim" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0"
+cc = "1.0.1"
 
 [features]
 debug = []
diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs
index 7dd85ddcc79..65e035d4ffd 100644
--- a/src/liballoc_jemalloc/build.rs
+++ b/src/liballoc_jemalloc/build.rs
@@ -63,15 +63,6 @@ fn main() {
         _ => return,
     };
 
-    let compiler = cc::Build::new().get_compiler();
-    // only msvc returns None for ar so unwrap is okay
-    let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
-    let cflags = compiler.args()
-        .iter()
-        .map(|s| s.to_str().unwrap())
-        .collect::<Vec<_>>()
-        .join(" ");
-
     let mut cmd = Command::new("sh");
     cmd.arg(native.src_dir.join("configure")
                           .to_str()
@@ -79,8 +70,6 @@ fn main() {
                           .replace("C:\\", "/c/")
                           .replace("\\", "/"))
        .current_dir(&native.out_dir)
-       .env("CC", compiler.path())
-       .env("EXTRA_CFLAGS", cflags.clone())
        // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
        // that GCC will run the preprocessor, and only the preprocessor, over
        // jemalloc's source files. If we don't specify CPPFLAGS, then at least
@@ -89,9 +78,7 @@ fn main() {
        // passed to GCC, and then GCC won't define the
        // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
        // select an atomic operation implementation.
-       .env("CPPFLAGS", cflags.clone())
-       .env("AR", &ar)
-       .env("RANLIB", format!("{} s", ar.display()));
+       .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default());
 
     if target.contains("ios") {
         cmd.arg("--disable-tls");
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 2eb659699eb..7aa5f8a9186 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -14,7 +14,7 @@
 #![unstable(feature = "alloc_system",
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
-            issue = "27783")]
+            issue = "32838")]
 #![feature(global_allocator)]
 #![feature(allocator_api)]
 #![feature(alloc)]
diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml
deleted file mode 100644
index 800e36161d2..00000000000
--- a/src/libcollections/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-authors = ["The Rust Project Developers"]
-name = "collections"
-version = "0.0.0"
-
-[lib]
-name = "collections"
-path = "lib.rs"
-
-[dependencies]
-alloc = { path = "../liballoc" }
-core = { path = "../libcore" }
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
deleted file mode 100644
index 55316db3d5a..00000000000
--- a/src/libcollections/lib.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(unused_attributes)]
-#![unstable(feature = "collections",
-            reason = "this library is unlikely to be stabilized in its current \
-                      form or name",
-            issue = "27783")]
-#![rustc_deprecated(since = "1.20.0",
-                    reason = "collections moved to `alloc`")]
-#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
-       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
-       html_root_url = "https://doc.rust-lang.org/nightly/",
-       issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
-       test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
-#![no_std]
-#![deny(warnings)]
-
-#![feature(alloc)]
-#![feature(collections_range)]
-#![feature(macro_reexport)]
-#![feature(staged_api)]
-
-//! Collection types
-//!
-//! See [`std::collections`](../std/collections/index.html) for a detailed
-//! discussion of collections in Rust.
-
-#[macro_reexport(vec, format)]
-extern crate alloc;
-
-pub use alloc::Bound;
-
-pub use alloc::binary_heap;
-pub use alloc::borrow;
-pub use alloc::fmt;
-pub use alloc::linked_list;
-pub use alloc::range;
-pub use alloc::slice;
-pub use alloc::str;
-pub use alloc::string;
-pub use alloc::vec;
-pub use alloc::vec_deque;
-
-pub use alloc::btree_map;
-pub use alloc::btree_set;
-
-#[doc(no_inline)]
-pub use alloc::binary_heap::BinaryHeap;
-#[doc(no_inline)]
-pub use alloc::btree_map::BTreeMap;
-#[doc(no_inline)]
-pub use alloc::btree_set::BTreeSet;
-#[doc(no_inline)]
-pub use alloc::linked_list::LinkedList;
-#[doc(no_inline)]
-pub use alloc::vec_deque::VecDeque;
-#[doc(no_inline)]
-pub use alloc::string::String;
-#[doc(no_inline)]
-pub use alloc::vec::Vec;
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs
index b594c886b64..60b9eeb1283 100644
--- a/src/libcore/fmt/builders.rs
+++ b/src/libcore/fmt/builders.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use fmt::{self, FlagV1};
+use fmt;
 
 struct PadAdapter<'a, 'b: 'a> {
     fmt: &'a mut fmt::Formatter<'b>,
@@ -140,7 +140,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
 
@@ -233,7 +233,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
 
@@ -277,7 +277,7 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
 
@@ -519,6 +519,6 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     }
 
     fn is_pretty(&self) -> bool {
-        self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
+        self.fmt.alternate()
     }
 }
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 6c251b9eb09..1e45af5b105 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -322,7 +322,6 @@ impl<'a> ArgumentV1<'a> {
 
 // flags available in the v1 format of format_args
 #[derive(Copy, Clone)]
-#[allow(dead_code)] // SignMinus isn't currently used
 enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, }
 
 impl<'a> Arguments<'a> {
@@ -427,7 +426,7 @@ impl<'a> Display for Arguments<'a> {
     }
 }
 
-/// Format trait for the `?` character.
+/// `?` formatting.
 ///
 /// `Debug` should format the output in a programmer-facing, debugging context.
 ///
@@ -593,7 +592,7 @@ pub trait Display {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `o` character.
+/// `o` formatting.
 ///
 /// The `Octal` trait should format its output as a number in base-8.
 ///
@@ -640,7 +639,7 @@ pub trait Octal {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `b` character.
+/// `b` formatting.
 ///
 /// The `Binary` trait should format its output as a number in binary.
 ///
@@ -687,7 +686,7 @@ pub trait Binary {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `x` character.
+/// `x` formatting.
 ///
 /// The `LowerHex` trait should format its output as a number in hexadecimal, with `a` through `f`
 /// in lower case.
@@ -735,7 +734,7 @@ pub trait LowerHex {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `X` character.
+/// `X` formatting.
 ///
 /// The `UpperHex` trait should format its output as a number in hexadecimal, with `A` through `F`
 /// in upper case.
@@ -783,7 +782,7 @@ pub trait UpperHex {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `p` character.
+/// `p` formatting.
 ///
 /// The `Pointer` trait should format its output as a memory location. This is commonly presented
 /// as hexadecimal.
@@ -828,7 +827,7 @@ pub trait Pointer {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `e` character.
+/// `e` formatting.
 ///
 /// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`.
 ///
@@ -871,7 +870,7 @@ pub trait LowerExp {
     fn fmt(&self, f: &mut Formatter) -> Result;
 }
 
-/// Format trait for the `E` character.
+/// `E` formatting.
 ///
 /// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`.
 ///
@@ -1276,7 +1275,7 @@ impl<'a> Formatter<'a> {
         write(self.buf, fmt)
     }
 
-    /// Flags for formatting (packed version of rt::Flag)
+    /// Flags for formatting
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn flags(&self) -> u32 { self.flags }
 
diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs
index 91fd01b36d4..4e4d9b3f1e2 100644
--- a/src/libcore/hash/sip.rs
+++ b/src/libcore/hash/sip.rs
@@ -22,7 +22,7 @@ use mem;
 /// This is currently the default hashing function used by standard library
 /// (eg. `collections::HashMap` uses it by default).
 ///
-/// See: https://131002.net/siphash/
+/// See: <https://131002.net/siphash>
 #[unstable(feature = "sip_hash_13", issue = "34767")]
 #[rustc_deprecated(since = "1.13.0",
                    reason = "use `std::collections::hash_map::DefaultHasher` instead")]
@@ -33,7 +33,7 @@ pub struct SipHasher13 {
 
 /// An implementation of SipHash 2-4.
 ///
-/// See: https://131002.net/siphash/
+/// See: <https://131002.net/siphash/>
 #[unstable(feature = "sip_hash_13", issue = "34767")]
 #[rustc_deprecated(since = "1.13.0",
                    reason = "use `std::collections::hash_map::DefaultHasher` instead")]
@@ -44,7 +44,7 @@ pub struct SipHasher24 {
 
 /// An implementation of SipHash 2-4.
 ///
-/// See: https://131002.net/siphash/
+/// See: <https://131002.net/siphash/>
 ///
 /// SipHash is a general-purpose hashing function: it runs at a good
 /// speed (competitive with Spooky and City) and permits strong _keyed_
@@ -72,6 +72,7 @@ struct Hasher<S: Sip> {
 }
 
 #[derive(Debug, Clone, Copy)]
+#[repr(C)]
 struct State {
     // v0, v2 and v1, v3 show up in pairs in the algorithm,
     // and simd implementations of SipHash will use vectors
diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index e9e31065cf8..79767b37601 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -2059,14 +2059,23 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return Ordering::Equal,
-                (None, _   ) => return Ordering::Less,
-                (_   , None) => return Ordering::Greater,
-                (Some(x), Some(y)) => match x.cmp(&y) {
-                    Ordering::Equal => (),
-                    non_eq => return non_eq,
+            let x = match self.next() {
+                None => if other.next().is_none() {
+                    return Ordering::Equal
+                } else {
+                    return Ordering::Less
                 },
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return Ordering::Greater,
+                Some(val) => val,
+            };
+
+            match x.cmp(&y) {
+                Ordering::Equal => (),
+                non_eq => return non_eq,
             }
         }
     }
@@ -2082,14 +2091,23 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return Some(Ordering::Equal),
-                (None, _   ) => return Some(Ordering::Less),
-                (_   , None) => return Some(Ordering::Greater),
-                (Some(x), Some(y)) => match x.partial_cmp(&y) {
-                    Some(Ordering::Equal) => (),
-                    non_eq => return non_eq,
+            let x = match self.next() {
+                None => if other.next().is_none() {
+                    return Some(Ordering::Equal)
+                } else {
+                    return Some(Ordering::Less)
                 },
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return Some(Ordering::Greater),
+                Some(val) => val,
+            };
+
+            match x.partial_cmp(&y) {
+                Some(Ordering::Equal) => (),
+                non_eq => return non_eq,
             }
         }
     }
@@ -2105,11 +2123,17 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return true,
-                (None, _) | (_, None) => return false,
-                (Some(x), Some(y)) => if x != y { return false },
-            }
+            let x = match self.next() {
+                None => return other.next().is_none(),
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return false,
+                Some(val) => val,
+            };
+
+            if x != y { return false }
         }
     }
 
@@ -2124,11 +2148,17 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return false,
-                (None, _) | (_, None) => return true,
-                (Some(x), Some(y)) => if x.ne(&y) { return true },
-            }
+            let x = match self.next() {
+                None => return other.next().is_some(),
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return true,
+                Some(val) => val,
+            };
+
+            if x != y { return true }
         }
     }
 
@@ -2143,18 +2173,21 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return false,
-                (None, _   ) => return true,
-                (_   , None) => return false,
-                (Some(x), Some(y)) => {
-                    match x.partial_cmp(&y) {
-                        Some(Ordering::Less) => return true,
-                        Some(Ordering::Equal) => {}
-                        Some(Ordering::Greater) => return false,
-                        None => return false,
-                    }
-                },
+            let x = match self.next() {
+                None => return other.next().is_some(),
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return false,
+                Some(val) => val,
+            };
+
+            match x.partial_cmp(&y) {
+                Some(Ordering::Less) => return true,
+                Some(Ordering::Equal) => (),
+                Some(Ordering::Greater) => return false,
+                None => return false,
             }
         }
     }
@@ -2170,18 +2203,21 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return true,
-                (None, _   ) => return true,
-                (_   , None) => return false,
-                (Some(x), Some(y)) => {
-                    match x.partial_cmp(&y) {
-                        Some(Ordering::Less) => return true,
-                        Some(Ordering::Equal) => {}
-                        Some(Ordering::Greater) => return false,
-                        None => return false,
-                    }
-                },
+            let x = match self.next() {
+                None => { other.next(); return true; },
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return false,
+                Some(val) => val,
+            };
+
+            match x.partial_cmp(&y) {
+                Some(Ordering::Less) => return true,
+                Some(Ordering::Equal) => (),
+                Some(Ordering::Greater) => return false,
+                None => return false,
             }
         }
     }
@@ -2197,18 +2233,21 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return false,
-                (None, _   ) => return false,
-                (_   , None) => return true,
-                (Some(x), Some(y)) => {
-                    match x.partial_cmp(&y) {
-                        Some(Ordering::Less) => return false,
-                        Some(Ordering::Equal) => {}
-                        Some(Ordering::Greater) => return true,
-                        None => return false,
-                    }
-                }
+            let x = match self.next() {
+                None => { other.next(); return false; },
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return true,
+                Some(val) => val,
+            };
+
+            match x.partial_cmp(&y) {
+                Some(Ordering::Less) => return false,
+                Some(Ordering::Equal) => (),
+                Some(Ordering::Greater) => return true,
+                None => return false,
             }
         }
     }
@@ -2224,18 +2263,21 @@ pub trait Iterator {
         let mut other = other.into_iter();
 
         loop {
-            match (self.next(), other.next()) {
-                (None, None) => return true,
-                (None, _   ) => return false,
-                (_   , None) => return true,
-                (Some(x), Some(y)) => {
-                    match x.partial_cmp(&y) {
-                        Some(Ordering::Less) => return false,
-                        Some(Ordering::Equal) => {}
-                        Some(Ordering::Greater) => return true,
-                        None => return false,
-                    }
-                },
+            let x = match self.next() {
+                None => return other.next().is_none(),
+                Some(val) => val,
+            };
+
+            let y = match other.next() {
+                None => return true,
+                Some(val) => val,
+            };
+
+            match x.partial_cmp(&y) {
+                Some(Ordering::Less) => return false,
+                Some(Ordering::Equal) => (),
+                Some(Ordering::Greater) => return true,
+                None => return false,
             }
         }
     }
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index d64c984ea7d..12667036444 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -682,7 +682,7 @@ mod builtin {
     #[cfg(dox)]
     macro_rules! file { () => ({ /* compiler built-in */ }) }
 
-    /// A macro which stringifies its argument.
+    /// A macro which stringifies its arguments.
     ///
     /// For more information, see the documentation for [`std::stringify!`].
     ///
@@ -690,7 +690,7 @@ mod builtin {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[macro_export]
     #[cfg(dox)]
-    macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
+    macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) }
 
     /// Includes a utf8-encoded file as a string.
     ///
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index e085d427b8c..16d5fadc536 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -429,9 +429,11 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
 
 /// Returns whether dropping values of type `T` matters.
 ///
-/// This is purely an optimization hint, and may be implemented conservatively.
-/// For instance, always returning `true` would be a valid implementation of
-/// this function.
+/// This is purely an optimization hint, and may be implemented conservatively:
+/// it may return `true` for types that don't actually need to be dropped.
+/// As such always returning `true` would be a valid implementation of
+/// this function. However if this function actually returns `false`, then you
+/// can be certain dropping `T` has no side effect.
 ///
 /// Low level implementations of things like collections, which need to manually
 /// drop their data, should use this function to avoid unnecessarily
@@ -836,7 +838,7 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
 ///
 /// See the `discriminant` function in this module for more information.
 #[stable(feature = "discriminant_value", since = "1.21.0")]
-pub struct Discriminant<T>(u64, PhantomData<*const T>);
+pub struct Discriminant<T>(u64, PhantomData<fn() -> T>);
 
 // N.B. These trait implementations cannot be derived because we don't want any bounds on T.
 
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 3d6abbb7e49..01990f61fee 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -551,7 +551,7 @@ impl<T: ?Sized> *const T {
     ///
     /// Most platforms fundamentally can't even construct such an allocation.
     /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2^63 bytes due to page-table limitations or splitting the address space.
+    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
     /// However, some 32-bit and 16-bit platforms may successfully serve a request for
     /// more than `isize::MAX` bytes with things like Physical Address
     /// Extension. As such, memory acquired directly from allocators or memory
@@ -684,7 +684,7 @@ impl<T: ?Sized> *const T {
     ///
     /// Most platforms fundamentally can't even construct such an allocation.
     /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2^63 bytes due to page-table limitations or splitting the address space.
+    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
     /// However, some 32-bit and 16-bit platforms may successfully serve a request for
     /// more than `isize::MAX` bytes with things like Physical Address
     /// Extension. As such, memory acquired directly from allocators or memory
@@ -743,7 +743,7 @@ impl<T: ?Sized> *const T {
     ///
     /// Most platforms fundamentally can't even construct such an allocation.
     /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2^63 bytes due to page-table limitations or splitting the address space.
+    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
     /// However, some 32-bit and 16-bit platforms may successfully serve a request for
     /// more than `isize::MAX` bytes with things like Physical Address
     /// Extension. As such, memory acquired directly from allocators or memory
@@ -1182,7 +1182,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// Most platforms fundamentally can't even construct such an allocation.
     /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2^63 bytes due to page-table limitations or splitting the address space.
+    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
     /// However, some 32-bit and 16-bit platforms may successfully serve a request for
     /// more than `isize::MAX` bytes with things like Physical Address
     /// Extension. As such, memory acquired directly from allocators or memory
@@ -1382,7 +1382,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// Most platforms fundamentally can't even construct such an allocation.
     /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2^63 bytes due to page-table limitations or splitting the address space.
+    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
     /// However, some 32-bit and 16-bit platforms may successfully serve a request for
     /// more than `isize::MAX` bytes with things like Physical Address
     /// Extension. As such, memory acquired directly from allocators or memory
@@ -1441,7 +1441,7 @@ impl<T: ?Sized> *mut T {
     ///
     /// Most platforms fundamentally can't even construct such an allocation.
     /// For instance, no known 64-bit platform can ever serve a request
-    /// for 2^63 bytes due to page-table limitations or splitting the address space.
+    /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space.
     /// However, some 32-bit and 16-bit platforms may successfully serve a request for
     /// more than `isize::MAX` bytes with things like Physical Address
     /// Extension. As such, memory acquired directly from allocators or memory
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index ea064ca5c39..db5bffced10 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -1060,7 +1060,7 @@ unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {}
 /// [`Result`]: enum.Result.html
 /// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter
 /// [`IntoIterator`]: ../iter/trait.IntoIterator.html
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<T> { inner: Option<T> }
 
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 0af9fcf0a3d..670c2afa66f 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1406,16 +1406,6 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> {
 impl<'a> FusedIterator for LinesAny<'a> {}
 
 /*
-Section: Comparing strings
-*/
-
-/// Bytewise slice equality
-#[inline]
-fn eq_slice(a: &str, b: &str) -> bool {
-    a.as_bytes() == b.as_bytes()
-}
-
-/*
 Section: UTF-8 validation
 */
 
@@ -1590,7 +1580,6 @@ mod traits {
     use cmp::Ordering;
     use ops;
     use slice::{self, SliceIndex};
-    use str::eq_slice;
 
     /// Implements ordering of strings.
     ///
@@ -1611,7 +1600,7 @@ mod traits {
     impl PartialEq for str {
         #[inline]
         fn eq(&self, other: &str) -> bool {
-            eq_slice(self, other)
+            self.as_bytes() == other.as_bytes()
         }
         #[inline]
         fn ne(&self, other: &str) -> bool { !(*self).eq(other) }
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 465d31b5f49..524f4508c9b 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -119,7 +119,9 @@ pub fn hint_core_should_pause()
 
 /// A boolean type which can be safely shared between threads.
 ///
-/// This type has the same in-memory representation as a `bool`.
+/// This type has the same in-memory representation as a [`bool`].
+///
+/// [`bool`]: ../../../std/primitive.bool.html
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicBool {
@@ -246,11 +248,13 @@ impl AtomicBool {
         AtomicBool { v: UnsafeCell::new(v as u8) }
     }
 
-    /// Returns a mutable reference to the underlying `bool`.
+    /// Returns a mutable reference to the underlying [`bool`].
     ///
     /// This is safe because the mutable reference guarantees that no other threads are
     /// concurrently accessing the atomic data.
     ///
+    /// [`bool`]: ../../../std/primitive.bool.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -369,7 +373,7 @@ impl AtomicBool {
         unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
     }
 
-    /// Stores a value into the `bool` if the current value is the same as the `current` value.
+    /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
     ///
     /// The return value is always the previous value. If it is equal to `current`, then the value
     /// was updated.
@@ -378,6 +382,7 @@ impl AtomicBool {
     /// ordering of this operation.
     ///
     /// [`Ordering`]: enum.Ordering.html
+    /// [`bool`]: ../../../std/primitive.bool.html
     ///
     /// # Examples
     ///
@@ -401,7 +406,7 @@ impl AtomicBool {
         }
     }
 
-    /// Stores a value into the `bool` if the current value is the same as the `current` value.
+    /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
     ///
     /// The return value is a result indicating whether the new value was written and containing
     /// the previous value. On success this value is guaranteed to be equal to `current`.
@@ -412,6 +417,7 @@ impl AtomicBool {
     /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and must
     /// be equivalent or weaker than the success ordering.
     ///
+    /// [`bool`]: ../../../std/primitive.bool.html
     /// [`Ordering`]: enum.Ordering.html
     /// [`Release`]: enum.Ordering.html#variant.Release
     /// [`AcqRel`]: enum.Ordering.html#variant.Release
@@ -452,7 +458,7 @@ impl AtomicBool {
         }
     }
 
-    /// Stores a value into the `bool` if the current value is the same as the `current` value.
+    /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
     ///
     /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the
     /// comparison succeeds, which can result in more efficient code on some platforms. The
@@ -465,6 +471,7 @@ impl AtomicBool {
     /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or
     /// weaker than the success ordering.
     ///
+    /// [`bool`]: ../../../std/primitive.bool.html
     /// [`compare_exchange`]: #method.compare_exchange
     /// [`Ordering`]: enum.Ordering.html
     /// [`Release`]: enum.Ordering.html#variant.Release
diff --git a/src/libcore/tests/hash/sip.rs b/src/libcore/tests/hash/sip.rs
index 4a9657e0340..c6dd41798f2 100644
--- a/src/libcore/tests/hash/sip.rs
+++ b/src/libcore/tests/hash/sip.rs
@@ -243,24 +243,22 @@ fn test_siphash_2_4() {
         t += 1;
     }
 }
-#[test] #[cfg(target_arch = "arm")]
+
+#[test]
+#[cfg(target_pointer_width = "32")]
 fn test_hash_usize() {
     let val = 0xdeadbeef_deadbeef_u64;
     assert!(hash(&(val as u64)) != hash(&(val as usize)));
     assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
 }
-#[test] #[cfg(target_arch = "x86_64")]
+
+#[test]
+#[cfg(target_pointer_width = "64")]
 fn test_hash_usize() {
     let val = 0xdeadbeef_deadbeef_u64;
     assert_eq!(hash(&(val as u64)), hash(&(val as usize)));
     assert!(hash(&(val as u32)) != hash(&(val as usize)));
 }
-#[test] #[cfg(target_arch = "x86")]
-fn test_hash_usize() {
-    let val = 0xdeadbeef_deadbeef_u64;
-    assert!(hash(&(val as u64)) != hash(&(val as usize)));
-    assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
-}
 
 #[test]
 fn test_hash_idempotent() {
diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs
index 86e59c736ba..f55a1c81463 100644
--- a/src/libcore/tests/mem.rs
+++ b/src/libcore/tests/mem.rs
@@ -121,3 +121,19 @@ fn test_transmute() {
     }
 }
 
+#[test]
+#[allow(dead_code)]
+fn test_discriminant_send_sync() {
+    enum Regular {
+        A,
+        B(i32)
+    }
+    enum NotSendSync {
+        A(*const i32)
+    }
+
+    fn is_send_sync<T: Send + Sync>() { }
+
+    is_send_sync::<Discriminant<Regular>>();
+    is_send_sync::<Discriminant<NotSendSync>>();
+}
diff --git a/src/libcore/tests/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs
index 0bca616ea9a..857aae72c8a 100644
--- a/src/libcore/tests/num/flt2dec/estimator.rs
+++ b/src/libcore/tests/num/flt2dec/estimator.rs
@@ -8,11 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME https://github.com/kripken/emscripten/issues/4563
-// NB we have to actually not compile this test to avoid
-// an undefined symbol error
-#![cfg(not(target_os = "emscripten"))]
-
 use core::num::flt2dec::estimator::*;
 
 #[test]
diff --git a/src/liblibc b/src/liblibc
-Subproject 44e4018e1a37716286ec98cb5b7dd7d33ecaf94
+Subproject 7e33065ce49759958c0d1c04fcadef961032a94
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index e6307f10c13..cf30966fa89 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -488,7 +488,7 @@ impl Literal {
     pub fn string(string: &str) -> Literal {
         let mut escaped = String::new();
         for ch in string.chars() {
-            escaped.extend(ch.escape_unicode());
+            escaped.extend(ch.escape_debug());
         }
         Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None))
     }
diff --git a/src/libprofiler_builtins/Cargo.toml b/src/libprofiler_builtins/Cargo.toml
index eb31f5730d1..04f456917b9 100644
--- a/src/libprofiler_builtins/Cargo.toml
+++ b/src/libprofiler_builtins/Cargo.toml
@@ -15,4 +15,4 @@ doc = false
 core = { path = "../libcore" }
 
 [build-dependencies]
-cc = "1.0"
+cc = "1.0.1"
diff --git a/src/librustc/README.md b/src/librustc/README.md
index 3ac2949b83e..ddf71a06d60 100644
--- a/src/librustc/README.md
+++ b/src/librustc/README.md
@@ -98,7 +98,7 @@ entire program, and each did a particular check of transformation.
 We are gradually replacing this pass-based code with an alternative
 setup based on on-demand **queries**. In the query-model, we work
 backwards, executing a *query* that expresses our ultimate goal (e.g.,
-"compiler this crate"). This query in turn may make other queries
+"compile this crate"). This query in turn may make other queries
 (e.g., "get me a list of all modules in the crate"). Those queries
 make other queries that ultimately bottom out in the base operations,
 like parsing the input, running the type-checker, and so forth. This
@@ -162,7 +162,7 @@ The compiler uses a number of...idiosyncratic abbreviations and
 things. This glossary attempts to list them and give you a few
 pointers for understanding them better.
 
-- AST -- the **abstract syntax tree** produced the `syntax` crate; reflects user syntax
+- AST -- the **abstract syntax tree** produced by the `syntax` crate; reflects user syntax
   very closely. 
 - codegen unit -- when we produce LLVM IR, we group the Rust code into a number of codegen
   units. Each of these units is processed by LLVM independently from one another,
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 36236ff25b0..56b21888985 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -65,7 +65,7 @@ use hir::map::DefPathHash;
 use hir::{HirId, ItemLocalId};
 
 use ich::Fingerprint;
-use ty::{TyCtxt, Instance, InstanceDef, ParamEnvAnd, Ty};
+use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
 use ty::subst::Substs;
 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use ich::StableHashingContext;
@@ -339,6 +339,25 @@ macro_rules! define_dep_nodes {
                     Ok(DepNode::new_no_params(kind))
                 }
             }
+
+            /// Used in testing
+            pub fn has_label_string(label: &str) -> bool {
+                match label {
+                    $(
+                        stringify!($variant) => true,
+                    )*
+                    _ => false,
+                }
+            }
+        }
+
+        /// Contains variant => str representations for constructing
+        /// DepNode groups for tests.
+        #[allow(dead_code, non_upper_case_globals)]
+        pub mod label_strs {
+           $(
+                pub const $variant: &'static str = stringify!($variant);
+            )*
         }
     );
 }
@@ -356,7 +375,7 @@ impl fmt::Debug for DepNode {
         ::ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
                 if let Some(def_id) = self.extract_def_id(tcx) {
-                    write!(f, "{}", tcx.def_path(def_id).to_string(tcx))?;
+                    write!(f, "{}", tcx.def_path_debug_str(def_id))?;
                 } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
                     write!(f, "{}", s)?;
                 } else {
@@ -457,6 +476,7 @@ define_dep_nodes!( <'tcx>
     [] TypeOfItem(DefId),
     [] GenericsOfItem(DefId),
     [] PredicatesOfItem(DefId),
+    [] InferredOutlivesOf(DefId),
     [] SuperPredicatesOfItem(DefId),
     [] TraitDefOfItem(DefId),
     [] AdtDefOfItem(DefId),
@@ -480,12 +500,15 @@ define_dep_nodes!( <'tcx>
     [] InherentImpls(DefId),
     [] TypeckBodiesKrate,
     [] TypeckTables(DefId),
+    [] UsedTraitImports(DefId),
     [] HasTypeckTables(DefId),
     [] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> },
     [] SymbolName(DefId),
     [] InstanceSymbolName { instance: Instance<'tcx> },
     [] SpecializationGraph(DefId),
     [] ObjectSafety(DefId),
+    [] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> },
+    [] VtableMethods { trait_ref: PolyTraitRef<'tcx> },
 
     [] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
     [] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
@@ -532,6 +555,7 @@ define_dep_nodes!( <'tcx>
     [] LookupDeprecationEntry(DefId),
     [] ItemBodyNestedBodies(DefId),
     [] ConstIsRvaluePromotableToStatic(DefId),
+    [] RvaluePromotableMap(DefId),
     [] ImplParent(DefId),
     [] TraitOfItem(DefId),
     [] IsExportedSymbol(DefId),
@@ -588,6 +612,14 @@ define_dep_nodes!( <'tcx>
     [] HasCloneClosures(CrateNum),
     [] HasCopyClosures(CrateNum),
 
+    // This query is not expected to have inputs -- as a result, it's
+    // not a good candidate for "replay" because it's essentially a
+    // pure function of its input (and hence the expectation is that
+    // no caller would be green **apart** from just this
+    // query). Making it anonymous avoids hashing the result, which
+    // may save a bit of time.
+    [anon] EraseRegionsTy { ty: Ty<'tcx> },
+
     [] Freevars(DefId),
     [] MaybeUnusedTraitImport(DefId),
     [] MaybeUnusedExternCrates,
@@ -601,7 +633,7 @@ define_dep_nodes!( <'tcx>
     [] CodegenUnit(InternedString),
     [] CompileCodegenUnit(InternedString),
     [] OutputFilenames,
-
+    [anon] NormalizeTy,
     // We use this for most things when incr. comp. is turned off.
     [] Null,
 );
@@ -700,8 +732,8 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId, De
         let (def_id_0, def_id_1) = *self;
 
         format!("({}, {})",
-                tcx.def_path(def_id_0).to_string(tcx),
-                tcx.def_path(def_id_1).to_string(tcx))
+                tcx.def_path_debug_str(def_id_0),
+                tcx.def_path_debug_str(def_id_1))
     }
 }
 
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index cb4126245af..0fdb6dc068d 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -12,7 +12,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHashingContextProvider};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use session::config::OutputType;
 use std::cell::{Ref, RefCell};
 use std::env;
 use std::hash::Hash;
@@ -577,7 +576,7 @@ impl DepGraph {
                       "DepGraph::try_mark_green() - Duplicate DepNodeColor \
                       insertion for {:?}", dep_node);
 
-        debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node.kind);
+        debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node);
         Some(dep_node_index)
     }
 
@@ -647,7 +646,14 @@ impl DepGraph {
 pub struct WorkProduct {
     pub cgu_name: String,
     /// Saved files associated with this CGU
-    pub saved_files: Vec<(OutputType, String)>,
+    pub saved_files: Vec<(WorkProductFileKind, String)>,
+}
+
+#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
+pub enum WorkProductFileKind {
+    Object,
+    Bytecode,
+    BytecodeCompressed,
 }
 
 pub(super) struct CurrentDepGraph {
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 8d2cf676849..fe0212423f6 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -19,8 +19,9 @@ mod safe;
 mod serialized;
 
 pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
-pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId};
+pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs};
 pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor};
+pub use self::graph::WorkProductFileKind;
 pub use self::prev::PreviousDepGraph;
 pub use self::query::DepGraphQuery;
 pub use self::safe::AssertDepGraphSafe;
diff --git a/src/librustc/hir/README.md b/src/librustc/hir/README.md
index c832a897dee..e283fc40c50 100644
--- a/src/librustc/hir/README.md
+++ b/src/librustc/hir/README.md
@@ -57,7 +57,7 @@ carry around references into the HIR, but rather to carry around
 *identifier numbers* (or just "ids"). Right now, you will find four
 sorts of identifiers in active use:
 
-- `DefId`, which primarily name "definitions" or top-level items.
+- `DefId`, which primarily names "definitions" or top-level items.
   - You can think of a `DefId` as being shorthand for a very explicit
     and complete path, like `std::collections::HashMap`. However,
     these paths are able to name things that are not nameable in
@@ -114,6 +114,6 @@ A **body** represents some kind of executable code, such as the body
 of a function/closure or the definition of a constant. Bodies are
 associated with an **owner**, which is typically some kind of item
 (e.g., a `fn()` or `const`), but could also be a closure expression
-(e.g., `|x, y| x + y`). You can use the HIR map to find find the body
+(e.g., `|x, y| x + y`). You can use the HIR map to find the body
 associated with a given def-id (`maybe_body_owned_by()`) or to find
 the owner of a body (`body_owner_def_id()`).
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 8e48352007b..69d23504cda 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -197,12 +197,12 @@ pub struct DefId {
 
 impl fmt::Debug for DefId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "DefId {{ krate: {:?}, node: {:?}",
+        write!(f, "DefId {{ krate: {:?}, index: {:?}",
                self.krate, self.index)?;
 
         ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
-                write!(f, " => {}", tcx.def_path(*self).to_string(tcx))?;
+                write!(f, " => {}", tcx.def_path_debug_str(*self))?;
             }
             Ok(())
         })?;
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 1755b3bca05..d99d7cd897b 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -780,9 +780,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
         FnKind::ItemFn(_, generics, ..) => {
             visitor.visit_generics(generics);
         }
-        FnKind::Method(_, sig, ..) => {
-            visitor.visit_generics(&sig.generics);
-        }
+        FnKind::Method(..) |
         FnKind::Closure(_) => {}
     }
 }
@@ -802,6 +800,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
     visitor.visit_name(trait_item.span, trait_item.name);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
+    visitor.visit_generics(&trait_item.generics);
     match trait_item.node {
         TraitItemKind::Const(ref ty, default) => {
             visitor.visit_id(trait_item.id);
@@ -810,7 +809,6 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
         }
         TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => {
             visitor.visit_id(trait_item.id);
-            visitor.visit_generics(&sig.generics);
             visitor.visit_fn_decl(&sig.decl);
             for name in names {
                 visitor.visit_name(name.span, name.node);
@@ -852,6 +850,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
         ref vis,
         ref defaultness,
         ref attrs,
+        ref generics,
         ref node,
         span
     } = *impl_item;
@@ -860,6 +859,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
     visitor.visit_vis(vis);
     visitor.visit_defaultness(defaultness);
     walk_list!(visitor, visit_attribute, attrs);
+    visitor.visit_generics(generics);
     match *node {
         ImplItemKind::Const(ref ty, body) => {
             visitor.visit_id(impl_item.id);
diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs
index ce1a34faf5e..2221ecf07b4 100644
--- a/src/librustc/hir/itemlikevisit.rs
+++ b/src/librustc/hir/itemlikevisit.rs
@@ -41,7 +41,7 @@ use super::intravisit::Visitor;
 ///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
 ///      impl into scope while visiting the impl-items, and then back out again.
 ///    - How: Implement `intravisit::Visitor` and override the
-///      `visit_nested_map()` methods to return
+///      `nested_visit_map()` methods to return
 ///      `NestedVisitorMap::All`. Walk your crate with
 ///      `intravisit::walk_crate()` invoked on `tcx.hir.krate()`.
 ///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 1fdfbe20328..184e6646558 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -673,6 +673,7 @@ impl<'a> LoweringContext<'a> {
                     unsafety: self.lower_unsafety(f.unsafety),
                     abi: f.abi,
                     decl: self.lower_fn_decl(&f.decl),
+                    arg_names: self.lower_fn_args_to_names(&f.decl),
                 }))
             }
             TyKind::Never => hir::TyNever,
@@ -704,7 +705,7 @@ impl<'a> LoweringContext<'a> {
                 let expr = self.lower_body(None, |this| this.lower_expr(expr));
                 hir::TyTypeof(expr)
             }
-            TyKind::TraitObject(ref bounds) => {
+            TyKind::TraitObject(ref bounds, ..) => {
                 let mut lifetime_bound = None;
                 let bounds = bounds.iter().filter_map(|bound| {
                     match *bound {
@@ -1538,6 +1539,7 @@ impl<'a> LoweringContext<'a> {
                 hir_id,
                 name: this.lower_ident(i.ident),
                 attrs: this.lower_attrs(&i.attrs),
+                generics: this.lower_generics(&i.generics),
                 node: match i.node {
                     TraitItemKind::Const(ref ty, ref default) => {
                         hir::TraitItemKind::Const(this.lower_ty(ty),
@@ -1602,6 +1604,7 @@ impl<'a> LoweringContext<'a> {
                 hir_id,
                 name: this.lower_ident(i.ident),
                 attrs: this.lower_attrs(&i.attrs),
+                generics: this.lower_generics(&i.generics),
                 vis: this.lower_visibility(&i.vis, None),
                 defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
                 node: match i.node {
@@ -1728,7 +1731,6 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
         hir::MethodSig {
-            generics: self.lower_generics(&sig.generics),
             abi: sig.abi,
             unsafety: self.lower_unsafety(sig.unsafety),
             constness: self.lower_constness(sig.constness),
@@ -2546,7 +2548,7 @@ impl<'a> LoweringContext<'a> {
                 };
 
                 // Err(err) => #[allow(unreachable_code)]
-                //             return Carrier::from_error(From::from(err)),
+                //             return Try::from_error(From::from(err)),
                 let err_arm = {
                     let err_ident = self.str_to_ident("err");
                     let err_local = self.pat_ident(e.span, err_ident);
@@ -2665,7 +2667,7 @@ impl<'a> LoweringContext<'a> {
                         -> hir::Visibility {
         match *v {
             Visibility::Public => hir::Public,
-            Visibility::Crate(_) => hir::Visibility::Crate,
+            Visibility::Crate(..) => hir::Visibility::Crate,
             Visibility::Restricted { ref path, id } => {
                 hir::Visibility::Restricted {
                     path: P(self.lower_path(id, path, ParamMode::Explicit, true)),
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index bd80b613e77..8bc7cf2faba 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -27,7 +27,6 @@ use std::hash::Hash;
 use syntax::ast;
 use syntax::ext::hygiene::Mark;
 use syntax::symbol::{Symbol, InternedString};
-use ty::TyCtxt;
 use util::nodemap::NodeMap;
 
 /// The DefPathTable maps DefIndexes to DefKeys and vice versa.
@@ -296,26 +295,6 @@ impl DefPath {
         DefPath { data: data, krate: krate }
     }
 
-    pub fn to_string(&self, tcx: TyCtxt) -> String {
-        let mut s = String::with_capacity(self.data.len() * 16);
-
-        s.push_str(&tcx.original_crate_name(self.krate).as_str());
-        s.push_str("/");
-        // Don't print the whole crate disambiguator. That's just annoying in
-        // debug output.
-        s.push_str(&tcx.crate_disambiguator(self.krate).as_str()[..7]);
-
-        for component in &self.data {
-            write!(s,
-                   "::{}[{}]",
-                   component.data.as_interned_str(),
-                   component.disambiguator)
-                .unwrap();
-        }
-
-        s
-    }
-
     /// Returns a string representation of the DefPath without
     /// the crate-prefix. This method is useful if you don't have
     /// a TyCtxt available.
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index dcff66dc23b..fb3fc8a2da4 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1295,7 +1295,6 @@ pub struct MethodSig {
     pub constness: Constness,
     pub abi: Abi,
     pub decl: P<FnDecl>,
-    pub generics: Generics,
 }
 
 // The bodies for items are stored "out of line", in a separate
@@ -1316,6 +1315,7 @@ pub struct TraitItem {
     pub name: Name,
     pub hir_id: HirId,
     pub attrs: HirVec<Attribute>,
+    pub generics: Generics,
     pub node: TraitItemKind,
     pub span: Span,
 }
@@ -1360,6 +1360,7 @@ pub struct ImplItem {
     pub vis: Visibility,
     pub defaultness: Defaultness,
     pub attrs: HirVec<Attribute>,
+    pub generics: Generics,
     pub node: ImplItemKind,
     pub span: Span,
 }
@@ -1418,6 +1419,7 @@ pub struct BareFnTy {
     pub abi: Abi,
     pub lifetimes: HirVec<LifetimeDef>,
     pub decl: P<FnDecl>,
+    pub arg_names: HirVec<Spanned<Name>>,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 5daffe667fd..b4614873550 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -399,7 +399,8 @@ impl<'a> State<'a> {
                     },
                     span: syntax_pos::DUMMY_SP,
                 };
-                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?;
+                self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics,
+                                 &f.arg_names[..])?;
             }
             hir::TyPath(ref qpath) => {
                 self.print_qpath(qpath, false)?
@@ -879,6 +880,7 @@ impl<'a> State<'a> {
     pub fn print_method_sig(&mut self,
                             name: ast::Name,
                             m: &hir::MethodSig,
+                            generics: &hir::Generics,
                             vis: &hir::Visibility,
                             arg_names: &[Spanned<ast::Name>],
                             body_id: Option<hir::BodyId>)
@@ -888,7 +890,7 @@ impl<'a> State<'a> {
                       m.constness,
                       m.abi,
                       Some(name),
-                      &m.generics,
+                      generics,
                       vis,
                       arg_names,
                       body_id)
@@ -904,12 +906,14 @@ impl<'a> State<'a> {
                 self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
             }
             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
-                self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
+                self.print_method_sig(ti.name, sig, &ti.generics, &hir::Inherited, arg_names,
+                    None)?;
                 self.s.word(";")?;
             }
             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
                 self.head("")?;
-                self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
+                self.print_method_sig(ti.name, sig, &ti.generics, &hir::Inherited, &[],
+                    Some(body))?;
                 self.nbsp()?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
@@ -937,7 +941,7 @@ impl<'a> State<'a> {
             }
             hir::ImplItemKind::Method(ref sig, body) => {
                 self.head("")?;
-                self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
+                self.print_method_sig(ii.name, sig, &ii.generics, &ii.vis, &[], Some(body))?;
                 self.nbsp()?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
@@ -2140,7 +2144,8 @@ impl<'a> State<'a> {
                        unsafety: hir::Unsafety,
                        decl: &hir::FnDecl,
                        name: Option<ast::Name>,
-                       generics: &hir::Generics)
+                       generics: &hir::Generics,
+                       arg_names: &[Spanned<ast::Name>])
                        -> io::Result<()> {
         self.ibox(indent_unit)?;
         if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
@@ -2163,7 +2168,7 @@ impl<'a> State<'a> {
                       name,
                       &generics,
                       &hir::Inherited,
-                      &[],
+                      arg_names,
                       None)?;
         self.end()
     }
diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs
index 2391b61253a..f3bb3b38566 100644
--- a/src/librustc/ich/fingerprint.rs
+++ b/src/librustc/ich/fingerprint.rs
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 use rustc_data_structures::stable_hasher;
-use std::mem;
-use std::slice;
 
 #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
 pub struct Fingerprint(u64, u64);
@@ -54,16 +52,9 @@ impl ::std::fmt::Display for Fingerprint {
 }
 
 impl stable_hasher::StableHasherResult for Fingerprint {
-    fn finish(mut hasher: stable_hasher::StableHasher<Self>) -> Self {
-        let hash_bytes: &[u8] = hasher.finalize();
-
-        assert!(hash_bytes.len() >= mem::size_of::<u64>() * 2);
-        let hash_bytes: &[u64] = unsafe {
-            slice::from_raw_parts(hash_bytes.as_ptr() as *const u64, 2)
-        };
-
-        // The bytes returned bytes the Blake2B hasher are always little-endian.
-        Fingerprint(u64::from_le(hash_bytes[0]), u64::from_le(hash_bytes[1]))
+    fn finish(hasher: stable_hasher::StableHasher<Self>) -> Self {
+        let (_0, _1) = hasher.finalize();
+        Fingerprint(_0, _1)
     }
 }
 
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 776f85cf5da..994f0bd16b1 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -232,8 +232,7 @@ impl_stable_hash_for!(struct hir::MethodSig {
     unsafety,
     constness,
     abi,
-    decl,
-    generics
+    decl
 });
 
 impl_stable_hash_for!(struct hir::TypeBinding {
@@ -274,7 +273,8 @@ impl_stable_hash_for!(struct hir::BareFnTy {
     unsafety,
     abi,
     lifetimes,
-    decl
+    decl,
+    arg_names
 });
 
 impl_stable_hash_for!(enum hir::Ty_ {
@@ -708,6 +708,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItem {
             hir_id: _,
             name,
             ref attrs,
+            ref generics,
             ref node,
             span
         } = *self;
@@ -715,6 +716,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::TraitItem {
         hcx.hash_hir_item_like(attrs, |hcx| {
             name.hash_stable(hcx, hasher);
             attrs.hash_stable(hcx, hasher);
+            generics.hash_stable(hcx, hasher);
             node.hash_stable(hcx, hasher);
             span.hash_stable(hcx, hasher);
         });
@@ -743,6 +745,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItem {
             ref vis,
             defaultness,
             ref attrs,
+            ref generics,
             ref node,
             span
         } = *self;
@@ -752,6 +755,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::ImplItem {
             vis.hash_stable(hcx, hasher);
             defaultness.hash_stable(hcx, hasher);
             attrs.hash_stable(hcx, hasher);
+            generics.hash_stable(hcx, hasher);
             node.hash_stable(hcx, hasher);
             span.hash_stable(hcx, hasher);
         });
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index fe060aaf426..50f7e4ba176 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -61,6 +61,9 @@ for ty::RegionKind {
                 def_id.hash_stable(hcx, hasher);
                 name.hash_stable(hcx, hasher);
             }
+            ty::ReLateBound(db, ty::BrEnv) => {
+                db.depth.hash_stable(hcx, hasher);
+            }
             ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => {
                 def_id.hash_stable(hcx, hasher);
                 index.hash_stable(hcx, hasher);
@@ -515,7 +518,7 @@ impl_stable_hash_for!(enum ty::cast::CastKind {
     FnPtrAddrCast
 });
 
-impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { idx });
+impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx });
 impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
 
 impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for region::Scope {
@@ -841,3 +844,129 @@ impl_stable_hash_for!(struct ::util::common::ErrorReported {});
 impl_stable_hash_for!(tuple_struct ::middle::reachable::ReachableSet {
     reachable_set
 });
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::Vtable<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use traits::Vtable::*;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match self {
+            &VtableImpl(ref table_impl) => table_impl.hash_stable(hcx, hasher),
+            &VtableDefaultImpl(ref table_def_impl) => table_def_impl.hash_stable(hcx, hasher),
+            &VtableParam(ref table_param) => table_param.hash_stable(hcx, hasher),
+            &VtableObject(ref table_obj) => table_obj.hash_stable(hcx, hasher),
+            &VtableBuiltin(ref table_builtin) => table_builtin.hash_stable(hcx, hasher),
+            &VtableClosure(ref table_closure) => table_closure.hash_stable(hcx, hasher),
+            &VtableFnPointer(ref table_fn_pointer) => table_fn_pointer.hash_stable(hcx, hasher),
+            &VtableGenerator(ref table_generator) => table_generator.hash_stable(hcx, hasher),
+        }
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableImplData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableImplData {
+            impl_def_id,
+            substs,
+            ref nested,
+        } = *self;
+        impl_def_id.hash_stable(hcx, hasher);
+        substs.hash_stable(hcx, hasher);
+        nested.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableDefaultImplData<N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableDefaultImplData {
+            trait_def_id,
+            ref nested,
+        } = *self;
+        trait_def_id.hash_stable(hcx, hasher);
+        nested.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableObjectData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableObjectData {
+            upcast_trait_ref,
+            vtable_base,
+            ref nested,
+        } = *self;
+        upcast_trait_ref.hash_stable(hcx, hasher);
+        vtable_base.hash_stable(hcx, hasher);
+        nested.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableBuiltinData<N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableBuiltinData {
+            ref nested,
+        } = *self;
+        nested.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableClosureData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableClosureData {
+            closure_def_id,
+            substs,
+            ref nested,
+        } = *self;
+        closure_def_id.hash_stable(hcx, hasher);
+        substs.hash_stable(hcx, hasher);
+        nested.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableFnPointerData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableFnPointerData {
+            fn_ty,
+            ref nested,
+        } = *self;
+        fn_ty.hash_stable(hcx, hasher);
+        nested.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx, N> HashStable<StableHashingContext<'gcx>>
+for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContext<'gcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let traits::VtableGeneratorData {
+            closure_def_id,
+            substs,
+            ref nested,
+        } = *self;
+        closure_def_id.hash_stable(hcx, hasher);
+        substs.hash_stable(hcx, hasher);
+        nested.hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 39bcd703574..79eeebfb250 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -480,16 +480,16 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     {
         assert!(!value.needs_subst());
         let value = self.erase_late_bound_regions(value);
-        self.normalize_associated_type(&value)
+        self.fully_normalize_associated_types_in(&value)
     }
 
     /// Fully normalizes any associated types in `value`, using an
     /// empty environment and `Reveal::All` mode (therefore, suitable
     /// only for monomorphized code during trans, basically).
-    pub fn normalize_associated_type<T>(self, value: &T) -> T
+    pub fn fully_normalize_associated_types_in<T>(self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
-        debug!("normalize_associated_type(t={:?})", value);
+        debug!("fully_normalize_associated_types_in(t={:?})", value);
 
         let param_env = ty::ParamEnv::empty(Reveal::All);
         let value = self.erase_regions(value);
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 015dbbb7aff..64fe4626d6e 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -60,7 +60,7 @@
 #![cfg_attr(stage0, feature(const_fn))]
 #![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
 
-#![recursion_limit="256"]
+#![recursion_limit="512"]
 
 extern crate arena;
 #[macro_use] extern crate bitflags;
@@ -106,6 +106,7 @@ pub mod lint;
 
 pub mod middle {
     pub mod allocator;
+    pub mod borrowck;
     pub mod expr_use_visitor;
     pub mod const_val;
     pub mod cstore;
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 5fe75d8ca71..d28963fc726 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -222,6 +222,12 @@ declare_lint! {
     "unnecessary use of an `unsafe` block"
 }
 
+declare_lint! {
+    pub UNUSED_MUT,
+    Warn,
+    "detect mut variables which don't need to be mutable"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -263,7 +269,8 @@ impl LintPass for HardwiredLints {
             PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
             LATE_BOUND_LIFETIME_ARGUMENTS,
             DEPRECATED,
-            UNUSED_UNSAFE
+            UNUSED_UNSAFE,
+            UNUSED_MUT
         )
     }
 }
diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs
new file mode 100644
index 00000000000..c8690422b18
--- /dev/null
+++ b/src/librustc/middle/borrowck.rs
@@ -0,0 +1,31 @@
+// 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 ich::StableHashingContext;
+use hir::HirId;
+use util::nodemap::FxHashSet;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+
+pub struct BorrowCheckResult {
+    pub used_mut_nodes: FxHashSet<HirId>,
+}
+
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for BorrowCheckResult {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let BorrowCheckResult {
+            ref used_mut_nodes,
+        } = *self;
+        used_mut_nodes.hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index e88678dea1d..5c86554f907 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -171,7 +171,7 @@ fn build_local_id_to_index(body: Option<&hir::Body>,
                            -> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
     let mut index = FxHashMap();
 
-    // FIXME (#6298): Would it be better to fold formals from decl
+    // FIXME(#15020) Would it be better to fold formals from decl
     // into cfg itself?  i.e. introduce a fn-based flow-graph in
     // addition to the current block-based flow-graph, rather than
     // have to put traversals like this here?
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index b036b145a96..e62cc2a658a 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -27,10 +27,11 @@ use middle::region;
 use ty::{self, TyCtxt, adjustment};
 
 use hir::{self, PatKind};
-
+use std::rc::Rc;
 use syntax::ast;
 use syntax::ptr::P;
 use syntax_pos::Span;
+use util::nodemap::ItemLocalMap;
 
 ///////////////////////////////////////////////////////////////////////////
 // The Delegate trait
@@ -262,15 +263,30 @@ macro_rules! return_if_err {
 }
 
 impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> {
+    /// Creates the ExprUseVisitor, configuring it with the various options provided:
+    ///
+    /// - `delegate` -- who receives the callbacks
+    /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
+    /// - `region_scope_tree` --- region scope tree for the code being analyzed
+    /// - `tables` --- typeck results for the code being analyzed
+    /// - `rvalue_promotable_map` --- if you care about rvalue promotion, then provide
+    ///   the map here (it can be computed with `tcx.rvalue_promotable_map(def_id)`).
+    ///   `None` means that rvalues will be given more conservative lifetimes.
+    ///
+    /// See also `with_infer`, which is used *during* typeck.
     pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
                tcx: TyCtxt<'a, 'tcx, 'tcx>,
                param_env: ty::ParamEnv<'tcx>,
                region_scope_tree: &'a region::ScopeTree,
-               tables: &'a ty::TypeckTables<'tcx>)
+               tables: &'a ty::TypeckTables<'tcx>,
+               rvalue_promotable_map: Option<Rc<ItemLocalMap<bool>>>)
                -> Self
     {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::new(tcx, region_scope_tree, tables),
+            mc: mc::MemCategorizationContext::new(tcx,
+                                                  region_scope_tree,
+                                                  tables,
+                                                  rvalue_promotable_map),
             delegate,
             param_env,
         }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index c973881c980..e0e30f88316 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -86,6 +86,7 @@ use syntax_pos::Span;
 
 use std::fmt;
 use std::rc::Rc;
+use util::nodemap::ItemLocalMap;
 
 #[derive(Clone, PartialEq)]
 pub enum Categorization<'tcx> {
@@ -285,6 +286,7 @@ pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
     pub region_scope_tree: &'a region::ScopeTree,
     pub tables: &'a ty::TypeckTables<'tcx>,
+    rvalue_promotable_map: Option<Rc<ItemLocalMap<bool>>>,
     infcx: Option<&'a InferCtxt<'a, 'gcx, 'tcx>>,
 }
 
@@ -392,21 +394,46 @@ impl MutabilityCategory {
 impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                region_scope_tree: &'a region::ScopeTree,
-               tables: &'a ty::TypeckTables<'tcx>)
+               tables: &'a ty::TypeckTables<'tcx>,
+               rvalue_promotable_map: Option<Rc<ItemLocalMap<bool>>>)
                -> MemCategorizationContext<'a, 'tcx, 'tcx> {
-        MemCategorizationContext { tcx, region_scope_tree, tables, infcx: None }
+        MemCategorizationContext {
+            tcx,
+            region_scope_tree,
+            tables,
+            rvalue_promotable_map,
+            infcx: None
+        }
     }
 }
 
 impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
+    /// Creates a `MemCategorizationContext` during type inference.
+    /// This is used during upvar analysis and a few other places.
+    /// Because the typeck tables are not yet complete, the results
+    /// from the analysis must be used with caution:
+    ///
+    /// - rvalue promotions are not known, so the lifetimes of
+    ///   temporaries may be overly conservative;
+    /// - similarly, as the results of upvar analysis are not yet
+    ///   known, the results around upvar accesses may be incorrect.
     pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
                       region_scope_tree: &'a region::ScopeTree,
                       tables: &'a ty::TypeckTables<'tcx>)
                       -> MemCategorizationContext<'a, 'gcx, 'tcx> {
+        let tcx = infcx.tcx;
+
+        // Subtle: we can't do rvalue promotion analysis until the
+        // typeck phase is complete, which means that you can't trust
+        // the rvalue lifetimes that result, but that's ok, since we
+        // don't need to know those during type inference.
+        let rvalue_promotable_map = None;
+
         MemCategorizationContext {
-            tcx: infcx.tcx,
+            tcx,
             region_scope_tree,
             tables,
+            rvalue_promotable_map,
             infcx: Some(infcx),
         }
     }
@@ -477,10 +504,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
     fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
         let base_ty = self.node_ty(pat.hir_id)?;
-        // FIXME (Issue #18207): This code detects whether we are
-        // looking at a `ref x`, and if so, figures out what the type
-        // *being borrowed* is.  But ideally we would put in a more
-        // fundamental fix to this conflated use of the node id.
+        // This code detects whether we are looking at a `ref x`,
+        // and if so, figures out what the type *being borrowed* is.
         let ret_ty = match pat.node {
             PatKind::Binding(..) => {
                 let bm = *self.tables
@@ -871,8 +896,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                            span: Span,
                            expr_ty: Ty<'tcx>)
                            -> cmt<'tcx> {
-        let promotable = self.tcx.rvalue_promotable_to_static.borrow().get(&id).cloned()
-                                   .unwrap_or(false);
+        let hir_id = self.tcx.hir.node_to_hir_id(id);
+        let promotable = self.rvalue_promotable_map.as_ref().map(|m| m[&hir_id.local_id])
+                                                            .unwrap_or(false);
 
         // Always promote `[T; 0]` (even when e.g. borrowed mutably).
         let promotable = match expr_ty.sty {
@@ -887,7 +913,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         let re = if promotable {
             self.tcx.types.re_static
         } else {
-            self.temporary_scope(self.tcx.hir.node_to_hir_id(id).local_id)
+            self.temporary_scope(hir_id.local_id)
         };
         let ret = self.cat_rvalue(id, span, re, expr_ty);
         debug!("cat_rvalue_node ret {:?}", ret);
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 55d0c6b4c66..2037bc01a5b 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -58,11 +58,10 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
 }
 
 fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     sig: &hir::MethodSig,
                                      impl_item: &hir::ImplItem,
                                      impl_src: DefId) -> bool {
     if attr::requests_inline(&impl_item.attrs) ||
-        generics_require_inlining(&sig.generics) {
+        generics_require_inlining(&impl_item.generics) {
         return true
     }
     if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) {
@@ -176,8 +175,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             Some(hir_map::NodeImplItem(impl_item)) => {
                 match impl_item.node {
                     hir::ImplItemKind::Const(..) => true,
-                    hir::ImplItemKind::Method(ref sig, _) => {
-                        if generics_require_inlining(&sig.generics) ||
+                    hir::ImplItemKind::Method(..) => {
+                        if generics_require_inlining(&impl_item.generics) ||
                                 attr::requests_inline(&impl_item.attrs) {
                             true
                         } else {
@@ -293,9 +292,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ImplItemKind::Const(_, body) => {
                         self.visit_nested_body(body);
                     }
-                    hir::ImplItemKind::Method(ref sig, body) => {
+                    hir::ImplItemKind::Method(_, body) => {
                         let did = self.tcx.hir.get_parent_did(search_item);
-                        if method_might_be_inlined(self.tcx, sig, impl_item, did) {
+                        if method_might_be_inlined(self.tcx, impl_item, did) {
                             self.visit_nested_body(body)
                         }
                     }
@@ -336,6 +335,12 @@ struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
+        // Anything which has custom linkage gets thrown on the worklist no
+        // matter where it is in the crate.
+        if attr::contains_name(&item.attrs, "linkage") {
+            self.worklist.push(item.id);
+        }
+
         // We need only trait impls here, not inherent impls, and only non-exported ones
         if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node {
             if !self.access_levels.is_reachable(item.id) {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index b909ee9f93b..fa4ee7c0092 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -156,26 +156,11 @@ pub struct BlockRemainder {
     pub first_statement_index: FirstStatementIndex,
 }
 
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
-         RustcDecodable, Copy)]
-pub struct FirstStatementIndex { pub idx: u32 }
-
-impl Idx for FirstStatementIndex {
-    fn new(idx: usize) -> Self {
-        assert!(idx <= SCOPE_DATA_REMAINDER_MAX as usize);
-        FirstStatementIndex { idx: idx as u32 }
-    }
-
-    fn index(self) -> usize {
-        self.idx as usize
-    }
-}
-
-impl fmt::Debug for FirstStatementIndex {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.index(), formatter)
-    }
-}
+newtype_index!(FirstStatementIndex
+    {
+        DEBUG_NAME = "",
+        MAX = SCOPE_DATA_REMAINDER_MAX,
+    });
 
 impl From<ScopeData> for Scope {
     #[inline]
@@ -208,7 +193,7 @@ impl Scope {
             SCOPE_DATA_DESTRUCTION => ScopeData::Destruction(self.id),
             idx => ScopeData::Remainder(BlockRemainder {
                 block: self.id,
-                first_statement_index: FirstStatementIndex { idx }
+                first_statement_index: FirstStatementIndex::new(idx as usize)
             })
         }
     }
@@ -960,7 +945,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
 
             hir::ExprAssignOp(..) | hir::ExprIndex(..) |
             hir::ExprUnary(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) => {
-                // FIXME(#6268) Nested method calls
+                // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
                 //
                 // The lifetimes for a call or method call look as follows:
                 //
@@ -1081,8 +1066,6 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
     // Here, the expression `[...]` has an extended lifetime due to rule
     // A, but the inner rvalues `a()` and `b()` have an extended lifetime
     // due to rule C.
-    //
-    // FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
 
     if let Some(expr) = init {
         record_rvalue_scope_if_borrow_expr(visitor, &expr, blk_scope);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d0c5460fa97..dc912f1c1b6 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -412,7 +412,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node {
             self.visit_early_late(
                 Some(self.hir_map.get_parent(trait_item.id)),
-                &sig.decl, &sig.generics,
+                &sig.decl, &trait_item.generics,
                 |this| intravisit::walk_trait_item(this, trait_item))
         } else {
             intravisit::walk_trait_item(self, trait_item);
@@ -423,7 +423,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
             self.visit_early_late(
                 Some(self.hir_map.get_parent(impl_item.id)),
-                &sig.decl, &sig.generics,
+                &sig.decl, &impl_item.generics,
                 |this| intravisit::walk_impl_item(this, impl_item))
         } else {
             intravisit::walk_impl_item(self, impl_item);
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 89049958309..4e4fc8b3118 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -429,7 +429,7 @@ impl<'a, 'tcx> Index<'tcx> {
             // while maintaining the invariant that all sysroot crates are unstable
             // by default and are unable to be used.
             if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
-                let reason = "this crate is being loaded from the sysroot, and \
+                let reason = "this crate is being loaded from the sysroot, an \
                               unstable location; did you mean to load this crate \
                               from crates.io via `Cargo.toml` instead?";
                 let stability = tcx.intern_stability(Stability {
diff --git a/src/librustc/mir/README.md b/src/librustc/mir/README.md
index e8ed8bf104c..fb0c7ce1df2 100644
--- a/src/librustc/mir/README.md
+++ b/src/librustc/mir/README.md
@@ -6,7 +6,7 @@ register and define new MIR transformations and analyses.
 
 Most of the code that operates on MIR can be found in the
 `librustc_mir` crate or other crates. The code found here in
-`librustc` is just the datatype definitions, alonging the functions
+`librustc` is just the datatype definitions, along with the functions
 which operate on MIR to be placed everywhere else.
 
 ## MIR Data Types and visitor
@@ -27,7 +27,7 @@ As a MIR *consumer*, you are expected to use one of the queries that
 returns a "final MIR". As of the time of this writing, there is only
 one: `optimized_mir(def_id)`, but more are expected to come in the
 future. For foreign def-ids, we simply read the MIR from the other
-crate's metadata. But for local query, this query will construct the
+crate's metadata. But for local def-ids, the query will construct the
 MIR and then iteratively optimize it by putting it through various
 pipeline stages. This section describes those pipeline stages and how
 you can extend them.
@@ -51,7 +51,7 @@ a `&'tcx Steal<Mir<'tcx>>`, allocated using
 **stolen** by the next suite of optimizations -- this is an
 optimization to avoid cloning the MIR. Attempting to use a stolen
 result will cause a panic in the compiler. Therefore, it is important
-that you not read directly from these intermediate queries except as
+that you do not read directly from these intermediate queries except as
 part of the MIR processing pipeline.
 
 Because of this stealing mechanism, some care must also be taken to
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index b909269e153..0159a198bc6 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -260,6 +260,19 @@ impl<'tcx> Mir<'tcx> {
         debug_assert!(location.statement_index < block.statements.len());
         block.statements[location.statement_index].make_nop()
     }
+
+    /// Returns the source info associated with `location`.
+    pub fn source_info(&self, location: Location) -> &SourceInfo {
+        let block = &self[location.block];
+        let stmts = &block.statements;
+        let idx = location.statement_index;
+        if location.statement_index < stmts.len() {
+            &stmts[idx].source_info
+        } else {
+            assert!(location.statement_index == stmts.len());
+            &block.terminator().source_info
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -402,9 +415,11 @@ pub enum BorrowKind {
 ///////////////////////////////////////////////////////////////////////////
 // Variables and temps
 
-newtype_index!(Local, "_");
-
-pub const RETURN_POINTER: Local = Local(0);
+newtype_index!(Local
+    {
+        DEBUG_NAME = "_",
+        const RETURN_POINTER = 0,
+    });
 
 /// Classifies locals into categories. See `Mir::local_kind`.
 #[derive(PartialEq, Eq, Debug)]
@@ -538,7 +553,7 @@ pub struct UpvarDecl {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlock
 
-newtype_index!(BasicBlock, "bb");
+newtype_index!(BasicBlock { DEBUG_NAME = "bb" });
 
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlockData and Terminator
@@ -1118,7 +1133,7 @@ pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx>
 /// and the index is a local.
 pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;
 
-newtype_index!(Field, "field");
+newtype_index!(Field { DEBUG_NAME = "field" });
 
 impl<'tcx> Lvalue<'tcx> {
     pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
@@ -1183,8 +1198,11 @@ impl<'tcx> Debug for Lvalue<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Scopes
 
-newtype_index!(VisibilityScope, "scope");
-pub const ARGUMENT_VISIBILITY_SCOPE : VisibilityScope = VisibilityScope(0);
+newtype_index!(VisibilityScope
+    {
+        DEBUG_NAME = "scope",
+        const ARGUMENT_VISIBILITY_SCOPE = 0,
+    });
 
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct VisibilityScopeData {
@@ -1509,7 +1527,7 @@ pub struct Constant<'tcx> {
     pub literal: Literal<'tcx>,
 }
 
-newtype_index!(Promoted, "promoted");
+newtype_index!(Promoted { DEBUG_NAME = "promoted" });
 
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 7c1d457a6ee..f9a4b5bb9a5 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -352,7 +352,7 @@ top_level_options!(
         actually_rustdoc: bool [TRACKED],
 
         // Number of object files/codegen units to produce on the backend
-        codegen_units: usize [UNTRACKED],
+        cli_forced_codegen_units: Option<usize> [UNTRACKED],
     }
 );
 
@@ -409,9 +409,7 @@ impl_stable_hash_for!(struct self::OutputFilenames {
     outputs
 });
 
-/// Codegen unit names generated by the numbered naming scheme will contain this
-/// marker right before the index of the codegen unit.
-pub const NUMBERED_CODEGEN_UNIT_MARKER: &'static str = ".cgu-";
+pub const RUST_CGU_EXT: &str = "rust-cgu";
 
 impl OutputFilenames {
     pub fn path(&self, flavor: OutputType) -> PathBuf {
@@ -442,22 +440,14 @@ impl OutputFilenames {
         let mut extension = String::new();
 
         if let Some(codegen_unit_name) = codegen_unit_name {
-            if codegen_unit_name.contains(NUMBERED_CODEGEN_UNIT_MARKER) {
-                // If we use the numbered naming scheme for modules, we don't want
-                // the files to look like <crate-name><extra>.<crate-name>.<index>.<ext>
-                // but simply <crate-name><extra>.<index>.<ext>
-                let marker_offset = codegen_unit_name.rfind(NUMBERED_CODEGEN_UNIT_MARKER)
-                                                     .unwrap();
-                let index_offset = marker_offset + NUMBERED_CODEGEN_UNIT_MARKER.len();
-                extension.push_str(&codegen_unit_name[index_offset .. ]);
-            } else {
-                extension.push_str(codegen_unit_name);
-            };
+            extension.push_str(codegen_unit_name);
         }
 
         if !ext.is_empty() {
             if !extension.is_empty() {
                 extension.push_str(".");
+                extension.push_str(RUST_CGU_EXT);
+                extension.push_str(".");
             }
 
             extension.push_str(ext);
@@ -515,7 +505,7 @@ pub fn basic_options() -> Options {
         unstable_features: UnstableFeatures::Disallow,
         debug_assertions: true,
         actually_rustdoc: false,
-        codegen_units: 1,
+        cli_forced_codegen_units: None,
     }
 }
 
@@ -874,7 +864,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
          build_codegen_options, "C", "codegen",
          CG_OPTIONS, cg_type_desc, cgsetters,
     ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "tool to assemble archives with"),
+        "this option is deprecated and does nothing"),
     linker: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "system linker to link outputs with"),
     link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
@@ -1060,6 +1050,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "print the result of the translation item collection pass"),
     mir_opt_level: usize = (1, parse_uint, [TRACKED],
           "set the MIR optimization level (0-3, default: 1)"),
+    mutable_noalias: bool = (false, parse_bool, [UNTRACKED],
+          "emit noalias metadata for mutable references"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
           "dump MIR state at various points in translation"),
     dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
@@ -1105,6 +1097,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
                  "run the non-lexical lifetimes MIR pass"),
     trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
         "generate a graphical HTML report of time spent in trans and LLVM"),
+    thinlto: bool = (false, parse_bool, [TRACKED],
+        "enable ThinLTO when possible"),
+    inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "control whether #[inline] functions are in all cgus"),
 }
 
 pub fn default_lib_output() -> CrateType {
@@ -1714,34 +1710,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
 
     let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
 
-    let codegen_units = codegen_units.unwrap_or_else(|| {
-        match opt_level {
-            // If we're compiling at `-O0` then default to 32 codegen units.
-            // The number here shouldn't matter too too much as debug mode
-            // builds don't rely on performance at all, meaning that lost
-            // opportunities for inlining through multiple codegen units is
-            // a non-issue.
-            //
-            // Note that the high number here doesn't mean that we'll be
-            // spawning a large number of threads in parallel. The backend
-            // of rustc contains global rate limiting through the
-            // `jobserver` crate so we'll never overload the system with too
-            // much work, but rather we'll only be optimizing when we're
-            // otherwise cooperating with other instances of rustc.
-            //
-            // Rather the high number here means that we should be able to
-            // keep a lot of idle cpus busy. By ensuring that no codegen
-            // unit takes *too* long to build we'll be guaranteed that all
-            // cpus will finish pretty closely to one another and we should
-            // make relatively optimal use of system resources
-            OptLevel::No => 32,
-
-            // All other optimization levels default use one codegen unit,
-            // the historical default in Rust for a Long Time.
-            _ => 1,
-        }
-    });
-
     (Options {
         crate_types,
         optimize: opt_level,
@@ -1766,7 +1734,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
         unstable_features: UnstableFeatures::from_environment(),
         debug_assertions,
         actually_rustdoc: false,
-        codegen_units,
+        cli_forced_codegen_units: codegen_units,
     },
     cfg)
 }
diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs
index 1004b282602..b636fc6c995 100644
--- a/src/librustc/session/filesearch.rs
+++ b/src/librustc/session/filesearch.rs
@@ -28,8 +28,6 @@ pub enum FileMatch {
 }
 
 // A module for searching for libraries
-// FIXME (#2658): I'm not happy how this module turned out. Should
-// probably just be folded into cstore.
 
 pub struct FileSearch<'a> {
     pub sysroot: &'a Path,
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index bd6e5eb67c8..2634ab10007 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -54,24 +54,24 @@ pub mod config;
 pub mod filesearch;
 pub mod search_paths;
 
-// Represents the data associated with a compilation
-// session for a single crate.
+/// Represents the data associated with a compilation
+/// session for a single crate.
 pub struct Session {
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
     pub parse_sess: ParseSess,
-    // For a library crate, this is always none
+    /// For a library crate, this is always none
     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
     pub entry_type: Cell<Option<config::EntryFnType>>,
     pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
     pub derive_registrar_fn: Cell<Option<ast::NodeId>>,
     pub default_sysroot: Option<PathBuf>,
-    // The name of the root source file of the crate, in the local file system.
-    // `None` means that there is no source file.
+    /// The name of the root source file of the crate, in the local file system.
+    /// `None` means that there is no source file.
     pub local_crate_source_file: Option<String>,
-    // The directory the compiler has been executed in plus a flag indicating
-    // if the value stored here has been affected by path remapping.
+    /// The directory the compiler has been executed in plus a flag indicating
+    /// if the value stored here has been affected by path remapping.
     pub working_dir: (String, bool),
     pub lint_store: RefCell<lint::LintStore>,
     pub buffered_lints: RefCell<Option<lint::LintBuffer>>,
@@ -83,11 +83,11 @@ pub struct Session {
     pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
     pub crate_types: RefCell<Vec<config::CrateType>>,
     pub dependency_formats: RefCell<dependency_format::Dependencies>,
-    // The crate_disambiguator is constructed out of all the `-C metadata`
-    // arguments passed to the compiler. Its value together with the crate-name
-    // forms a unique global identifier for the crate. It is used to allow
-    // multiple crates with the same name to coexist. See the
-    // trans::back::symbol_names module for more information.
+    /// The crate_disambiguator is constructed out of all the `-C metadata`
+    /// arguments passed to the compiler. Its value together with the crate-name
+    /// forms a unique global identifier for the crate. It is used to allow
+    /// multiple crates with the same name to coexist. See the
+    /// trans::back::symbol_names module for more information.
     pub crate_disambiguator: RefCell<Option<Symbol>>,
     pub features: RefCell<feature_gate::Features>,
 
@@ -143,17 +143,17 @@ pub struct Session {
 }
 
 pub struct PerfStats {
-    // The accumulated time needed for computing the SVH of the crate
+    /// The accumulated time needed for computing the SVH of the crate
     pub svh_time: Cell<Duration>,
-    // The accumulated time spent on computing incr. comp. hashes
+    /// The accumulated time spent on computing incr. comp. hashes
     pub incr_comp_hashes_time: Cell<Duration>,
-    // The number of incr. comp. hash computations performed
+    /// The number of incr. comp. hash computations performed
     pub incr_comp_hashes_count: Cell<u64>,
-    // The number of bytes hashed when computing ICH values
+    /// The number of bytes hashed when computing ICH values
     pub incr_comp_bytes_hashed: Cell<u64>,
-    // The accumulated time spent on computing symbol hashes
+    /// The accumulated time spent on computing symbol hashes
     pub symbol_hash_time: Cell<Duration>,
-    // The accumulated time spent decoding def path tables from metadata
+    /// The accumulated time spent decoding def path tables from metadata
     pub decode_def_path_tables_time: Cell<Duration>,
 }
 
@@ -636,6 +636,43 @@ impl Session {
         }
         ret
     }
+
+    /// Returns the number of codegen units that should be used for this
+    /// compilation
+    pub fn codegen_units(&self) -> usize {
+        if let Some(n) = self.opts.cli_forced_codegen_units {
+            return n
+        }
+        if let Some(n) = self.target.target.options.default_codegen_units {
+            return n as usize
+        }
+
+        match self.opts.optimize {
+            // If we're compiling at `-O0` then default to 16 codegen units.
+            // The number here shouldn't matter too too much as debug mode
+            // builds don't rely on performance at all, meaning that lost
+            // opportunities for inlining through multiple codegen units is
+            // a non-issue.
+            //
+            // Note that the high number here doesn't mean that we'll be
+            // spawning a large number of threads in parallel. The backend
+            // of rustc contains global rate limiting through the
+            // `jobserver` crate so we'll never overload the system with too
+            // much work, but rather we'll only be optimizing when we're
+            // otherwise cooperating with other instances of rustc.
+            //
+            // Rather the high number here means that we should be able to
+            // keep a lot of idle cpus busy. By ensuring that no codegen
+            // unit takes *too* long to build we'll be guaranteed that all
+            // cpus will finish pretty closely to one another and we should
+            // make relatively optimal use of system resources
+            config::OptLevel::No => 16,
+
+            // All other optimization levels default use one codegen unit,
+            // the historical default in Rust for a Long Time.
+            _ => 1,
+        }
+    }
 }
 
 pub fn build_session(sopts: config::Options,
@@ -804,24 +841,24 @@ pub fn build_session_(sopts: config::Options,
 /// Holds data on the current incremental compilation session, if there is one.
 #[derive(Debug)]
 pub enum IncrCompSession {
-    // This is the state the session will be in until the incr. comp. dir is
-    // needed.
+    /// This is the state the session will be in until the incr. comp. dir is
+    /// needed.
     NotInitialized,
-    // This is the state during which the session directory is private and can
-    // be modified.
+    /// This is the state during which the session directory is private and can
+    /// be modified.
     Active {
         session_directory: PathBuf,
         lock_file: flock::Lock,
         load_dep_graph: bool,
     },
-    // This is the state after the session directory has been finalized. In this
-    // state, the contents of the directory must not be modified any more.
+    /// This is the state after the session directory has been finalized. In this
+    /// state, the contents of the directory must not be modified any more.
     Finalized {
         session_directory: PathBuf,
     },
-    // This is an error state that is reached when some compilation error has
-    // occurred. It indicates that the contents of the session directory must
-    // not be used, since they might be invalid.
+    /// This is an error state that is reached when some compilation error has
+    /// occurred. It indicates that the contents of the session directory must
+    /// not be used, since they might be invalid.
     InvalidBecauseOfErrors {
         session_directory: PathBuf,
     }
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index f3682f8d35d..dc5ce735324 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -252,7 +252,6 @@ fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, infer_is_local: InferIsLocal)
 
 fn is_type_parameter(ty: Ty) -> bool {
     match ty.sty {
-        // FIXME(#20590) straighten story about projection types
         ty::TyProjection(..) | ty::TyParam(..) => true,
         _ => false,
     }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index c7c8141f4f7..030b7e4f646 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -711,41 +711,105 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, _) => {
+            OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
+                let found_trait_ref = self.resolve_type_vars_if_possible(&*found_trait_ref);
                 let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref);
-                let actual_trait_ref = self.resolve_type_vars_if_possible(&*actual_trait_ref);
-                if actual_trait_ref.self_ty().references_error() {
+                if expected_trait_ref.self_ty().references_error() {
                     return;
                 }
-                let expected_trait_ty = expected_trait_ref.self_ty();
-                let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| {
+                let found_trait_ty = found_trait_ref.self_ty();
+
+                let found_did = found_trait_ty.ty_to_def_id();
+                let found_span = found_did.and_then(|did| {
                     self.tcx.hir.span_if_local(did)
                 });
 
-                let self_ty_count =
-                    match expected_trait_ref.skip_binder().substs.type_at(1).sty {
+                let found_ty_count =
+                    match found_trait_ref.skip_binder().substs.type_at(1).sty {
                         ty::TyTuple(ref tys, _) => tys.len(),
                         _ => 1,
                     };
-                let arg_ty_count =
-                    match actual_trait_ref.skip_binder().substs.type_at(1).sty {
-                        ty::TyTuple(ref tys, _) => tys.len(),
-                        _ => 1,
+                let (expected_tys, expected_ty_count) =
+                    match expected_trait_ref.skip_binder().substs.type_at(1).sty {
+                        ty::TyTuple(ref tys, _) =>
+                            (tys.iter().map(|t| &t.sty).collect(), tys.len()),
+                        ref sty => (vec![sty], 1),
                     };
-                if self_ty_count == arg_ty_count {
+                if found_ty_count == expected_ty_count {
                     self.report_closure_arg_mismatch(span,
                                                      found_span,
-                                                     expected_trait_ref,
-                                                     actual_trait_ref)
+                                                     found_trait_ref,
+                                                     expected_trait_ref)
                 } else {
-                    // Expected `|| { }`, found `|x, y| { }`
-                    // Expected `fn(x) -> ()`, found `|| { }`
+                    let expected_tuple = if expected_ty_count == 1 {
+                        expected_tys.first().and_then(|t| {
+                            if let &&ty::TyTuple(ref tuptys, _) = t {
+                                Some(tuptys.len())
+                            } else {
+                                None
+                            }
+                        })
+                    } else {
+                        None
+                    };
+
+                    // FIXME(#44150): Expand this to "N args expected but a N-tuple found."
+                    // Type of the 1st expected argument is somehow provided as type of a
+                    // found one in that case.
+                    //
+                    // ```
+                    // [1i32, 2, 3].sort_by(|(a, b)| ..)
+                    // //                   ^^^^^^^^
+                    // // expected_trait_ref:  std::ops::FnMut<(&i32, &i32)>
+                    // //    found_trait_ref:  std::ops::FnMut<(&i32,)>
+                    // ```
+
+                    let (closure_span, closure_args) = found_did
+                        .and_then(|did| self.tcx.hir.get_if_local(did))
+                        .and_then(|node| {
+                            if let hir::map::NodeExpr(
+                                &hir::Expr {
+                                    node: hir::ExprClosure(_, ref decl, id, span, _),
+                                    ..
+                                }) = node
+                            {
+                                let ty_snips = decl.inputs.iter()
+                                    .map(|ty| {
+                                        self.tcx.sess.codemap().span_to_snippet(ty.span).ok()
+                                            .and_then(|snip| {
+                                                // filter out dummy spans
+                                                if snip == "," || snip == "|" {
+                                                    None
+                                                } else {
+                                                    Some(snip)
+                                                }
+                                            })
+                                    })
+                                    .collect::<Vec<Option<String>>>();
+
+                                let body = self.tcx.hir.body(id);
+                                let pat_snips = body.arguments.iter()
+                                    .map(|arg|
+                                        self.tcx.sess.codemap().span_to_snippet(arg.pat.span).ok())
+                                    .collect::<Option<Vec<String>>>();
+
+                                Some((span, pat_snips, ty_snips))
+                            } else {
+                                None
+                            }
+                        })
+                        .map(|(span, pat, ty)| (Some(span), Some((pat, ty))))
+                        .unwrap_or((None, None));
+                    let closure_args = closure_args.and_then(|(pat, ty)| Some((pat?, ty)));
+
                     self.report_arg_count_mismatch(
                         span,
-                        found_span,
-                        arg_ty_count,
-                        self_ty_count,
-                        expected_trait_ty.is_closure()
+                        closure_span.or(found_span),
+                        expected_ty_count,
+                        expected_tuple,
+                        found_ty_count,
+                        closure_args,
+                        found_trait_ty.is_closure()
                     )
                 }
             }
@@ -767,32 +831,97 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         err.emit();
     }
 
-    fn report_arg_count_mismatch(&self,
-                                 span: Span,
-                                 found_span: Option<Span>,
-                                 expected: usize,
-                                 found: usize,
-                                 is_closure: bool)
-        -> DiagnosticBuilder<'tcx>
-    {
+    fn report_arg_count_mismatch(
+        &self,
+        span: Span,
+        found_span: Option<Span>,
+        expected: usize,
+        expected_tuple: Option<usize>,
+        found: usize,
+        closure_args: Option<(Vec<String>, Vec<Option<String>>)>,
+        is_closure: bool
+    ) -> DiagnosticBuilder<'tcx> {
+        use std::borrow::Cow;
+
+        let kind = if is_closure { "closure" } else { "function" };
+
+        let args_str = |n, distinct| format!(
+                "{} {}argument{}",
+                n,
+                if distinct && n >= 2 { "distinct " } else { "" },
+                if n == 1 { "" } else { "s" },
+            );
+
+        let expected_str = if let Some(n) = expected_tuple {
+            assert!(expected == 1);
+            if closure_args.as_ref().map(|&(ref pats, _)| pats.len()) == Some(n) {
+                Cow::from("a single tuple as argument")
+            } else {
+                // be verbose when numbers differ
+                Cow::from(format!("a single {}-tuple as argument", n))
+            }
+        } else {
+            Cow::from(args_str(expected, false))
+        };
+
+        let found_str = if expected_tuple.is_some() {
+            args_str(found, true)
+        } else {
+            args_str(found, false)
+        };
+
+
         let mut err = struct_span_err!(self.tcx.sess, span, E0593,
-            "{} takes {} argument{} but {} argument{} {} required",
-            if is_closure { "closure" } else { "function" },
-            found,
-            if found == 1 { "" } else { "s" },
-            expected,
-            if expected == 1 { "" } else { "s" },
-            if expected == 1 { "is" } else { "are" });
-
-        err.span_label(span, format!("expected {} that takes {} argument{}",
-                                      if is_closure { "closure" } else { "function" },
-                                      expected,
-                                      if expected == 1 { "" } else { "s" }));
+            "{} is expected to take {}, but it takes {}",
+            kind,
+            expected_str,
+            found_str,
+        );
+
+        err.span_label(
+            span,
+            format!(
+                "expected {} that takes {}",
+                kind,
+                expected_str,
+            )
+        );
+
         if let Some(span) = found_span {
-            err.span_label(span, format!("takes {} argument{}",
-                                          found,
-                                          if found == 1 { "" } else { "s" }));
+            if let (Some(expected_tuple), Some((pats, tys))) = (expected_tuple, closure_args) {
+                if expected_tuple != found || pats.len() != found {
+                    err.span_label(span, format!("takes {}", found_str));
+                } else {
+                    let sugg = format!(
+                        "|({}){}|",
+                        pats.join(", "),
+
+                        // add type annotations if available
+                        if tys.iter().any(|ty| ty.is_some()) {
+                            Cow::from(format!(
+                                ": ({})",
+                                tys.into_iter().map(|ty| if let Some(ty) = ty {
+                                    ty
+                                } else {
+                                    "_".to_string()
+                                }).collect::<Vec<String>>().join(", ")
+                            ))
+                        } else {
+                            Cow::from("")
+                        },
+                    );
+
+                    err.span_suggestion(
+                        span,
+                        "consider changing the closure to accept a tuple",
+                        sugg
+                    );
+                }
+            } else {
+                err.span_label(span, format!("takes {}", found_str));
+            }
         }
+
         err
     }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a1817f18106..1fddb186417 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -650,53 +650,55 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// Given a trait `trait_ref`, iterates the vtable entries
 /// that come from `trait_ref`, including its supertraits.
 #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
-pub fn get_vtable_methods<'a, 'tcx>(
+fn vtable_methods<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>)
-    -> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
+    -> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>
 {
-    debug!("get_vtable_methods({:?})", trait_ref);
-
-    supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
-        let trait_methods = tcx.associated_items(trait_ref.def_id())
-            .filter(|item| item.kind == ty::AssociatedKind::Method);
-
-        // Now list each method's DefId and Substs (for within its trait).
-        // If the method can never be called from this object, produce None.
-        trait_methods.map(move |trait_method| {
-            debug!("get_vtable_methods: trait_method={:?}", trait_method);
-            let def_id = trait_method.def_id;
-
-            // Some methods cannot be called on an object; skip those.
-            if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
-                debug!("get_vtable_methods: not vtable safe");
-                return None;
-            }
-
-            // the method may have some early-bound lifetimes, add
-            // regions for those
-            let substs = Substs::for_item(tcx, def_id,
-                                          |_, _| tcx.types.re_erased,
-                                          |def, _| trait_ref.substs().type_for_def(def));
-
-            // the trait type may have higher-ranked lifetimes in it;
-            // so erase them if they appear, so that we get the type
-            // at some particular call site
-            let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));
-
-            // It's possible that the method relies on where clauses that
-            // do not hold for this particular set of type parameters.
-            // Note that this method could then never be called, so we
-            // do not want to try and trans it, in that case (see #23435).
-            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-            if !normalize_and_test_predicates(tcx, predicates.predicates) {
-                debug!("get_vtable_methods: predicates do not hold");
-                return None;
-            }
-
-            Some((def_id, substs))
-        })
-    })
+    debug!("vtable_methods({:?})", trait_ref);
+
+    Rc::new(
+        supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+            let trait_methods = tcx.associated_items(trait_ref.def_id())
+                .filter(|item| item.kind == ty::AssociatedKind::Method);
+
+            // Now list each method's DefId and Substs (for within its trait).
+            // If the method can never be called from this object, produce None.
+            trait_methods.map(move |trait_method| {
+                debug!("vtable_methods: trait_method={:?}", trait_method);
+                let def_id = trait_method.def_id;
+
+                // Some methods cannot be called on an object; skip those.
+                if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
+                    debug!("vtable_methods: not vtable safe");
+                    return None;
+                }
+
+                // the method may have some early-bound lifetimes, add
+                // regions for those
+                let substs = Substs::for_item(tcx, def_id,
+                                              |_, _| tcx.types.re_erased,
+                                              |def, _| trait_ref.substs().type_for_def(def));
+
+                // the trait type may have higher-ranked lifetimes in it;
+                // so erase them if they appear, so that we get the type
+                // at some particular call site
+                let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));
+
+                // It's possible that the method relies on where clauses that
+                // do not hold for this particular set of type parameters.
+                // Note that this method could then never be called, so we
+                // do not want to try and trans it, in that case (see #23435).
+                let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+                if !normalize_and_test_predicates(tcx, predicates.predicates) {
+                    debug!("vtable_methods: predicates do not hold");
+                    return None;
+                }
+
+                Some((def_id, substs))
+            })
+        }).collect()
+    )
 }
 
 impl<'tcx,O> Obligation<'tcx,O> {
@@ -835,6 +837,8 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         is_object_safe: object_safety::is_object_safe_provider,
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
+        trans_fulfill_obligation: trans::trans_fulfill_obligation,
+        vtable_methods,
         ..*providers
     };
 }
@@ -844,6 +848,8 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
         is_object_safe: object_safety::is_object_safe_provider,
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
+        trans_fulfill_obligation: trans::trans_fulfill_obligation,
+        vtable_methods,
         ..*providers
     };
 }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 00f0672822f..cec79faff31 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1309,13 +1309,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         };
 
         if obligation.predicate.skip_binder().self_ty().is_ty_var() {
-            // FIXME(#20297): Self is a type variable (e.g. `_: AsRef<str>`).
+            // Self is a type variable (e.g. `_: AsRef<str>`).
             //
             // This is somewhat problematic, as the current scheme can't really
             // handle it turning to be a projection. This does end up as truly
             // ambiguous in most cases anyway.
             //
-            // Until this is fixed, take the fast path out - this also improves
+            // Take the fast path out - this also improves
             // performance by preventing assemble_candidates_from_impls from
             // matching every impl for this trait.
             return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true });
@@ -1383,8 +1383,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     {
         debug!("assemble_candidates_for_projected_tys({:?})", obligation);
 
-        // FIXME(#20297) -- just examining the self-type is very simplistic
-
         // before we go into the whole skolemization thing, just
         // quickly check if the self-type is a projection at all.
         match obligation.predicate.0.trait_ref.self_ty().sty {
@@ -2174,14 +2172,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             ty::TyClosure(def_id, ref substs) => {
-                // FIXME(#27086). We are invariant w/r/t our
-                // func_substs, but we don't see them as
-                // constituent types; this seems RIGHT but also like
-                // something that a normal type couldn't simulate. Is
-                // this just a gap with the way that PhantomData and
-                // OIBIT interact? That is, there is no way to say
-                // "make me invariant with respect to this TYPE, but
-                // do not act as though I can reach it"
                 substs.upvar_tys(def_id, self.tcx()).collect()
             }
 
diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs
index 947e7117c4e..761e7259204 100644
--- a/src/librustc/traits/trans/mod.rs
+++ b/src/librustc/traits/trans/mod.rs
@@ -13,89 +13,79 @@
 // seems likely that they should eventually be merged into more
 // general routines.
 
-use dep_graph::{DepGraph, DepKind, DepTrackingMap, DepTrackingMapConfig};
+use dep_graph::{DepKind, DepTrackingMapConfig};
 use infer::TransNormalize;
-use std::cell::RefCell;
 use std::marker::PhantomData;
-use syntax::ast;
-use syntax_pos::Span;
+use syntax_pos::DUMMY_SP;
 use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable};
 use ty::{self, Ty, TyCtxt};
 use ty::subst::{Subst, Substs};
 use ty::fold::{TypeFoldable, TypeFolder};
-use util::common::MemoizationMap;
 
-impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
-    /// Attempts to resolve an obligation to a vtable.. The result is
-    /// a shallow vtable resolution -- meaning that we do not
-    /// (necessarily) resolve all nested obligations on the impl. Note
-    /// that type check should guarantee to us that all nested
-    /// obligations *could be* resolved if we wanted to.
-    /// Assumes that this is run after the entire crate has been successfully type-checked.
-    pub fn trans_fulfill_obligation(self,
-                                    span: Span,
-                                    param_env: ty::ParamEnv<'tcx>,
-                                    trait_ref: ty::PolyTraitRef<'tcx>)
-                                    -> Vtable<'tcx, ()>
-    {
-        // Remove any references to regions; this helps improve caching.
-        let trait_ref = self.erase_regions(&trait_ref);
-
-        self.trans_trait_caches.trait_cache.memoize((param_env, trait_ref), || {
-            debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
-                   (param_env, trait_ref), trait_ref.def_id());
-
-            // Do the initial selection for the obligation. This yields the
-            // shallow result we are looking for -- that is, what specific impl.
-            self.infer_ctxt().enter(|infcx| {
-                let mut selcx = SelectionContext::new(&infcx);
-
-                let obligation_cause = ObligationCause::misc(span,
-                                                             ast::DUMMY_NODE_ID);
-                let obligation = Obligation::new(obligation_cause,
-                                                 param_env,
-                                                 trait_ref.to_poly_trait_predicate());
-
-                let selection = match selcx.select(&obligation) {
-                    Ok(Some(selection)) => selection,
-                    Ok(None) => {
-                        // Ambiguity can happen when monomorphizing during trans
-                        // expands to some humongo type that never occurred
-                        // statically -- this humongo type can then overflow,
-                        // leading to an ambiguous result. So report this as an
-                        // overflow bug, since I believe this is the only case
-                        // where ambiguity can result.
-                        debug!("Encountered ambiguity selecting `{:?}` during trans, \
-                                presuming due to overflow",
-                               trait_ref);
-                        self.sess.span_fatal(span,
-                                            "reached the recursion limit during monomorphization \
-                                             (selection ambiguity)");
-                    }
-                    Err(e) => {
-                        span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
-                                  e, trait_ref)
-                    }
-                };
-
-                debug!("fulfill_obligation: selection={:?}", selection);
-
-                // Currently, we use a fulfillment context to completely resolve
-                // all nested obligations. This is because they can inform the
-                // inference of the impl's type parameters.
-                let mut fulfill_cx = FulfillmentContext::new();
-                let vtable = selection.map(|predicate| {
-                    debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
-                    fulfill_cx.register_predicate_obligation(&infcx, predicate);
-                });
-                let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
-
-                info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
-                vtable
-            })
-        })
-    }
+/// Attempts to resolve an obligation to a vtable.. The result is
+/// a shallow vtable resolution -- meaning that we do not
+/// (necessarily) resolve all nested obligations on the impl. Note
+/// that type check should guarantee to us that all nested
+/// obligations *could be* resolved if we wanted to.
+/// Assumes that this is run after the entire crate has been successfully type-checked.
+pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>,
+                                          (param_env, trait_ref):
+                                          (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>))
+                                          -> Vtable<'tcx, ()>
+{
+    // Remove any references to regions; this helps improve caching.
+    let trait_ref = ty.erase_regions(&trait_ref);
+
+    debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
+            (param_env, trait_ref), trait_ref.def_id());
+
+    // Do the initial selection for the obligation. This yields the
+    // shallow result we are looking for -- that is, what specific impl.
+    ty.infer_ctxt().enter(|infcx| {
+        let mut selcx = SelectionContext::new(&infcx);
+
+        let obligation_cause = ObligationCause::dummy();
+        let obligation = Obligation::new(obligation_cause,
+                                            param_env,
+                                            trait_ref.to_poly_trait_predicate());
+
+        let selection = match selcx.select(&obligation) {
+            Ok(Some(selection)) => selection,
+            Ok(None) => {
+                // Ambiguity can happen when monomorphizing during trans
+                // expands to some humongo type that never occurred
+                // statically -- this humongo type can then overflow,
+                // leading to an ambiguous result. So report this as an
+                // overflow bug, since I believe this is the only case
+                // where ambiguity can result.
+                bug!("Encountered ambiguity selecting `{:?}` during trans, \
+                        presuming due to overflow",
+                        trait_ref)
+            }
+            Err(e) => {
+                bug!("Encountered error `{:?}` selecting `{:?}` during trans",
+                            e, trait_ref)
+            }
+        };
+
+        debug!("fulfill_obligation: selection={:?}", selection);
+
+        // Currently, we use a fulfillment context to completely resolve
+        // all nested obligations. This is because they can inform the
+        // inference of the impl's type parameters.
+        let mut fulfill_cx = FulfillmentContext::new();
+        let vtable = selection.map(|predicate| {
+            debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
+            fulfill_cx.register_predicate_obligation(&infcx, predicate);
+        });
+        let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable);
+
+        info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
+        vtable
+    })
+}
 
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     /// Monomorphizes a type from the AST by first applying the in-scope
     /// substitutions and then normalizing any associated types.
     pub fn trans_apply_param_substs<T>(self,
@@ -138,26 +128,8 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
         if !ty.has_projections() {
             ty
         } else {
-            self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
-                debug!("AssociatedTypeNormalizer: ty={:?}", ty);
-                self.tcx.normalize_associated_type(&ty)
-            })
-        }
-    }
-}
-
-/// Specializes caches used in trans -- in particular, they assume all
-/// types are fully monomorphized and that free regions can be erased.
-pub struct TransTraitCaches<'tcx> {
-    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
-    project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
-}
-
-impl<'tcx> TransTraitCaches<'tcx> {
-    pub fn new(graph: DepGraph) -> Self {
-        TransTraitCaches {
-            trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())),
-            project_cache: RefCell::new(DepTrackingMap::new(graph)),
+            debug!("AssociatedTypeNormalizer: ty={:?}", ty);
+            self.tcx.fully_normalize_monormophic_ty(ty)
         }
     }
 }
diff --git a/src/librustc/ty/README.md b/src/librustc/ty/README.md
index 4f63912a1e0..3fd956ecfb8 100644
--- a/src/librustc/ty/README.md
+++ b/src/librustc/ty/README.md
@@ -42,7 +42,7 @@ wasteful.
 Often, we wish to write code that explicitly asserts that it is not
 taking place during inference. In that case, there is no "local"
 arena, and all the types that you can access are allocated in the
-global arena.  To express this, the idea is to us the same lifetime
+global arena.  To express this, the idea is to use the same lifetime
 for the `'gcx` and `'tcx` parameters of `TyCtxt`. Just to be a touch
 confusing, we tend to use the name `'tcx` in such contexts. Here is an
 example:
@@ -100,10 +100,10 @@ fn test_type<'tcx>(ty: Ty<'tcx>) {
 
 The `sty` field (the origin of this name is unclear to me; perhaps
 structural type?) is of type `TypeVariants<'tcx>`, which is an enum
-definined all of the different kinds of types in the compiler.
+defining all of the different kinds of types in the compiler.
 
 > NB: inspecting the `sty` field on types during type inference can be
-> risky, as there are may be inference variables and other things to
+> risky, as there may be inference variables and other things to
 > consider, or sometimes types are not yet known that will become
 > known later.).
 
@@ -132,7 +132,7 @@ a safe approximation, so that is what you get back.
 > you are going to be testing for type equality, you probably need to
 > start looking into the inference code to do it right.
 
-You can also find various common types in the tcx itself by accessing
+You can also find various common types in the `tcx` itself by accessing
 `tcx.types.bool`, `tcx.types.char`, etc (see `CommonTypes` for more).
 
 ### Beyond types: Other kinds of arena-allocated data structures
@@ -143,7 +143,7 @@ module. Here are a few examples:
 
 - `Substs`, allocated with `mk_substs` -- this will intern a slice of types, often used to
   specify the values to be substituted for generics (e.g., `HashMap<i32, u32>`
-  would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`.
+  would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`).
 - `TraitRef`, typically passed by value -- a **trait reference**
   consists of a reference to a trait along with its various type
   parameters (including `Self`), like `i32: Display` (here, the def-id
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 15e10f8c5e8..47ca7b11731 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -43,7 +43,6 @@ use ty::RegionKind;
 use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
 use ty::TypeVariants::*;
 use ty::layout::{Layout, TargetDataLayout};
-use ty::inhabitedness::DefIdForest;
 use ty::maps;
 use ty::steal::Steal;
 use ty::BindingMode;
@@ -387,8 +386,10 @@ pub struct TypeckTables<'tcx> {
     cast_kinds: ItemLocalMap<ty::cast::CastKind>,
 
     /// Set of trait imports actually used in the method resolution.
-    /// This is used for warning unused imports.
-    pub used_trait_imports: DefIdSet,
+    /// This is used for warning unused imports. During type
+    /// checking, this `Rc` should not be cloned: it must have a ref-count
+    /// of 1 so that we can insert things into the set mutably.
+    pub used_trait_imports: Rc<DefIdSet>,
 
     /// If any errors occurred while type-checking this body,
     /// this field will be set to `true`.
@@ -418,7 +419,7 @@ impl<'tcx> TypeckTables<'tcx> {
             liberated_fn_sigs: ItemLocalMap(),
             fru_field_types: ItemLocalMap(),
             cast_kinds: ItemLocalMap(),
-            used_trait_imports: DefIdSet(),
+            used_trait_imports: Rc::new(DefIdSet()),
             tainted_by_errors: false,
             free_region_map: FreeRegionMap::new(),
         }
@@ -852,9 +853,6 @@ pub struct GlobalCtxt<'tcx> {
 
     pub sess: &'tcx Session,
 
-
-    pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
-
     pub dep_graph: DepGraph,
 
     /// Common types, pre-interned for your convenience.
@@ -893,16 +891,6 @@ pub struct GlobalCtxt<'tcx> {
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
 
-    // FIXME dep tracking -- should be harmless enough
-    pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
-
-    pub inhabitedness_cache: RefCell<FxHashMap<Ty<'tcx>, DefIdForest>>,
-
-    /// Set of nodes which mark locals as mutable which end up getting used at
-    /// some point. Local variable definitions not in this set can be warned
-    /// about.
-    pub used_mut_nodes: RefCell<NodeSet>,
-
     /// Caches the results of trait selection. This cache is used
     /// for things that do not have to do with the parameters in scope.
     pub selection_cache: traits::SelectionCache<'tcx>,
@@ -912,9 +900,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Merge this with `selection_cache`?
     pub evaluation_cache: traits::EvaluationCache<'tcx>,
 
-    /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
-    pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
-
     /// The definite name of the current crate after taking into account
     /// attributes, commandline parameters, etc.
     pub crate_name: Symbol,
@@ -1151,7 +1136,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         tls::enter_global(GlobalCtxt {
             sess: s,
             cstore,
-            trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
             global_arenas: arenas,
             global_interners: interners,
             dep_graph: dep_graph.clone(),
@@ -1183,12 +1167,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             maps: maps::Maps::new(providers),
             mir_passes,
             rcache: RefCell::new(FxHashMap()),
-            normalized_cache: RefCell::new(FxHashMap()),
-            inhabitedness_cache: RefCell::new(FxHashMap()),
-            used_mut_nodes: RefCell::new(NodeSet()),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
-            rvalue_promotable_to_static: RefCell::new(NodeMap()),
             crate_name: Symbol::intern(crate_name),
             data_layout,
             layout_interner: RefCell::new(FxHashSet()),
@@ -1252,6 +1232,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn def_path_debug_str(self, def_id: DefId) -> String {
+        // We are explicitly not going through queries here in order to get
+        // crate name and disambiguator since this code is called from debug!()
+        // statements within the query system and we'd run into endless
+        // recursion otherwise.
+        let (crate_name, crate_disambiguator) = if def_id.is_local() {
+            (self.crate_name.clone(),
+             self.sess.local_crate_disambiguator())
+        } else {
+            (self.cstore.crate_name_untracked(def_id.krate),
+             self.cstore.crate_disambiguator_untracked(def_id.krate))
+        };
+
+        format!("{}[{}]{}",
+                crate_name,
+                // Don't print the whole crate disambiguator. That's just
+                // annoying in debug output.
+                &(crate_disambiguator.as_str())[..4],
+                self.def_path(def_id).to_string_no_crate())
+    }
+
     pub fn metadata_encoding_version(self) -> Vec<u8> {
         self.cstore.metadata_encoding_version().to_vec()
     }
@@ -2319,4 +2320,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         assert_eq!(cnum, LOCAL_CRATE);
         tcx.sess.features.borrow().clone_closures
     };
+    providers.fully_normalize_monormophic_ty = |tcx, ty| {
+        tcx.fully_normalize_associated_types_in(&ty)
+    };
 }
diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs
new file mode 100644
index 00000000000..4f8fca67949
--- /dev/null
+++ b/src/librustc/ty/erase_regions.rs
@@ -0,0 +1,79 @@
+// 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 ty::{self, Ty, TyCtxt};
+use ty::fold::{TypeFolder, TypeFoldable};
+
+pub(super) fn provide(providers: &mut ty::maps::Providers) {
+    *providers = ty::maps::Providers {
+        erase_regions_ty,
+        ..*providers
+    };
+}
+
+fn erase_regions_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+    // NB: use `super_fold_with` here. If we used `fold_with`, it
+    // could invoke the `erase_regions_ty` query recursively.
+    ty.super_fold_with(&mut RegionEraserVisitor { tcx })
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    /// Returns an equivalent value with all free regions removed (note
+    /// that late-bound regions remain, because they are important for
+    /// subtyping, but they are anonymized and normalized as well)..
+    pub fn erase_regions<T>(self, value: &T) -> T
+        where T : TypeFoldable<'tcx>
+    {
+        let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
+        debug!("erase_regions({:?}) = {:?}", value, value1);
+        value1
+    }
+}
+
+struct RegionEraserVisitor<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let Some(ty_lifted) = self.tcx.lift_to_global(&ty) {
+            self.tcx.erase_regions_ty(ty_lifted)
+        } else {
+            ty.super_fold_with(self)
+        }
+    }
+
+    fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+        where T : TypeFoldable<'tcx>
+    {
+        let u = self.tcx.anonymize_late_bound_regions(t);
+        u.super_fold_with(self)
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        // because late-bound regions affect subtyping, we can't
+        // erase the bound/free distinction, but we can replace
+        // all free regions with 'erased.
+        //
+        // Note that we *CAN* replace early-bound regions -- the
+        // type system never "sees" those, they get substituted
+        // away. In trans, they will always be erased to 'erased
+        // whenever a substitution occurs.
+        match *r {
+            ty::ReLateBound(..) => r,
+            _ => self.tcx.types.re_erased
+        }
+    }
+}
+
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 543e8f3e2f0..edd4329fa41 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -445,67 +445,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// Region eraser
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    /// Returns an equivalent value with all free regions removed (note
-    /// that late-bound regions remain, because they are important for
-    /// subtyping, but they are anonymized and normalized as well)..
-    pub fn erase_regions<T>(self, value: &T) -> T
-        where T : TypeFoldable<'tcx>
-    {
-        let value1 = value.fold_with(&mut RegionEraser(self));
-        debug!("erase_regions({:?}) = {:?}",
-               value, value1);
-        return value1;
-
-        struct RegionEraser<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(TyCtxt<'a, 'gcx, 'tcx>);
-
-        impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraser<'a, 'gcx, 'tcx> {
-            fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.0 }
-
-            fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-                if let Some(u) = self.tcx().normalized_cache.borrow().get(&ty).cloned() {
-                    return u;
-                }
-
-                // FIXME(eddyb) should local contexts have a cache too?
-                if let Some(ty_lifted) = self.tcx().lift_to_global(&ty) {
-                    let tcx = self.tcx().global_tcx();
-                    let t_norm = ty_lifted.super_fold_with(&mut RegionEraser(tcx));
-                    tcx.normalized_cache.borrow_mut().insert(ty_lifted, t_norm);
-                    t_norm
-                } else {
-                    ty.super_fold_with(self)
-                }
-            }
-
-            fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
-                where T : TypeFoldable<'tcx>
-            {
-                let u = self.tcx().anonymize_late_bound_regions(t);
-                u.super_fold_with(self)
-            }
-
-            fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-                // because late-bound regions affect subtyping, we can't
-                // erase the bound/free distinction, but we can replace
-                // all free regions with 'erased.
-                //
-                // Note that we *CAN* replace early-bound regions -- the
-                // type system never "sees" those, they get substituted
-                // away. In trans, they will always be erased to 'erased
-                // whenever a substitution occurs.
-                match *r {
-                    ty::ReLateBound(..) => r,
-                    _ => self.tcx().types.re_erased
-                }
-            }
-        }
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
 // Region shifter
 //
 // Shifts the De Bruijn indices on all escaping bound regions by a
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index a829814e090..0072512464a 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -10,7 +10,7 @@
 
 use util::nodemap::{FxHashMap, FxHashSet};
 use ty::context::TyCtxt;
-use ty::{AdtDef, VariantDef, FieldDef, TyS};
+use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
 use ty::{DefId, Substs};
 use ty::{AdtKind, Visibility};
 use ty::TypeVariants::*;
@@ -62,13 +62,95 @@ mod def_id_forest;
 // This code should only compile in modules where the uninhabitedness of Foo is
 // visible.
 
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+    /// Checks whether a type is visibly uninhabited from a particular module.
+    /// # Example
+    /// ```rust
+    /// enum Void {}
+    /// mod a {
+    ///     pub mod b {
+    ///         pub struct SecretlyUninhabited {
+    ///             _priv: !,
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// mod c {
+    ///     pub struct AlsoSecretlyUninhabited {
+    ///         _priv: Void,
+    ///     }
+    ///     mod d {
+    ///     }
+    /// }
+    ///
+    /// struct Foo {
+    ///     x: a::b::SecretlyUninhabited,
+    ///     y: c::AlsoSecretlyUninhabited,
+    /// }
+    /// ```
+    /// In this code, the type `Foo` will only be visibly uninhabited inside the
+    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
+    /// contain `Foo`.
+    ///
+    /// # Example
+    /// ```rust
+    /// let foo_result: Result<T, Foo> = ... ;
+    /// let Ok(t) = foo_result;
+    /// ```
+    /// This code should only compile in modules where the uninhabitedness of Foo is
+    /// visible.
+    pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
+        // To check whether this type is uninhabited at all (not just from the
+        // given node) you could check whether the forest is empty.
+        // ```
+        // forest.is_empty()
+        // ```
+        self.ty_inhabitedness_forest(ty).contains(self, module)
+    }
+
+    pub fn is_ty_uninhabited_from_all_modules(self, ty: Ty<'tcx>) -> bool {
+        !self.ty_inhabitedness_forest(ty).is_empty()
+    }
+
+    fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
+        ty.uninhabited_from(&mut FxHashMap(), self)
+    }
+
+    pub fn is_enum_variant_uninhabited_from(self,
+                                            module: DefId,
+                                            variant: &'tcx VariantDef,
+                                            substs: &'tcx Substs<'tcx>)
+                                            -> bool
+    {
+        self.variant_inhabitedness_forest(variant, substs).contains(self, module)
+    }
+
+    pub fn is_variant_uninhabited_from_all_modules(self,
+                                                   variant: &'tcx VariantDef,
+                                                   substs: &'tcx Substs<'tcx>)
+                                                   -> bool
+    {
+        !self.variant_inhabitedness_forest(variant, substs).is_empty()
+    }
+
+    fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: &'tcx Substs<'tcx>)
+                                    -> DefIdForest {
+        // Determine the ADT kind:
+        let adt_def_id = self.adt_def_id_of_variant(variant);
+        let adt_kind = self.adt_def(adt_def_id).adt_kind();
+
+        // Compute inhabitedness forest:
+        variant.uninhabited_from(&mut FxHashMap(), self, substs, adt_kind)
+    }
+}
+
 impl<'a, 'gcx, 'tcx> AdtDef {
     /// Calculate the forest of DefIds from which this adt is visibly uninhabited.
-    pub fn uninhabited_from(
-                &self,
-                visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
-                tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                substs: &'tcx Substs<'tcx>) -> DefIdForest
+    fn uninhabited_from(
+        &self,
+        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        substs: &'tcx Substs<'tcx>) -> DefIdForest
     {
         DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
             v.uninhabited_from(visited, tcx, substs, self.adt_kind())
@@ -78,12 +160,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
 
 impl<'a, 'gcx, 'tcx> VariantDef {
     /// Calculate the forest of DefIds from which this variant is visibly uninhabited.
-    pub fn uninhabited_from(
-                &self,
-                visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
-                tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                substs: &'tcx Substs<'tcx>,
-                adt_kind: AdtKind) -> DefIdForest
+    fn uninhabited_from(
+        &self,
+        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        substs: &'tcx Substs<'tcx>,
+        adt_kind: AdtKind) -> DefIdForest
     {
         match adt_kind {
             AdtKind::Union => {
@@ -107,12 +189,12 @@ impl<'a, 'gcx, 'tcx> VariantDef {
 
 impl<'a, 'gcx, 'tcx> FieldDef {
     /// Calculate the forest of DefIds from which this field is visibly uninhabited.
-    pub fn uninhabited_from(
-                &self,
-                visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
-                tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                substs: &'tcx Substs<'tcx>,
-                is_enum: bool) -> DefIdForest
+    fn uninhabited_from(
+        &self,
+        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        substs: &'tcx Substs<'tcx>,
+        is_enum: bool) -> DefIdForest
     {
         let mut data_uninhabitedness = move || {
             self.ty(tcx, substs).uninhabited_from(visited, tcx)
@@ -138,35 +220,10 @@ impl<'a, 'gcx, 'tcx> FieldDef {
 
 impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     /// Calculate the forest of DefIds from which this type is visibly uninhabited.
-    pub fn uninhabited_from(
-                &self,
-                visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
-                tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
-    {
-        match tcx.lift_to_global(&self) {
-            Some(global_ty) => {
-                {
-                    let cache = tcx.inhabitedness_cache.borrow();
-                    if let Some(forest) = cache.get(&global_ty) {
-                        return forest.clone();
-                    }
-                }
-                let forest = global_ty.uninhabited_from_inner(visited, tcx);
-                let mut cache = tcx.inhabitedness_cache.borrow_mut();
-                cache.insert(global_ty, forest.clone());
-                forest
-            },
-            None => {
-                let forest = self.uninhabited_from_inner(visited, tcx);
-                forest
-            },
-        }
-    }
-
-    fn uninhabited_from_inner(
-                &self,
-                visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
-                tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
+    fn uninhabited_from(
+        &self,
+        visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
     {
         match self.sty {
             TyAdt(def, substs) => {
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 35ab1cec4cf..600b2572f92 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -13,7 +13,6 @@ use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
 use ty::subst::{Kind, Subst};
 use traits;
 use syntax::abi::Abi;
-use syntax::codemap::DUMMY_SP;
 use util::ppaux;
 
 use std::fmt;
@@ -212,7 +211,7 @@ fn resolve_associated_item<'a, 'tcx>(
            def_id, trait_id, rcvr_substs);
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
-    let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, param_env, ty::Binder(trait_ref));
+    let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder(trait_ref)));
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
diff --git a/src/librustc/ty/maps/README.md b/src/librustc/ty/maps/README.md
index 8abc68d431a..8207c18e677 100644
--- a/src/librustc/ty/maps/README.md
+++ b/src/librustc/ty/maps/README.md
@@ -169,7 +169,7 @@ That is, they take an `&mut Providers` and mutate it in place. Usually
 we use the formulation above just because it looks nice, but you could
 as well do `providers.type_of = type_of`, which would be equivalent.
 (Here, `type_of` would be a top-level function, defined as we saw
-before.) So, if we wanted to have add a provider for some other query,
+before.) So, if we want to add a provider for some other query,
 let's call it `fubar`, into the crate above, we might modify the `provide()`
 function like so:
 
@@ -185,7 +185,7 @@ pub fn provide(providers: &mut Providers) {
 fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. }
 ```
 
-NB. Most of the `rustc_*` crate only provide **local
+NB. Most of the `rustc_*` crates only provide **local
 providers**. Almost all **extern providers** wind up going through the
 `rustc_metadata` crate, which loads the information from the crate
 metadata.  But in some cases there are crates that provide queries for
@@ -201,7 +201,7 @@ Well, defining a query takes place in two steps:
 1. first, you have to specify the query name and arguments; and then,
 2. you have to supply query providers where needed.
 
-The specify the query name and arguments, you simply add an entry
+To specify the query name and arguments, you simply add an entry
 to the big macro invocation in `mod.rs`. This will probably have changed
 by the time you read this README, but at present it looks something
 like:
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index c8520c5be2d..deaafd1efed 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -29,7 +29,12 @@ pub(super) trait QueryDescription: QueryConfig {
 
 impl<M: QueryConfig<Key=DefId>> QueryDescription for M {
     default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
-        format!("processing `{}`", tcx.item_path_str(def_id))
+        if !tcx.sess.verbose() {
+            format!("processing `{}`", tcx.item_path_str(def_id))
+        } else {
+            let name = unsafe { ::std::intrinsics::type_name::<M>() };
+            format!("processing `{}` applied to `{:?}`", name, def_id)
+        }
     }
 }
 
@@ -70,6 +75,12 @@ impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::erase_regions_ty<'tcx> {
+    fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
+        format!("erasing regions from `{:?}`", ty)
+    }
+}
+
 impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
     fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
         let id = tcx.hir.as_local_node_id(def_id).unwrap();
@@ -214,6 +225,13 @@ impl<'tcx> QueryDescription for queries::const_is_rvalue_promotable_to_static<'t
     }
 }
 
+impl<'tcx> QueryDescription for queries::rvalue_promotable_map<'tcx> {
+    fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+        format!("checking which parts of `{}` are promotable to static",
+                tcx.item_path_str(def_id))
+    }
+}
+
 impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
     fn describe(tcx: TyCtxt, def_id: DefId) -> String {
         format!("checking if item is mir available: `{}`",
@@ -221,6 +239,12 @@ impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::trans_fulfill_obligation<'tcx> {
+    fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String {
+        format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id()))
+    }
+}
+
 impl<'tcx> QueryDescription for queries::trait_impls_of<'tcx> {
     fn describe(tcx: TyCtxt, def_id: DefId) -> String {
         format!("trait impls of `{}`", tcx.item_path_str(def_id))
@@ -497,8 +521,20 @@ impl<'tcx> QueryDescription for queries::has_clone_closures<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::vtable_methods<'tcx> {
+    fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String {
+        format!("finding all methods for trait {}", tcx.item_path_str(key.def_id()))
+    }
+}
+
 impl<'tcx> QueryDescription for queries::has_copy_closures<'tcx> {
     fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
         format!("seeing if the crate has enabled `Copy` closures")
     }
 }
+
+impl<'tcx> QueryDescription for queries::fully_normalize_monormophic_ty<'tcx> {
+    fn describe(_tcx: TyCtxt, _: Ty) -> String {
+        format!("normalizing types")
+    }
+}
diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs
index e37cf669797..ee4523d6f3e 100644
--- a/src/librustc/ty/maps/keys.rs
+++ b/src/librustc/ty/maps/keys.rs
@@ -134,6 +134,24 @@ impl Key for (MirSuite, MirPassIndex, DefId) {
     }
 }
 
+impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
+    fn map_crate(&self) -> CrateNum {
+        self.1.def_id().krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        tcx.def_span(self.1.def_id())
+    }
+}
+
+impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
+    fn map_crate(&self) -> CrateNum {
+        self.def_id().krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        tcx.def_span(self.def_id())
+    }
+}
+
 impl<'tcx> Key for Ty<'tcx> {
     fn map_crate(&self) -> CrateNum {
         LOCAL_CRATE
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 3dcbeda94bc..851d126056c 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -15,6 +15,7 @@ use hir::def::{Def, Export};
 use hir::{self, TraitCandidate, ItemLocalId};
 use hir::svh::Svh;
 use lint;
+use middle::borrowck::BorrowCheckResult;
 use middle::const_val;
 use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
                      ExternBodyNestedBodies};
@@ -30,12 +31,13 @@ use middle::trans::{CodegenUnit, Stats};
 use mir;
 use session::CompileResult;
 use session::config::OutputFilenames;
+use traits::Vtable;
 use traits::specialization_graph;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use ty::layout::{Layout, LayoutError};
 use ty::steal::Steal;
 use ty::subst::Substs;
-use util::nodemap::{DefIdSet, DefIdMap};
+use util::nodemap::{DefIdSet, DefIdMap, ItemLocalMap};
 use util::common::{profq_msg, ProfileQueriesMsg};
 
 use rustc_data_structures::indexed_set::IdxSetBuf;
@@ -119,6 +121,9 @@ define_maps! { <'tcx>
     /// (inferred) variance.
     [] fn variances_of: ItemVariances(DefId) -> Rc<Vec<ty::Variance>>,
 
+    /// Maps from def-id of a type to its (inferred) outlives.
+    [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Vec<ty::Predicate<'tcx>>,
+
     /// Maps from an impl/trait def-id to a list of the def-ids of its items
     [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
 
@@ -178,11 +183,13 @@ define_maps! { <'tcx>
 
     [] fn typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
 
+    [] fn used_trait_imports: UsedTraitImports(DefId) -> Rc<DefIdSet>,
+
     [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool,
 
     [] fn coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
 
-    [] fn borrowck: BorrowCheck(DefId) -> (),
+    [] fn borrowck: BorrowCheck(DefId) -> Rc<BorrowCheckResult>,
     // FIXME: shouldn't this return a `Result<(), BorrowckErrors>` instead?
     [] fn mir_borrowck: MirBorrowCheck(DefId) -> (),
 
@@ -226,8 +233,13 @@ define_maps! { <'tcx>
     [] fn is_exported_symbol: IsExportedSymbol(DefId) -> bool,
     [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
     [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
+    [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Rc<ItemLocalMap<bool>>,
     [] fn is_mir_available: IsMirAvailable(DefId) -> bool,
+    [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
+                          -> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,
 
+    [] fn trans_fulfill_obligation: fulfill_obligation_dep_node(
+        (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>,
     [] fn trait_impls_of: TraitImpls(DefId) -> Rc<ty::trait_def::TraitImpls>,
     [] fn specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
     [] fn is_object_safe: ObjectSafety(DefId) -> bool,
@@ -334,12 +346,22 @@ define_maps! { <'tcx>
 
     [] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
     [] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
+
+    // Erases regions from `ty` to yield a new type.
+    // Normally you would just use `tcx.erase_regions(&value)`,
+    // however, which uses this query as a kind of cache.
+    [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>,
+    [] fn fully_normalize_monormophic_ty: normalize_ty_node(Ty<'tcx>) -> Ty<'tcx>,
 }
 
 //////////////////////////////////////////////////////////////////////
 // These functions are little shims used to find the dep-node for a
 // given query when there is not a *direct* mapping:
 
+fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
+    DepConstructor::EraseRegionsTy { ty }
+}
+
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
     DepConstructor::TypeParamPredicates {
         item_id,
@@ -347,6 +369,14 @@ fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstr
     }
 }
 
+fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref):
+    (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> {
+    DepConstructor::FulfillObligation {
+        param_env,
+        trait_ref
+    }
+}
+
 fn coherent_trait_dep_node<'tcx>((_, def_id): (CrateNum, DefId)) -> DepConstructor<'tcx> {
     DepConstructor::CoherenceCheckTrait(def_id)
 }
@@ -459,3 +489,10 @@ fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstru
 fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::OutputFilenames
 }
+
+fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> {
+    DepConstructor::VtableMethods{ trait_ref }
+}
+fn normalize_ty_node<'tcx>(_: Ty<'tcx>) -> DepConstructor<'tcx> {
+    DepConstructor::NormalizeTy
+}
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index 88b619558d9..7edad824cdc 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -12,7 +12,7 @@
 //! that generate the actual methods on tcx which find and execute the
 //! provider, manage the caches, and so forth.
 
-use dep_graph::{DepNodeIndex, DepNode, DepKind};
+use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor};
 use errors::{Diagnostic, DiagnosticBuilder};
 use ty::{TyCtxt};
 use ty::maps::Query; // NB: actually generated by the macros in this file
@@ -133,6 +133,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         Ok(result)
     }
+
+    /// Try to read a node index for the node dep_node.
+    /// A node will have an index, when it's already been marked green, or when we can mark it
+    /// green. This function will mark the current task as a reader of the specified node, when
+    /// the a node index can be found for that node.
+    pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option<DepNodeIndex> {
+        match self.dep_graph.node_color(dep_node) {
+            Some(DepNodeColor::Green(dep_node_index)) => {
+                self.dep_graph.read_index(dep_node_index);
+                Some(dep_node_index)
+            }
+            Some(DepNodeColor::Red) => {
+                None
+            }
+            None => {
+                // try_mark_green (called below) will panic when full incremental
+                // compilation is disabled. If that's the case, we can't try to mark nodes
+                // as green anyway, so we can safely return None here.
+                if !self.dep_graph.is_fully_enabled() {
+                    return None;
+                }
+                match self.dep_graph.try_mark_green(self, &dep_node) {
+                    Some(dep_node_index) => {
+                        debug_assert!(self.dep_graph.is_green(dep_node_index));
+                        self.dep_graph.read_index(dep_node_index);
+                        Some(dep_node_index)
+                    }
+                    None => {
+                        None
+                    }
+                }
+            }
+        }
+    }
 }
 
 // If enabled, send a message to the profile-queries thread
@@ -309,25 +343,8 @@ macro_rules! define_maps {
                 }
 
                 if !dep_node.kind.is_input() {
-                    use dep_graph::DepNodeColor;
-                    if let Some(DepNodeColor::Green(dep_node_index)) = tcx.dep_graph
-                                                                          .node_color(&dep_node) {
+                    if let Some(dep_node_index) = tcx.try_mark_green_and_read(&dep_node) {
                         profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
-                        tcx.dep_graph.read_index(dep_node_index);
-                        return Self::load_from_disk_and_cache_in_memory(tcx,
-                                                                        key,
-                                                                        span,
-                                                                        dep_node_index)
-                    }
-
-                    debug!("ty::queries::{}::try_get_with(key={:?}) - running try_mark_green",
-                           stringify!($name),
-                           key);
-
-                    if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, &dep_node) {
-                        debug_assert!(tcx.dep_graph.is_green(dep_node_index));
-                        profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
-                        tcx.dep_graph.read_index(dep_node_index);
                         return Self::load_from_disk_and_cache_in_memory(tcx,
                                                                         key,
                                                                         span,
@@ -344,6 +361,30 @@ macro_rules! define_maps {
                 }
             }
 
+            /// Ensure that either this query has all green inputs or been executed.
+            /// Executing query::ensure(D) is considered a read of the dep-node D.
+            ///
+            /// This function is particularly useful when executing passes for their
+            /// side-effects -- e.g., in order to report errors for erroneous programs.
+            ///
+            /// Note: The optimization is only available during incr. comp.
+            pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () {
+                let dep_node = Self::to_dep_node(tcx, &key);
+
+                // Ensuring an "input" or anonymous query makes no sense
+                assert!(!dep_node.kind.is_anon());
+                assert!(!dep_node.kind.is_input());
+                if tcx.try_mark_green_and_read(&dep_node).is_none() {
+                    // A None return from `try_mark_green_and_read` means that this is either
+                    // a new dep node or that the dep node has already been marked red.
+                    // Either way, we can't call `dep_graph.read()` as we don't have the
+                    // DepNodeIndex. We must invoke the query itself. The performance cost
+                    // this introduces should be negligible as we'll immediately hit the
+                    // in-memory cache, or another query down the line will.
+                    let _ = tcx.$name(key);
+                }
+            }
+
             fn compute_result(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V {
                 let provider = tcx.maps.providers[key.map_crate()].$name;
                 provider(tcx.global_tcx(), key)
@@ -468,8 +509,7 @@ macro_rules! define_maps {
 
         define_provider_struct! {
             tcx: $tcx,
-            input: ($(([$($modifiers)*] [$name] [$K] [$V]))*),
-            output: ()
+            input: ($(([$($modifiers)*] [$name] [$K] [$V]))*)
         }
 
         impl<$tcx> Copy for Providers<$tcx> {}
@@ -480,78 +520,19 @@ macro_rules! define_maps {
 }
 
 macro_rules! define_map_struct {
-    // Initial state
-    (tcx: $tcx:tt,
-     input: $input:tt) => {
-        define_map_struct! {
-            tcx: $tcx,
-            input: $input,
-            output: ()
-        }
-    };
-
-    // Final output
     (tcx: $tcx:tt,
-     input: (),
-     output: ($($output:tt)*)) => {
+     input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
         pub struct Maps<$tcx> {
             providers: IndexVec<CrateNum, Providers<$tcx>>,
             query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,
-            $($output)*
-        }
-    };
-
-    // Field recognized and ready to shift into the output
-    (tcx: $tcx:tt,
-     ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]),
-     input: $input:tt,
-     output: ($($output:tt)*)) => {
-        define_map_struct! {
-            tcx: $tcx,
-            input: $input,
-            output: ($($output)*
-                     $(#[$attr])* $($pub)* $name: RefCell<QueryMap<queries::$name<$tcx>>>,)
-        }
-    };
-
-    // No modifiers left? This is a private item.
-    (tcx: $tcx:tt,
-     input: (([] $attrs:tt $name:tt) $($input:tt)*),
-     output: $output:tt) => {
-        define_map_struct! {
-            tcx: $tcx,
-            ready: ([] $attrs $name),
-            input: ($($input)*),
-            output: $output
-        }
-    };
-
-    // Skip other modifiers
-    (tcx: $tcx:tt,
-     input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
-     output: $output:tt) => {
-        define_map_struct! {
-            tcx: $tcx,
-            input: (([$($modifiers)*] $($fields)*) $($input)*),
-            output: $output
+            $($(#[$attr])*  $name: RefCell<QueryMap<queries::$name<$tcx>>>,)*
         }
     };
 }
 
 macro_rules! define_provider_struct {
-    // Initial state:
-    (tcx: $tcx:tt, input: $input:tt) => {
-        define_provider_struct! {
-            tcx: $tcx,
-            input: $input,
-            output: ()
-        }
-    };
-
-    // Final state:
     (tcx: $tcx:tt,
-     input: (),
-     output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => {
+     input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => {
         pub struct Providers<$tcx> {
             $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)*
         }
@@ -566,43 +547,51 @@ macro_rules! define_provider_struct {
             }
         }
     };
-
-    // Something ready to shift:
-    (tcx: $tcx:tt,
-     ready: ($name:tt $K:tt $V:tt),
-     input: $input:tt,
-     output: ($($output:tt)*)) => {
-        define_provider_struct! {
-            tcx: $tcx,
-            input: $input,
-            output: ($($output)* ($name $K $V))
-        }
-    };
-
-    // Regular queries produce a `V` only.
-    (tcx: $tcx:tt,
-     input: (([] $name:tt $K:tt $V:tt) $($input:tt)*),
-     output: $output:tt) => {
-        define_provider_struct! {
-            tcx: $tcx,
-            ready: ($name $K $V),
-            input: ($($input)*),
-            output: $output
-        }
-    };
-
-    // Skip modifiers.
-    (tcx: $tcx:tt,
-     input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
-     output: $output:tt) => {
-        define_provider_struct! {
-            tcx: $tcx,
-            input: (([$($modifiers)*] $($fields)*) $($input)*),
-            output: $output
-        }
-    };
 }
 
+
+/// The red/green evaluation system will try to mark a specific DepNode in the
+/// dependency graph as green by recursively trying to mark the dependencies of
+/// that DepNode as green. While doing so, it will sometimes encounter a DepNode
+/// where we don't know if it is red or green and we therefore actually have
+/// to recompute its value in order to find out. Since the only piece of
+/// information that we have at that point is the DepNode we are trying to
+/// re-evaluate, we need some way to re-run a query from just that. This is what
+/// `force_from_dep_node()` implements.
+///
+/// In the general case, a DepNode consists of a DepKind and an opaque
+/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+/// is usually constructed by computing a stable hash of the query-key that the
+/// DepNode corresponds to. Consequently, it is not in general possible to go
+/// back from hash to query-key (since hash functions are not reversible). For
+/// this reason `force_from_dep_node()` is expected to fail from time to time
+/// because we just cannot find out, from the DepNode alone, what the
+/// corresponding query-key is and therefore cannot re-run the query.
+///
+/// The system deals with this case letting `try_mark_green` fail which forces
+/// the root query to be re-evaluated.
+///
+/// Now, if force_from_dep_node() would always fail, it would be pretty useless.
+/// Fortunately, we can use some contextual information that will allow us to
+/// reconstruct query-keys for certain kinds of DepNodes. In particular, we
+/// enforce by construction that the GUID/fingerprint of certain DepNodes is a
+/// valid DefPathHash. Since we also always build a huge table that maps every
+/// DefPathHash in the current codebase to the corresponding DefId, we have
+/// everything we need to re-run the query.
+///
+/// Take the `mir_validated` query as an example. Like many other queries, it
+/// just has a single parameter: the DefId of the item it will compute the
+/// validated MIR for. Now, when we call `force_from_dep_node()` on a dep-node
+/// with kind `MirValidated`, we know that the GUID/fingerprint of the dep-node
+/// is actually a DefPathHash, and can therefore just look up the corresponding
+/// DefId in `tcx.def_path_hash_to_def_id`.
+///
+/// When you implement a new query, it will likely have a corresponding new
+/// DepKind, and you'll have to support it here in `force_from_dep_node()`. As
+/// a rule of thumb, if your query takes a DefId or DefIndex as sole parameter,
+/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
+/// add it to the "We don't have enough information to reconstruct..." group in
+/// the match below.
 pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
                                            dep_node: &DepNode)
                                            -> bool {
@@ -687,16 +676,16 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::Hir |
 
         // This are anonymous nodes
+        DepKind::TraitSelect |
+
+        // We don't have enough information to reconstruct the query key of
+        // these
         DepKind::IsCopy |
         DepKind::IsSized |
         DepKind::IsFreeze |
         DepKind::NeedsDrop |
         DepKind::Layout |
-        DepKind::TraitSelect |
         DepKind::ConstEval |
-
-        // We don't have enough information to reconstruct the query key of
-        // these
         DepKind::InstanceSymbolName |
         DepKind::MirShim |
         DepKind::BorrowCheckKrate |
@@ -705,6 +694,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TypeParamPredicates |
         DepKind::CodegenUnit |
         DepKind::CompileCodegenUnit |
+        DepKind::FulfillObligation |
+        DepKind::VtableMethods |
+        DepKind::EraseRegionsTy |
+        DepKind::NormalizeTy |
 
         // These are just odd
         DepKind::Null |
@@ -740,6 +733,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TypeOfItem => { force!(type_of, def_id!()); }
         DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
         DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
+        DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
         DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); }
         DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); }
         DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }
@@ -760,6 +754,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::InherentImpls => { force!(inherent_impls, def_id!()); }
         DepKind::TypeckBodiesKrate => { force!(typeck_item_bodies, LOCAL_CRATE); }
         DepKind::TypeckTables => { force!(typeck_tables_of, def_id!()); }
+        DepKind::UsedTraitImports => { force!(used_trait_imports, def_id!()); }
         DepKind::HasTypeckTables => { force!(has_typeck_tables, def_id!()); }
         DepKind::SymbolName => { force!(def_symbol_name, def_id!()); }
         DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); }
@@ -777,6 +772,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::ConstIsRvaluePromotableToStatic => {
             force!(const_is_rvalue_promotable_to_static, def_id!());
         }
+        DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); }
         DepKind::ImplParent => { force!(impl_parent, def_id!()); }
         DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); }
         DepKind::IsExportedSymbol => { force!(is_exported_symbol, def_id!()); }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index c4f526d8014..129c81c5cd6 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -18,6 +18,7 @@ pub use self::fold::TypeFoldable;
 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 hir::map::DefPathData;
 use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
@@ -89,6 +90,7 @@ pub mod adjustment;
 pub mod binding;
 pub mod cast;
 pub mod error;
+mod erase_regions;
 pub mod fast_reject;
 pub mod fold;
 pub mod inhabitedness;
@@ -2232,6 +2234,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Given a `VariantDef`, returns the def-id of the `AdtDef` of which it is a part.
+    pub fn adt_def_id_of_variant(self, variant_def: &'tcx VariantDef) -> DefId {
+        let def_key = self.def_key(variant_def.did);
+        match def_key.disambiguated_data.data {
+            // for enum variants and tuple structs, the def-id of the ADT itself
+            // is the *parent* of the variant
+            DefPathData::EnumVariant(..) | DefPathData::StructCtor =>
+                DefId { krate: variant_def.did.krate, index: def_key.parent.unwrap() },
+
+            // otherwise, for structs and unions, they share a def-id
+            _ => variant_def.did,
+        }
+    }
+
     pub fn item_name(self, id: DefId) -> InternedString {
         if let Some(id) = self.hir.as_local_node_id(id) {
             self.hir.name(id).as_str()
@@ -2560,6 +2576,7 @@ fn original_crate_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 pub fn provide(providers: &mut ty::maps::Providers) {
     util::provide(providers);
     context::provide(providers);
+    erase_regions::provide(providers);
     *providers = ty::maps::Providers {
         associated_item,
         associated_item_def_ids,
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 657ed407791..5e1dc485d42 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -73,42 +73,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // projection).
         match ty.sty {
             ty::TyClosure(def_id, ref substs) => {
-                // FIXME(#27086). We do not accumulate from substs, since they
-                // don't represent reachable data. This means that, in
-                // practice, some of the lifetime parameters might not
-                // be in scope when the body runs, so long as there is
-                // no reachable data with that lifetime. For better or
-                // worse, this is consistent with fn types, however,
-                // which can also encapsulate data in this fashion
-                // (though it's somewhat harder, and typically
-                // requires virtual dispatch).
-                //
-                // Note that changing this (in a naive way, at least)
-                // causes regressions for what appears to be perfectly
-                // reasonable code like this:
-                //
-                // ```
-                // fn foo<'a>(p: &Data<'a>) {
-                //    bar(|q: &mut Parser| q.read_addr())
-                // }
-                // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
-                // }
-                // ```
-                //
-                // Note that `p` (and `'a`) are not used in the
-                // closure at all, but to meet the requirement that
-                // the closure type `C: 'static` (so it can be coerced
-                // to the object type), we get the requirement that
-                // `'a: 'static` since `'a` appears in the closure
-                // type `C`.
-                //
-                // A smarter fix might "prune" unused `func_substs` --
-                // this would avoid breaking simple examples like
-                // this, but would still break others (which might
-                // indeed be invalid, depending on your POV). Pruning
-                // would be a subtle process, since we have to see
-                // what func/type parameters are used and unused,
-                // taking into consideration UFCS and so forth.
 
                 for upvar_ty in substs.upvar_tys(def_id, *self) {
                     self.compute_components(upvar_ty, out);
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 10e1286465d..064627c21bf 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -24,7 +24,6 @@ use std::cmp::Ordering;
 use syntax::abi;
 use syntax::ast::{self, Name};
 use syntax::symbol::keywords;
-use util::nodemap::FxHashMap;
 
 use serialize;
 
@@ -1070,54 +1069,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
-    /// Checks whether a type is visibly uninhabited from a particular module.
-    /// # Example
-    /// ```rust
-    /// enum Void {}
-    /// mod a {
-    ///     pub mod b {
-    ///         pub struct SecretlyUninhabited {
-    ///             _priv: !,
-    ///         }
-    ///     }
-    /// }
-    ///
-    /// mod c {
-    ///     pub struct AlsoSecretlyUninhabited {
-    ///         _priv: Void,
-    ///     }
-    ///     mod d {
-    ///     }
-    /// }
-    ///
-    /// struct Foo {
-    ///     x: a::b::SecretlyUninhabited,
-    ///     y: c::AlsoSecretlyUninhabited,
-    /// }
-    /// ```
-    /// In this code, the type `Foo` will only be visibly uninhabited inside the
-    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
-    /// contain `Foo`.
-    ///
-    /// # Example
-    /// ```rust
-    /// let foo_result: Result<T, Foo> = ... ;
-    /// let Ok(t) = foo_result;
-    /// ```
-    /// This code should only compile in modules where the uninhabitedness of Foo is
-    /// visible.
-    pub fn is_uninhabited_from(&self, module: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
-        let mut visited = FxHashMap::default();
-        let forest = self.uninhabited_from(&mut visited, tcx);
-
-        // To check whether this type is uninhabited at all (not just from the
-        // given node) you could check whether the forest is empty.
-        // ```
-        // forest.is_empty()
-        // ```
-        forest.contains(tcx, module)
-    }
-
     pub fn is_primitive(&self) -> bool {
         match self.sty {
             TyBool | TyChar | TyInt(_) | TyUint(_) | TyFloat(_) => true,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 214973e3085..0eb2c19fe44 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -20,6 +20,7 @@ use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
 use ty::{TyClosure, TyGenerator, TyProjection, TyAnon};
 use ty::{TyDynamic, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
+use util::nodemap::FxHashSet;
 
 use std::cell::Cell;
 use std::fmt;
@@ -32,310 +33,543 @@ use syntax::ast::CRATE_NODE_ID;
 use syntax::symbol::Symbol;
 use hir;
 
-pub fn verbose() -> bool {
-    ty::tls::with(|tcx| tcx.sess.verbose())
+macro_rules! gen_display_debug_body {
+    ( $with:path ) => {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            let mut cx = PrintContext::new();
+            $with(self, f, &mut cx)
+        }
+    };
 }
-
-pub fn identify_regions() -> bool {
-    ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.identify_regions)
+macro_rules! gen_display_debug {
+    ( ($($x:tt)+) $target:ty, display yes ) => {
+        impl<$($x)+> fmt::Display for $target {
+            gen_display_debug_body! { Print::print_display }
+        }
+    };
+    ( () $target:ty, display yes ) => {
+        impl fmt::Display for $target {
+            gen_display_debug_body! { Print::print_display }
+        }
+    };
+    ( ($($x:tt)+) $target:ty, debug yes ) => {
+        impl<$($x)+> fmt::Debug for $target {
+            gen_display_debug_body! { Print::print_debug }
+        }
+    };
+    ( () $target:ty, debug yes ) => {
+        impl fmt::Debug for $target {
+            gen_display_debug_body! { Print::print_debug }
+        }
+    };
+    ( $generic:tt $target:ty, $t:ident no ) => {};
 }
-
-fn fn_sig(f: &mut fmt::Formatter,
-          inputs: &[Ty],
-          variadic: bool,
-          output: Ty)
-          -> fmt::Result {
-    write!(f, "(")?;
-    let mut inputs = inputs.iter();
-    if let Some(&ty) = inputs.next() {
-        write!(f, "{}", ty)?;
-        for &ty in inputs {
-            write!(f, ", {}", ty)?;
+macro_rules! gen_print_impl {
+    ( ($($x:tt)+) $target:ty, ($self:ident, $f:ident, $cx:ident) $disp:block $dbg:block ) => {
+        impl<$($x)+> Print for $target {
+            fn print<F: fmt::Write>(&$self, $f: &mut F, $cx: &mut PrintContext) -> fmt::Result {
+                if $cx.is_debug $dbg
+                else $disp
+            }
         }
-        if variadic {
-            write!(f, ", ...")?;
+    };
+    ( () $target:ty, ($self:ident, $f:ident, $cx:ident) $disp:block $dbg:block ) => {
+        impl Print for $target {
+            fn print<F: fmt::Write>(&$self, $f: &mut F, $cx: &mut PrintContext) -> fmt::Result {
+                if $cx.is_debug $dbg
+                else $disp
+            }
         }
+    };
+    ( $generic:tt $target:ty,
+      $vars:tt $gendisp:ident $disp:block $gendbg:ident $dbg:block ) => {
+        gen_print_impl! { $generic $target, $vars $disp $dbg }
+        gen_display_debug! { $generic $target, display $gendisp }
+        gen_display_debug! { $generic $target, debug $gendbg }
     }
-    write!(f, ")")?;
-    if !output.is_nil() {
-        write!(f, " -> {}", output)?;
+}
+macro_rules! define_print {
+    ( $generic:tt $target:ty,
+      $vars:tt { display $disp:block debug $dbg:block } ) => {
+        gen_print_impl! { $generic $target, $vars yes $disp yes $dbg }
+    };
+    ( $generic:tt $target:ty,
+      $vars:tt { debug $dbg:block display $disp:block } ) => {
+        gen_print_impl! { $generic $target, $vars yes $disp yes $dbg }
+    };
+    ( $generic:tt $target:ty,
+      $vars:tt { debug $dbg:block } ) => {
+        gen_print_impl! { $generic $target, $vars no {
+            bug!(concat!("display not implemented for ", stringify!($target)));
+        } yes $dbg }
+    };
+    ( $generic:tt $target:ty,
+      ($self:ident, $f:ident, $cx:ident) { display $disp:block } ) => {
+        gen_print_impl! { $generic $target, ($self, $f, $cx) yes $disp no {
+            write!($f, "{:?}", $self)
+        } }
+    };
+}
+macro_rules! define_print_multi {
+    ( [ $($generic:tt $target:ty),* ] $vars:tt $def:tt ) => {
+        $(define_print! { $generic $target, $vars $def })*
+    };
+}
+macro_rules! print_inner {
+    ( $f:expr, $cx:expr, write ($($data:expr),+) ) => {
+        write!($f, $($data),+)
+    };
+    ( $f:expr, $cx:expr, $kind:ident ($data:expr) ) => {
+        $data.$kind($f, $cx)
+    };
+}
+macro_rules! print {
+    ( $f:expr, $cx:expr $(, $kind:ident $data:tt)+ ) => {
+        Ok(())$(.and_then(|_| print_inner!($f, $cx, $kind $data)))+
+    };
+}
+
+
+struct LateBoundRegionNameCollector(FxHashSet<Symbol>);
+impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+        match *r {
+            ty::ReLateBound(_, ty::BrNamed(_, name)) => {
+                self.0.insert(name);
+            },
+            _ => {},
+        }
+        r.super_visit_with(self)
     }
+}
 
-    Ok(())
+#[derive(Debug)]
+pub struct PrintContext {
+    is_debug: bool,
+    is_verbose: bool,
+    identify_regions: bool,
+    used_region_names: Option<FxHashSet<Symbol>>,
+    region_index: usize,
+    binder_depth: usize,
+}
+impl PrintContext {
+    fn new() -> Self {
+        ty::tls::with_opt(|tcx| {
+            let (is_verbose, identify_regions) = tcx.map(
+                |tcx| (tcx.sess.verbose(), tcx.sess.opts.debugging_opts.identify_regions)
+            ).unwrap_or((false, false));
+            PrintContext {
+                is_debug: false,
+                is_verbose: is_verbose,
+                identify_regions: identify_regions,
+                used_region_names: None,
+                region_index: 0,
+                binder_depth: 0,
+            }
+        })
+    }
+    fn prepare_late_bound_region_info<'tcx, T>(&mut self, value: &ty::Binder<T>)
+    where T: TypeFoldable<'tcx>
+    {
+        let mut collector = LateBoundRegionNameCollector(FxHashSet());
+        value.visit_with(&mut collector);
+        self.used_region_names = Some(collector.0);
+        self.region_index = 0;
+    }
 }
 
-pub fn parameterized(f: &mut fmt::Formatter,
-                     substs: &subst::Substs,
-                     mut did: DefId,
-                     projections: &[ty::ProjectionPredicate])
-                     -> fmt::Result {
-    let key = ty::tls::with(|tcx| tcx.def_key(did));
-    let mut item_name = if let Some(name) = key.disambiguated_data.data.get_opt_name() {
-        Some(name)
-    } else {
-        did.index = key.parent.unwrap_or_else(
-            || bug!("finding type for {:?}, encountered def-id {:?} with no parent",
-                    did, did));
-        parameterized(f, substs, did, projections)?;
-        return write!(f, "::{}", key.disambiguated_data.data.as_interned_str());
-    };
+pub trait Print {
+    fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result;
+    fn print_to_string(&self, cx: &mut PrintContext) -> String {
+        let mut result = String::new();
+        let _ = self.print(&mut result, cx);
+        result
+    }
+    fn print_display<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
+        let old_debug = cx.is_debug;
+        cx.is_debug = false;
+        let result = self.print(f, cx);
+        cx.is_debug = old_debug;
+        result
+    }
+    fn print_display_to_string(&self, cx: &mut PrintContext) -> String {
+        let mut result = String::new();
+        let _ = self.print_display(&mut result, cx);
+        result
+    }
+    fn print_debug<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
+        let old_debug = cx.is_debug;
+        cx.is_debug = true;
+        let result = self.print(f, cx);
+        cx.is_debug = old_debug;
+        result
+    }
+    fn print_debug_to_string(&self, cx: &mut PrintContext) -> String {
+        let mut result = String::new();
+        let _ = self.print_debug(&mut result, cx);
+        result
+    }
+}
 
-    let mut verbose = false;
-    let mut num_supplied_defaults = 0;
-    let mut has_self = false;
-    let mut num_regions = 0;
-    let mut num_types = 0;
-    let mut is_value_path = false;
-    let fn_trait_kind = ty::tls::with(|tcx| {
-        // Unfortunately, some kinds of items (e.g., closures) don't have
-        // generics. So walk back up the find the closest parent that DOES
-        // have them.
-        let mut item_def_id = did;
-        loop {
-            let key = tcx.def_key(item_def_id);
-            match key.disambiguated_data.data {
-                DefPathData::TypeNs(_) => {
-                    break;
-                }
-                DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => {
-                    is_value_path = true;
-                    break;
-                }
-                _ => {
-                    // if we're making a symbol for something, there ought
-                    // to be a value or type-def or something in there
-                    // *somewhere*
-                    item_def_id.index = key.parent.unwrap_or_else(|| {
-                        bug!("finding type for {:?}, encountered def-id {:?} with no \
-                             parent", did, item_def_id);
-                    });
-                }
+impl PrintContext {
+    fn fn_sig<F: fmt::Write>(&mut self,
+                             f: &mut F,
+                             inputs: &[Ty],
+                             variadic: bool,
+                             output: Ty)
+                             -> fmt::Result {
+        write!(f, "(")?;
+        let mut inputs = inputs.iter();
+        if let Some(&ty) = inputs.next() {
+            print!(f, self, print_display(ty))?;
+            for &ty in inputs {
+                print!(f, self, write(", "), print_display(ty))?;
+            }
+            if variadic {
+                write!(f, ", ...")?;
             }
         }
-        let mut generics = tcx.generics_of(item_def_id);
-        let mut path_def_id = did;
-        verbose = tcx.sess.verbose();
-        has_self = generics.has_self;
-
-        let mut child_types = 0;
-        if let Some(def_id) = generics.parent {
-            // Methods.
-            assert!(is_value_path);
-            child_types = generics.types.len();
-            generics = tcx.generics_of(def_id);
-            num_regions = generics.regions.len();
-            num_types = generics.types.len();
+        write!(f, ")")?;
+        if !output.is_nil() {
+            print!(f, self, write(" -> "), print_display(output))?;
+        }
 
-            if has_self {
-                write!(f, "<{} as ", substs.type_at(0))?;
-            }
+        Ok(())
+    }
 
-            path_def_id = def_id;
+    fn parameterized<F: fmt::Write>(&mut self,
+                                    f: &mut F,
+                                    substs: &subst::Substs,
+                                    mut did: DefId,
+                                    projections: &[ty::ProjectionPredicate])
+                                    -> fmt::Result {
+        let key = ty::tls::with(|tcx| tcx.def_key(did));
+        let mut item_name = if let Some(name) = key.disambiguated_data.data.get_opt_name() {
+            Some(name)
         } else {
-            item_name = None;
+            did.index = key.parent.unwrap_or_else(
+                || bug!("finding type for {:?}, encountered def-id {:?} with no parent",
+                        did, did));
+            self.parameterized(f, substs, did, projections)?;
+            return write!(f, "::{}", key.disambiguated_data.data.as_interned_str());
+        };
 
-            if is_value_path {
-                // Functions.
-                assert_eq!(has_self, false);
-            } else {
-                // Types and traits.
+        let verbose = self.is_verbose;
+        let mut num_supplied_defaults = 0;
+        let mut has_self = false;
+        let mut num_regions = 0;
+        let mut num_types = 0;
+        let mut is_value_path = false;
+        let fn_trait_kind = ty::tls::with(|tcx| {
+            // Unfortunately, some kinds of items (e.g., closures) don't have
+            // generics. So walk back up the find the closest parent that DOES
+            // have them.
+            let mut item_def_id = did;
+            loop {
+                let key = tcx.def_key(item_def_id);
+                match key.disambiguated_data.data {
+                    DefPathData::TypeNs(_) => {
+                        break;
+                    }
+                    DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => {
+                        is_value_path = true;
+                        break;
+                    }
+                    _ => {
+                        // if we're making a symbol for something, there ought
+                        // to be a value or type-def or something in there
+                        // *somewhere*
+                        item_def_id.index = key.parent.unwrap_or_else(|| {
+                            bug!("finding type for {:?}, encountered def-id {:?} with no \
+                                 parent", did, item_def_id);
+                        });
+                    }
+                }
+            }
+            let mut generics = tcx.generics_of(item_def_id);
+            let mut path_def_id = did;
+            has_self = generics.has_self;
+
+            let mut child_types = 0;
+            if let Some(def_id) = generics.parent {
+                // Methods.
+                assert!(is_value_path);
+                child_types = generics.types.len();
+                generics = tcx.generics_of(def_id);
                 num_regions = generics.regions.len();
                 num_types = generics.types.len();
+
+                if has_self {
+                    print!(f, self, write("<"), print_display(substs.type_at(0)), write(" as "))?;
+                }
+
+                path_def_id = def_id;
+            } else {
+                item_name = None;
+
+                if is_value_path {
+                    // Functions.
+                    assert_eq!(has_self, false);
+                } else {
+                    // Types and traits.
+                    num_regions = generics.regions.len();
+                    num_types = generics.types.len();
+                }
             }
-        }
 
-        if !verbose {
-            if generics.types.last().map_or(false, |def| def.has_default) {
-                if let Some(substs) = tcx.lift(&substs) {
-                    let tps = substs.types().rev().skip(child_types);
-                    for (def, actual) in generics.types.iter().rev().zip(tps) {
-                        if !def.has_default {
-                            break;
-                        }
-                        if tcx.type_of(def.def_id).subst(tcx, substs) != actual {
-                            break;
+            if !verbose {
+                if generics.types.last().map_or(false, |def| def.has_default) {
+                    if let Some(substs) = tcx.lift(&substs) {
+                        let tps = substs.types().rev().skip(child_types);
+                        for (def, actual) in generics.types.iter().rev().zip(tps) {
+                            if !def.has_default {
+                                break;
+                            }
+                            if tcx.type_of(def.def_id).subst(tcx, substs) != actual {
+                                break;
+                            }
+                            num_supplied_defaults += 1;
                         }
-                        num_supplied_defaults += 1;
                     }
                 }
             }
-        }
 
-        write!(f, "{}", tcx.item_path_str(path_def_id))?;
-        Ok(tcx.lang_items().fn_trait_kind(path_def_id))
-    })?;
+            print!(f, self, write("{}", tcx.item_path_str(path_def_id)))?;
+            Ok(tcx.lang_items().fn_trait_kind(path_def_id))
+        })?;
 
-    if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
-        let projection_ty = projections[0].ty;
-        if let TyTuple(ref args, _) = substs.type_at(1).sty {
-            return fn_sig(f, args, false, projection_ty);
+        if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
+            let projection_ty = projections[0].ty;
+            if let TyTuple(ref args, _) = substs.type_at(1).sty {
+                return self.fn_sig(f, args, false, projection_ty);
+            }
         }
-    }
 
-    let empty = Cell::new(true);
-    let start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
-        if empty.get() {
-            empty.set(false);
-            write!(f, "{}", start)
-        } else {
-            write!(f, "{}", cont)
-        }
-    };
+        let empty = Cell::new(true);
+        let start_or_continue = |f: &mut F, start: &str, cont: &str| {
+            if empty.get() {
+                empty.set(false);
+                write!(f, "{}", start)
+            } else {
+                write!(f, "{}", cont)
+            }
+        };
 
-    let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| {
-        // Don't print any regions if they're all erased.
-        let regions = || substs.regions().skip(skip).take(count);
-        if regions().all(|r: ty::Region| *r == ty::ReErased) {
-            return Ok(());
-        }
+        let print_regions = |f: &mut F, start: &str, skip, count| {
+            // Don't print any regions if they're all erased.
+            let regions = || substs.regions().skip(skip).take(count);
+            if regions().all(|r: ty::Region| *r == ty::ReErased) {
+                return Ok(());
+            }
 
-        for region in regions() {
-            let region: ty::Region = region;
-            start_or_continue(f, start, ", ")?;
-            if verbose {
-                write!(f, "{:?}", region)?;
-            } else {
-                let s = region.to_string();
-                if s.is_empty() {
-                    // This happens when the value of the region
-                    // parameter is not easily serialized. This may be
-                    // because the user omitted it in the first place,
-                    // or because it refers to some block in the code,
-                    // etc. I'm not sure how best to serialize this.
-                    write!(f, "'_")?;
+            for region in regions() {
+                let region: ty::Region = region;
+                start_or_continue(f, start, ", ")?;
+                if verbose {
+                    write!(f, "{:?}", region)?;
                 } else {
-                    write!(f, "{}", s)?;
+                    let s = region.to_string();
+                    if s.is_empty() {
+                        // This happens when the value of the region
+                        // parameter is not easily serialized. This may be
+                        // because the user omitted it in the first place,
+                        // or because it refers to some block in the code,
+                        // etc. I'm not sure how best to serialize this.
+                        write!(f, "'_")?;
+                    } else {
+                        write!(f, "{}", s)?;
+                    }
                 }
             }
+
+            Ok(())
+        };
+
+        print_regions(f, "<", 0, num_regions)?;
+
+        let tps = substs.types().take(num_types - num_supplied_defaults)
+                                .skip(has_self as usize);
+
+        for ty in tps {
+            start_or_continue(f, "<", ", ")?;
+            ty.print_display(f, self)?;
         }
 
-        Ok(())
-    };
+        for projection in projections {
+            start_or_continue(f, "<", ", ")?;
+            ty::tls::with(|tcx|
+                print!(f, self,
+                       write("{}=",
+                             tcx.associated_item(projection.projection_ty.item_def_id).name),
+                       print_display(projection.ty))
+            )?;
+        }
 
-    print_regions(f, "<", 0, num_regions)?;
+        start_or_continue(f, "", ">")?;
 
-    let tps = substs.types().take(num_types - num_supplied_defaults)
-                            .skip(has_self as usize);
+        // For values, also print their name and type parameters.
+        if is_value_path {
+            empty.set(true);
 
-    for ty in tps {
-        start_or_continue(f, "<", ", ")?;
-        write!(f, "{}", ty)?;
-    }
+            if has_self {
+                write!(f, ">")?;
+            }
 
-    for projection in projections {
-        start_or_continue(f, "<", ", ")?;
-        ty::tls::with(|tcx|
-            write!(f, "{}={}",
-            tcx.associated_item(projection.projection_ty.item_def_id).name,
-            projection.ty)
-        )?;
-    }
+            if let Some(item_name) = item_name {
+                write!(f, "::{}", item_name)?;
+            }
 
-    start_or_continue(f, "", ">")?;
+            print_regions(f, "::<", num_regions, usize::MAX)?;
 
-    // For values, also print their name and type parameters.
-    if is_value_path {
-        empty.set(true);
+            // FIXME: consider being smart with defaults here too
+            for ty in substs.types().skip(num_types) {
+                start_or_continue(f, "::<", ", ")?;
+                ty.print_display(f, self)?;
+            }
 
-        if has_self {
-            write!(f, ">")?;
+            start_or_continue(f, "", ">")?;
         }
 
-        if let Some(item_name) = item_name {
-            write!(f, "::{}", item_name)?;
+        Ok(())
+    }
+
+    fn in_binder<'a, 'gcx, 'tcx, T, U, F>(&mut self,
+                                          f: &mut F,
+                                          tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                          original: &ty::Binder<T>,
+                                          lifted: Option<ty::Binder<U>>) -> fmt::Result
+        where T: Print, U: Print + TypeFoldable<'tcx>, F: fmt::Write
+    {
+        fn name_by_region_index(index: usize) -> Symbol {
+            match index {
+                0 => Symbol::intern("'r"),
+                1 => Symbol::intern("'s"),
+                i => Symbol::intern(&format!("'t{}", i-2)),
+            }
         }
 
-        print_regions(f, "::<", num_regions, usize::MAX)?;
+        // Replace any anonymous late-bound regions with named
+        // variants, using gensym'd identifiers, so that we can
+        // clearly differentiate between named and unnamed regions in
+        // the output. We'll probably want to tweak this over time to
+        // decide just how much information to give.
+        let value = if let Some(v) = lifted {
+            v
+        } else {
+            return original.0.print_display(f, self);
+        };
 
-        // FIXME: consider being smart with defaults here too
-        for ty in substs.types().skip(num_types) {
-            start_or_continue(f, "::<", ", ")?;
-            write!(f, "{}", ty)?;
+        if self.binder_depth == 0 {
+            self.prepare_late_bound_region_info(&value);
         }
 
-        start_or_continue(f, "", ">")?;
+        let mut empty = true;
+        let mut start_or_continue = |f: &mut F, start: &str, cont: &str| {
+            if empty {
+                empty = false;
+                write!(f, "{}", start)
+            } else {
+                write!(f, "{}", cont)
+            }
+        };
+
+        let old_region_index = self.region_index;
+        let mut region_index = old_region_index;
+        let new_value = tcx.replace_late_bound_regions(&value, |br| {
+            let _ = start_or_continue(f, "for<", ", ");
+            let br = match br {
+                ty::BrNamed(_, name) => {
+                    let _ = write!(f, "{}", name);
+                    br
+                }
+                ty::BrAnon(_) |
+                ty::BrFresh(_) |
+                ty::BrEnv => {
+                    let name = loop {
+                        let name = name_by_region_index(region_index);
+                        region_index += 1;
+                        if !self.is_name_used(&name) {
+                            break name;
+                        }
+                    };
+                    let _ = write!(f, "{}", name);
+                    ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID),
+                                name)
+                }
+            };
+            tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
+        }).0;
+        start_or_continue(f, "", "> ")?;
+
+        // Push current state to gcx, and restore after writing new_value.
+        self.binder_depth += 1;
+        self.region_index = region_index;
+        let result = new_value.print_display(f, self);
+        self.region_index = old_region_index;
+        self.binder_depth -= 1;
+        result
     }
 
-    Ok(())
+    fn is_name_used(&self, name: &Symbol) -> bool {
+        match self.used_region_names {
+            Some(ref names) => names.contains(name),
+            None => false,
+        }
+    }
 }
 
-fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
-                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                   original: &ty::Binder<T>,
-                                   lifted: Option<ty::Binder<U>>) -> fmt::Result
-    where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx>
-{
-    // Replace any anonymous late-bound regions with named
-    // variants, using gensym'd identifiers, so that we can
-    // clearly differentiate between named and unnamed regions in
-    // the output. We'll probably want to tweak this over time to
-    // decide just how much information to give.
-    let value = if let Some(v) = lifted {
-        v
-    } else {
-        return write!(f, "{}", original.0);
-    };
+pub fn verbose() -> bool {
+    ty::tls::with(|tcx| tcx.sess.verbose())
+}
 
-    let mut empty = true;
-    let mut start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
-        if empty {
-            empty = false;
-            write!(f, "{}", start)
-        } else {
-            write!(f, "{}", cont)
-        }
-    };
+pub fn identify_regions() -> bool {
+    ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.identify_regions)
+}
 
-    let new_value = tcx.replace_late_bound_regions(&value, |br| {
-        let _ = start_or_continue(f, "for<", ", ");
-        let br = match br {
-            ty::BrNamed(_, name) => {
-                let _ = write!(f, "{}", name);
-                br
-            }
-            ty::BrAnon(_) |
-            ty::BrFresh(_) |
-            ty::BrEnv => {
-                let name = Symbol::intern("'r");
-                let _ = write!(f, "{}", name);
-                ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID),
-                            name)
-            }
-        };
-        tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
-    }).0;
+pub fn parameterized<F: fmt::Write>(f: &mut F,
+                                    substs: &subst::Substs,
+                                    did: DefId,
+                                    projections: &[ty::ProjectionPredicate])
+                                    -> fmt::Result {
+    PrintContext::new().parameterized(f, substs, did, projections)
+}
 
-    start_or_continue(f, "", "> ")?;
-    write!(f, "{}", new_value)
+
+impl<'a, T: Print> Print for &'a T {
+    fn print<F: fmt::Write>(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result {
+        (*self).print(f, cx)
+    }
 }
 
-impl<'tcx> fmt::Display for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // Generate the main trait ref, including associated types.
-        ty::tls::with(|tcx| {
-            // Use a type that can't appear in defaults of type parameters.
-            let dummy_self = tcx.mk_infer(ty::FreshTy(0));
-
-            if let Some(p) = self.principal() {
-                let principal = tcx.lift(&p).expect("could not lift TraitRef for printing")
-                    .with_self_ty(tcx, dummy_self);
-                let projections = self.projection_bounds().map(|p| {
-                    tcx.lift(&p)
-                        .expect("could not lift projection for printing")
-                        .with_self_ty(tcx, dummy_self)
-                }).collect::<Vec<_>>();
-                parameterized(f, principal.substs, principal.def_id, &projections)?;
-            }
+define_print! {
+    ('tcx) &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, (self, f, cx) {
+        display {
+            // Generate the main trait ref, including associated types.
+            ty::tls::with(|tcx| {
+                // Use a type that can't appear in defaults of type parameters.
+                let dummy_self = tcx.mk_infer(ty::FreshTy(0));
+
+                if let Some(p) = self.principal() {
+                    let principal = tcx.lift(&p).expect("could not lift TraitRef for printing")
+                        .with_self_ty(tcx, dummy_self);
+                    let projections = self.projection_bounds().map(|p| {
+                        tcx.lift(&p)
+                            .expect("could not lift projection for printing")
+                            .with_self_ty(tcx, dummy_self)
+                    }).collect::<Vec<_>>();
+                    cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
+                }
 
-            // Builtin bounds.
-            for did in self.auto_traits() {
-                write!(f, " + {}", tcx.item_path_str(did))?;
-            }
+                // Builtin bounds.
+                for did in self.auto_traits() {
+                    write!(f, " + {}", tcx.item_path_str(did))?;
+                }
 
-            Ok(())
-        })?;
+                Ok(())
+            })?;
 
-        Ok(())
+            Ok(())
+        }
     }
 }
 
@@ -357,42 +591,6 @@ impl fmt::Debug for ty::RegionParameterDef {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::TyS<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", *self)
-    }
-}
-
-impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}{}",
-               if self.mutbl == hir::MutMutable { "mut " } else { "" },
-               self.ty)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // when printing out the debug representation, we don't need
-        // to enumerate the `for<...>` etc because the debruijn index
-        // tells you everything you need to know.
-        write!(f, "<{:?} as {}>", self.self_ty(), *self)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| {
-            let dummy_self = tcx.mk_infer(ty::FreshTy(0));
-
-            let trait_ref = tcx.lift(&ty::Binder(*self))
-                               .expect("could not lift TraitRef for printing")
-                               .with_self_ty(tcx, dummy_self).0;
-            parameterized(f, trait_ref.substs, trait_ref.def_id, &[])
-        })
-    }
-}
-
 impl fmt::Debug for ty::TraitDef {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         ty::tls::with(|tcx| {
@@ -409,196 +607,226 @@ impl fmt::Debug for ty::AdtDef {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
+impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:?} -> {}", self.kind, self.target)
+        write!(f, "ClosureUpvar({:?},{:?})",
+               self.def,
+               self.ty)
     }
 }
 
-impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+impl fmt::Debug for ty::UpvarId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
-            ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
-            ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair),
-            ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
-            ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
-            ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
-            ty::Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty),
-            ty::Predicate::ObjectSafe(trait_def_id) => {
-                write!(f, "ObjectSafe({:?})", trait_def_id)
-            }
-            ty::Predicate::ClosureKind(closure_def_id, kind) => {
-                write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
-            }
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
-            }
-        }
+        write!(f, "UpvarId({:?};`{}`;{:?})",
+               self.var_id,
+               ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))),
+               self.closure_expr_id)
     }
 }
 
-impl fmt::Display for ty::BoundRegion {
+impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if verbose() {
-            return write!(f, "{:?}", *self);
+        write!(f, "UpvarBorrow({:?}, {:?})",
+               self.kind, self.region)
+    }
+}
+
+define_print! {
+    ('tcx) ty::TypeAndMut<'tcx>, (self, f, cx) {
+        display {
+            print!(f, cx,
+                   write("{}", if self.mutbl == hir::MutMutable { "mut " } else { "" }),
+                   print(self.ty))
         }
+    }
+}
 
-        match *self {
-            BrNamed(_, name) => write!(f, "{}", name),
-            BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
+define_print! {
+    ('tcx) ty::ExistentialTraitRef<'tcx>, (self, f, cx) {
+        debug {
+            ty::tls::with(|tcx| {
+                let dummy_self = tcx.mk_infer(ty::FreshTy(0));
+
+                let trait_ref = tcx.lift(&ty::Binder(*self))
+                                   .expect("could not lift TraitRef for printing")
+                                   .with_self_ty(tcx, dummy_self).0;
+                cx.parameterized(f, trait_ref.substs, trait_ref.def_id, &[])
+            })
         }
     }
 }
 
-impl fmt::Debug for ty::BoundRegion {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            BrAnon(n) => write!(f, "BrAnon({:?})", n),
-            BrFresh(n) => write!(f, "BrFresh({:?})", n),
-            BrNamed(did, name) => {
-                write!(f, "BrNamed({:?}:{:?}, {:?})",
-                       did.krate, did.index, name)
-            }
-            BrEnv => "BrEnv".fmt(f),
+define_print! {
+    ('tcx) ty::adjustment::Adjustment<'tcx>, (self, f, cx) {
+        debug {
+            print!(f, cx, write("{:?} -> ", self.kind), print(self.target))
         }
     }
 }
 
-impl fmt::Debug for ty::RegionKind {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::ReEarlyBound(ref data) => {
-                write!(f, "ReEarlyBound({}, {})",
-                       data.index,
-                       data.name)
+define_print! {
+    () ty::BoundRegion, (self, f, cx) {
+        display {
+            if cx.is_verbose {
+                return self.print_debug(f, cx);
             }
 
-            ty::ReLateBound(binder_id, ref bound_region) => {
-                write!(f, "ReLateBound({:?}, {:?})",
-                       binder_id,
-                       bound_region)
+            match *self {
+                BrNamed(_, name) => write!(f, "{}", name),
+                BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
             }
+        }
+        debug {
+            return match *self {
+                BrAnon(n) => write!(f, "BrAnon({:?})", n),
+                BrFresh(n) => write!(f, "BrFresh({:?})", n),
+                BrNamed(did, name) => {
+                    write!(f, "BrNamed({:?}:{:?}, {:?})",
+                           did.krate, did.index, name)
+                }
+                BrEnv => write!(f, "BrEnv"),
+            };
+        }
+    }
+}
 
-            ty::ReFree(ref fr) => write!(f, "{:?}", fr),
-
-            ty::ReScope(id) => {
-                write!(f, "ReScope({:?})", id)
+define_print! {
+    () ty::RegionKind, (self, f, cx) {
+        display {
+            if cx.is_verbose {
+                return self.print_debug(f, cx);
             }
 
-            ty::ReStatic => write!(f, "ReStatic"),
-
-            ty::ReVar(ref vid) => {
-                write!(f, "{:?}", vid)
+            // These printouts are concise.  They do not contain all the information
+            // the user might want to diagnose an error, but there is basically no way
+            // to fit that into a short string.  Hence the recommendation to use
+            // `explain_region()` or `note_and_explain_region()`.
+            match *self {
+                ty::ReEarlyBound(ref data) => {
+                    write!(f, "{}", data.name)
+                }
+                ty::ReLateBound(_, br) |
+                ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
+                ty::ReSkolemized(_, br) => {
+                    write!(f, "{}", br)
+                }
+                ty::ReScope(scope) if cx.identify_regions => {
+                    match scope.data() {
+                        region::ScopeData::Node(id) =>
+                            write!(f, "'{}s", id.as_usize()),
+                        region::ScopeData::CallSite(id) =>
+                            write!(f, "'{}cs", id.as_usize()),
+                        region::ScopeData::Arguments(id) =>
+                            write!(f, "'{}as", id.as_usize()),
+                        region::ScopeData::Destruction(id) =>
+                            write!(f, "'{}ds", id.as_usize()),
+                        region::ScopeData::Remainder(BlockRemainder
+                                                     { block, first_statement_index }) =>
+                            write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()),
+                    }
+                }
+                ty::ReVar(region_vid) if cx.identify_regions => {
+                    write!(f, "'{}rv", region_vid.index)
+                }
+                ty::ReScope(_) |
+                ty::ReVar(_) |
+                ty::ReErased => Ok(()),
+                ty::ReStatic => write!(f, "'static"),
+                ty::ReEmpty => write!(f, "'<empty>"),
             }
+        }
+        debug {
+            match *self {
+                ty::ReEarlyBound(ref data) => {
+                    write!(f, "ReEarlyBound({}, {})",
+                           data.index,
+                           data.name)
+                }
 
-            ty::ReSkolemized(id, ref bound_region) => {
-                write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
-            }
+                ty::ReLateBound(binder_id, ref bound_region) => {
+                    write!(f, "ReLateBound({:?}, {:?})",
+                           binder_id,
+                           bound_region)
+                }
 
-            ty::ReEmpty => write!(f, "ReEmpty"),
+                ty::ReFree(ref fr) => write!(f, "{:?}", fr),
 
-            ty::ReErased => write!(f, "ReErased")
-        }
-    }
-}
+                ty::ReScope(id) => {
+                    write!(f, "ReScope({:?})", id)
+                }
 
-impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ClosureUpvar({:?},{:?})",
-               self.def,
-               self.ty)
-    }
-}
+                ty::ReStatic => write!(f, "ReStatic"),
 
-impl fmt::Display for ty::RegionKind {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if verbose() {
-            return write!(f, "{:?}", *self);
-        }
+                ty::ReVar(ref vid) => {
+                    write!(f, "{:?}", vid)
+                }
 
-        // These printouts are concise.  They do not contain all the information
-        // the user might want to diagnose an error, but there is basically no way
-        // to fit that into a short string.  Hence the recommendation to use
-        // `explain_region()` or `note_and_explain_region()`.
-        match *self {
-            ty::ReEarlyBound(ref data) => {
-                write!(f, "{}", data.name)
-            }
-            ty::ReLateBound(_, br) |
-            ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
-            ty::ReSkolemized(_, br) => {
-                write!(f, "{}", br)
-            }
-            ty::ReScope(scope) if identify_regions() => {
-                match scope.data() {
-                    region::ScopeData::Node(id) =>
-                        write!(f, "'{}s", id.as_usize()),
-                    region::ScopeData::CallSite(id) =>
-                        write!(f, "'{}cs", id.as_usize()),
-                    region::ScopeData::Arguments(id) =>
-                        write!(f, "'{}as", id.as_usize()),
-                    region::ScopeData::Destruction(id) =>
-                        write!(f, "'{}ds", id.as_usize()),
-                    region::ScopeData::Remainder(BlockRemainder { block, first_statement_index }) =>
-                        write!(f, "'{}_{}rs", block.as_usize(), first_statement_index.index()),
+                ty::ReSkolemized(id, ref bound_region) => {
+                    write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
                 }
+
+                ty::ReEmpty => write!(f, "ReEmpty"),
+
+                ty::ReErased => write!(f, "ReErased")
             }
-            ty::ReVar(region_vid) if identify_regions() => {
-                write!(f, "'{}rv", region_vid.index)
-            }
-            ty::ReScope(_) |
-            ty::ReVar(_) |
-            ty::ReErased => Ok(()),
-            ty::ReStatic => write!(f, "'static"),
-            ty::ReEmpty => write!(f, "'<empty>"),
         }
     }
 }
 
-impl fmt::Debug for ty::FreeRegion {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ReFree({:?}, {:?})",
-               self.scope, self.bound_region)
+define_print! {
+    () ty::FreeRegion, (self, f, cx) {
+        debug {
+            write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region)
+        }
     }
 }
 
-impl fmt::Debug for ty::Variance {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write_str(match *self {
-            ty::Covariant => "+",
-            ty::Contravariant => "-",
-            ty::Invariant => "o",
-            ty::Bivariant => "*",
-        })
+define_print! {
+    () ty::Variance, (self, f, cx) {
+        debug {
+            f.write_str(match *self {
+                ty::Covariant => "+",
+                ty::Contravariant => "-",
+                ty::Invariant => "o",
+                ty::Bivariant => "*",
+            })
+        }
     }
 }
 
-impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "GenericPredicates({:?})", self.predicates)
+define_print! {
+    ('tcx) ty::GenericPredicates<'tcx>, (self, f, cx) {
+        debug {
+            write!(f, "GenericPredicates({:?})", self.predicates)
+        }
     }
 }
 
-impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "InstantiatedPredicates({:?})",
-               self.predicates)
+define_print! {
+    ('tcx) ty::InstantiatedPredicates<'tcx>, (self, f, cx) {
+        debug {
+            write!(f, "InstantiatedPredicates({:?})", self.predicates)
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if self.unsafety == hir::Unsafety::Unsafe {
-            write!(f, "unsafe ")?;
-        }
+define_print! {
+    ('tcx) ty::FnSig<'tcx>, (self, f, cx) {
+        display {
+            if self.unsafety == hir::Unsafety::Unsafe {
+                write!(f, "unsafe ")?;
+            }
 
-        if self.abi != Abi::Rust {
-            write!(f, "extern {} ", self.abi)?;
-        }
+            if self.abi != Abi::Rust {
+                write!(f, "extern {} ", self.abi)?;
+            }
 
-        write!(f, "fn")?;
-        fn_sig(f, self.inputs(), self.variadic, self.output())
+            write!(f, "fn")?;
+            cx.fn_sig(f, self.inputs(), self.variadic, self.output())
+        }
+        debug {
+            write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output())
+        }
     }
 }
 
@@ -626,21 +854,27 @@ impl fmt::Debug for ty::RegionVid {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output())
-    }
-}
-
-impl fmt::Debug for ty::InferTy {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::TyVar(ref v) => v.fmt(f),
-            ty::IntVar(ref v) => v.fmt(f),
-            ty::FloatVar(ref v) => v.fmt(f),
-            ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
-            ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
-            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
+define_print! {
+    () ty::InferTy, (self, f, cx) {
+        display {
+            match *self {
+                ty::TyVar(_) => write!(f, "_"),
+                ty::IntVar(_) => write!(f, "{}", "{integer}"),
+                ty::FloatVar(_) => write!(f, "{}", "{float}"),
+                ty::FreshTy(v) => write!(f, "FreshTy({})", v),
+                ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+                ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
+            }
+        }
+        debug {
+            match *self {
+                ty::TyVar(ref v) => write!(f, "{:?}", v),
+                ty::IntVar(ref v) => write!(f, "{:?}", v),
+                ty::FloatVar(ref v) => write!(f, "{:?}", v),
+                ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
+                ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
+                ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
+            }
         }
     }
 }
@@ -665,406 +899,393 @@ impl fmt::Debug for ty::IntVarValue {
     }
 }*/
 
-impl<'tcx> fmt::Display for ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::TraitRef<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::FnSig<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::TraitPredicate<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::EquatePredicate<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::SubtypePredicate<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::ProjectionPredicate<'tcx>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
-    }
-}
-
-impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>,
-                                                             ty::Region<'tcx>>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
+define_print_multi! {
+    [
+    ('tcx) ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>,
+    ('tcx) ty::Binder<ty::TraitRef<'tcx>>,
+    ('tcx) ty::Binder<ty::FnSig<'tcx>>,
+    ('tcx) ty::Binder<ty::TraitPredicate<'tcx>>,
+    ('tcx) ty::Binder<ty::EquatePredicate<'tcx>>,
+    ('tcx) ty::Binder<ty::SubtypePredicate<'tcx>>,
+    ('tcx) ty::Binder<ty::ProjectionPredicate<'tcx>>,
+    ('tcx) ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
+    ('tcx) ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>
+    ]
+    (self, f, cx) {
+        display {
+            ty::tls::with(|tcx| cx.in_binder(f, tcx, self, tcx.lift(self)))
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::TraitRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        parameterized(f, self.substs, self.def_id, &[])
+define_print! {
+    ('tcx) ty::TraitRef<'tcx>, (self, f, cx) {
+        display {
+            cx.parameterized(f, self.substs, self.def_id, &[])
+        }
+        debug {
+            // when printing out the debug representation, we don't need
+            // to enumerate the `for<...>` etc because the debruijn index
+            // tells you everything you need to know.
+            print!(f, cx,
+                   write("<"),
+                   print(self.self_ty()),
+                   write(" as "))?;
+            cx.parameterized(f, self.substs, self.def_id, &[])?;
+            write!(f, ">")
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::GeneratorInterior<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.witness.fmt(f)
+define_print! {
+    ('tcx) ty::GeneratorInterior<'tcx>, (self, f, cx) {
+        display {
+            self.witness.print(f, cx)
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            TyBool => write!(f, "bool"),
-            TyChar => write!(f, "char"),
-            TyInt(t) => write!(f, "{}", t.ty_to_string()),
-            TyUint(t) => write!(f, "{}", t.ty_to_string()),
-            TyFloat(t) => write!(f, "{}", t.ty_to_string()),
-            TyRawPtr(ref tm) => {
-                write!(f, "*{} {}", match tm.mutbl {
-                    hir::MutMutable => "mut",
-                    hir::MutImmutable => "const",
-                },  tm.ty)
-            }
-            TyRef(r, ref tm) => {
-                write!(f, "&")?;
-                let s = r.to_string();
-                write!(f, "{}", s)?;
-                if !s.is_empty() {
-                    write!(f, " ")?;
+define_print! {
+    ('tcx) ty::TypeVariants<'tcx>, (self, f, cx) {
+        display {
+            match *self {
+                TyBool => write!(f, "bool"),
+                TyChar => write!(f, "char"),
+                TyInt(t) => write!(f, "{}", t.ty_to_string()),
+                TyUint(t) => write!(f, "{}", t.ty_to_string()),
+                TyFloat(t) => write!(f, "{}", t.ty_to_string()),
+                TyRawPtr(ref tm) => {
+                    write!(f, "*{} ", match tm.mutbl {
+                        hir::MutMutable => "mut",
+                        hir::MutImmutable => "const",
+                    })?;
+                    tm.ty.print(f, cx)
                 }
-                write!(f, "{}", tm)
-            }
-            TyNever => write!(f, "!"),
-            TyTuple(ref tys, _) => {
-                write!(f, "(")?;
-                let mut tys = tys.iter();
-                if let Some(&ty) = tys.next() {
-                    write!(f, "{},", ty)?;
+                TyRef(r, ref tm) => {
+                    write!(f, "&")?;
+                    let s = r.print_to_string(cx);
+                    write!(f, "{}", s)?;
+                    if !s.is_empty() {
+                        write!(f, " ")?;
+                    }
+                    tm.print(f, cx)
+                }
+                TyNever => write!(f, "!"),
+                TyTuple(ref tys, _) => {
+                    write!(f, "(")?;
+                    let mut tys = tys.iter();
                     if let Some(&ty) = tys.next() {
-                        write!(f, " {}", ty)?;
-                        for &ty in tys {
-                            write!(f, ", {}", ty)?;
+                        print!(f, cx, print(ty), write(","))?;
+                        if let Some(&ty) = tys.next() {
+                            print!(f, cx, write(" "), print(ty))?;
+                            for &ty in tys {
+                                print!(f, cx, write(", "), print(ty))?;
+                            }
                         }
                     }
+                    write!(f, ")")
                 }
-                write!(f, ")")
-            }
-            TyFnDef(def_id, substs) => {
-                ty::tls::with(|tcx| {
-                    let mut sig = tcx.fn_sig(def_id);
-                    if let Some(substs) = tcx.lift(&substs) {
-                        sig = sig.subst(tcx, substs);
+                TyFnDef(def_id, substs) => {
+                    ty::tls::with(|tcx| {
+                        let mut sig = tcx.fn_sig(def_id);
+                        if let Some(substs) = tcx.lift(&substs) {
+                            sig = sig.subst(tcx, substs);
+                        }
+                        print!(f, cx, print(sig), write(" {{"))
+                    })?;
+                    cx.parameterized(f, substs, def_id, &[])?;
+                    write!(f, "}}")
+                }
+                TyFnPtr(ref bare_fn) => {
+                    bare_fn.print(f, cx)
+                }
+                TyInfer(infer_ty) => write!(f, "{}", infer_ty),
+                TyError => write!(f, "[type error]"),
+                TyParam(ref param_ty) => write!(f, "{}", param_ty),
+                TyAdt(def, substs) => cx.parameterized(f, substs, def.did, &[]),
+                TyDynamic(data, r) => {
+                    data.print(f, cx)?;
+                    let r = r.print_to_string(cx);
+                    if !r.is_empty() {
+                        write!(f, " + {}", r)
+                    } else {
+                        Ok(())
                     }
-                    write!(f, "{} {{", sig.0)
-                })?;
-                parameterized(f, substs, def_id, &[])?;
-                write!(f, "}}")
-            }
-            TyFnPtr(ref bare_fn) => {
-                write!(f, "{}", bare_fn.0)
-            }
-            TyInfer(infer_ty) => write!(f, "{}", infer_ty),
-            TyError => write!(f, "[type error]"),
-            TyParam(ref param_ty) => write!(f, "{}", param_ty),
-            TyAdt(def, substs) => parameterized(f, substs, def.did, &[]),
-            TyDynamic(data, r) => {
-                write!(f, "{}", data)?;
-                let r = r.to_string();
-                if !r.is_empty() {
-                    write!(f, " + {}", r)
-                } else {
-                    Ok(())
                 }
-            }
-            TyProjection(ref data) => write!(f, "{}", data),
-            TyAnon(def_id, substs) => {
-                ty::tls::with(|tcx| {
-                    // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
-                    // by looking up the projections associated with the def_id.
-                    let predicates_of = tcx.predicates_of(def_id);
-                    let substs = tcx.lift(&substs).unwrap_or_else(|| {
-                        tcx.intern_substs(&[])
-                    });
-                    let bounds = predicates_of.instantiate(tcx, substs);
-
-                    let mut first = true;
-                    let mut is_sized = false;
-                    write!(f, "impl")?;
-                    for predicate in bounds.predicates {
-                        if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
-                            // Don't print +Sized, but rather +?Sized if absent.
-                            if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
-                                is_sized = true;
-                                continue;
+                TyProjection(ref data) => data.print(f, cx),
+                TyAnon(def_id, substs) => {
+                    ty::tls::with(|tcx| {
+                        // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
+                        // by looking up the projections associated with the def_id.
+                        let predicates_of = tcx.predicates_of(def_id);
+                        let substs = tcx.lift(&substs).unwrap_or_else(|| {
+                            tcx.intern_substs(&[])
+                        });
+                        let bounds = predicates_of.instantiate(tcx, substs);
+
+                        let mut first = true;
+                        let mut is_sized = false;
+                        write!(f, "impl")?;
+                        for predicate in bounds.predicates {
+                            if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
+                                // Don't print +Sized, but rather +?Sized if absent.
+                                if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
+                                    is_sized = true;
+                                    continue;
+                                }
+
+                                print!(f, cx,
+                                       write("{}", if first { " " } else { "+" }),
+                                       print(trait_ref))?;
+                                first = false;
                             }
-
-                            write!(f, "{}{}", if first { " " } else { "+" }, trait_ref)?;
-                            first = false;
                         }
-                    }
-                    if !is_sized {
-                        write!(f, "{}?Sized", if first { " " } else { "+" })?;
-                    }
-                    Ok(())
-                })
-            }
-            TyStr => write!(f, "str"),
-            TyGenerator(did, substs, interior) => ty::tls::with(|tcx| {
-                let upvar_tys = substs.upvar_tys(did, tcx);
-                write!(f, "[generator")?;
-
-                if let Some(node_id) = tcx.hir.as_local_node_id(did) {
-                    write!(f, "@{:?}", tcx.hir.span(node_id))?;
-                    let mut sep = " ";
-                    tcx.with_freevars(node_id, |freevars| {
-                        for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) {
-                            write!(f,
-                                        "{}{}:{}",
-                                        sep,
-                                        tcx.hir.name(freevar.var_id()),
-                                        upvar_ty)?;
-                            sep = ", ";
+                        if !is_sized {
+                            write!(f, "{}?Sized", if first { " " } else { "+" })?;
                         }
                         Ok(())
-                    })?
-                } else {
-                    // cross-crate closure types should only be
-                    // visible in trans bug reports, I imagine.
-                    write!(f, "@{:?}", did)?;
-                    let mut sep = " ";
-                    for (index, upvar_ty) in upvar_tys.enumerate() {
-                        write!(f, "{}{}:{}", sep, index, upvar_ty)?;
-                        sep = ", ";
-                    }
+                    })
                 }
+                TyStr => write!(f, "str"),
+                TyGenerator(did, substs, interior) => ty::tls::with(|tcx| {
+                    let upvar_tys = substs.upvar_tys(did, tcx);
+                    write!(f, "[generator")?;
 
-                write!(f, " {}", interior)?;
-
-                write!(f, "]")
-            }),
-            TyClosure(did, substs) => ty::tls::with(|tcx| {
-                let upvar_tys = substs.upvar_tys(did, tcx);
-                write!(f, "[closure")?;
-
-                if let Some(node_id) = tcx.hir.as_local_node_id(did) {
-                    if tcx.sess.opts.debugging_opts.span_free_formats {
-                        write!(f, "@{:?}", node_id)?;
-                    } else {
+                    if let Some(node_id) = tcx.hir.as_local_node_id(did) {
                         write!(f, "@{:?}", tcx.hir.span(node_id))?;
-                    }
-                    let mut sep = " ";
-                    tcx.with_freevars(node_id, |freevars| {
-                        for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) {
-                            write!(f,
-                                        "{}{}:{}",
-                                        sep,
-                                        tcx.hir.name(freevar.var_id()),
-                                        upvar_ty)?;
+                        let mut sep = " ";
+                        tcx.with_freevars(node_id, |freevars| {
+                            for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) {
+                                print!(f, cx,
+                                       write("{}{}:",
+                                             sep,
+                                             tcx.hir.name(freevar.var_id())),
+                                       print(upvar_ty))?;
+                                sep = ", ";
+                            }
+                            Ok(())
+                        })?
+                    } else {
+                        // cross-crate closure types should only be
+                        // visible in trans bug reports, I imagine.
+                        write!(f, "@{:?}", did)?;
+                        let mut sep = " ";
+                        for (index, upvar_ty) in upvar_tys.enumerate() {
+                            print!(f, cx,
+                                   write("{}{}:", sep, index),
+                                   print(upvar_ty))?;
                             sep = ", ";
                         }
-                        Ok(())
-                    })?
-                } else {
-                    // cross-crate closure types should only be
-                    // visible in trans bug reports, I imagine.
-                    write!(f, "@{:?}", did)?;
-                    let mut sep = " ";
-                    for (index, upvar_ty) in upvar_tys.enumerate() {
-                        write!(f, "{}{}:{}", sep, index, upvar_ty)?;
-                        sep = ", ";
                     }
-                }
 
-                write!(f, "]")
-            }),
-            TyArray(ty, sz) => {
-                write!(f, "[{}; ", ty)?;
-                match sz.val {
-                    ConstVal::Integral(ConstInt::Usize(sz)) => {
-                        write!(f, "{}", sz)?;
-                    }
-                    ConstVal::Unevaluated(_def_id, substs) => {
-                        write!(f, "<unevaluated{:?}>", &substs[..])?;
+                    print!(f, cx, write(" "), print(interior), write("]"))
+                }),
+                TyClosure(did, substs) => ty::tls::with(|tcx| {
+                    let upvar_tys = substs.upvar_tys(did, tcx);
+                    write!(f, "[closure")?;
+
+                    if let Some(node_id) = tcx.hir.as_local_node_id(did) {
+                        if tcx.sess.opts.debugging_opts.span_free_formats {
+                            write!(f, "@{:?}", node_id)?;
+                        } else {
+                            write!(f, "@{:?}", tcx.hir.span(node_id))?;
+                        }
+                        let mut sep = " ";
+                        tcx.with_freevars(node_id, |freevars| {
+                            for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) {
+                                print!(f, cx,
+                                       write("{}{}:",
+                                             sep,
+                                             tcx.hir.name(freevar.var_id())),
+                                       print(upvar_ty))?;
+                                sep = ", ";
+                            }
+                            Ok(())
+                        })?
+                    } else {
+                        // cross-crate closure types should only be
+                        // visible in trans bug reports, I imagine.
+                        write!(f, "@{:?}", did)?;
+                        let mut sep = " ";
+                        for (index, upvar_ty) in upvar_tys.enumerate() {
+                            print!(f, cx,
+                                   write("{}{}:", sep, index),
+                                   print(upvar_ty))?;
+                            sep = ", ";
+                        }
                     }
-                    _ => {
-                        write!(f, "{:?}", sz)?;
+
+                    write!(f, "]")
+                }),
+                TyArray(ty, sz) => {
+                    print!(f, cx, write("["), print(ty), write("; "))?;
+                    match sz.val {
+                        ConstVal::Integral(ConstInt::Usize(sz)) => {
+                            write!(f, "{}", sz)?;
+                        }
+                        ConstVal::Unevaluated(_def_id, substs) => {
+                            write!(f, "<unevaluated{:?}>", &substs[..])?;
+                        }
+                        _ => {
+                            write!(f, "{:?}", sz)?;
+                        }
                     }
+                    write!(f, "]")
+                }
+                TySlice(ty) => {
+                    print!(f, cx, write("["), print(ty), write("]"))
                 }
-                write!(f, "]")
             }
-            TySlice(ty) => write!(f, "[{}]",  ty)
         }
     }
 }
 
-impl<'tcx> fmt::Display for ty::TyS<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.sty)
-    }
-}
-
-impl fmt::Debug for ty::UpvarId {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "UpvarId({:?};`{}`;{:?})",
-               self.var_id,
-               ty::tls::with(|tcx| tcx.hir.name(tcx.hir.hir_to_node_id(self.var_id))),
-               self.closure_expr_id)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "UpvarBorrow({:?}, {:?})",
-               self.kind, self.region)
-    }
-}
-
-impl fmt::Display for ty::InferTy {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let print_var_ids = verbose();
-        match *self {
-            ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
-            ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
-            ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
-            ty::TyVar(_) => write!(f, "_"),
-            ty::IntVar(_) => write!(f, "{}", "{integer}"),
-            ty::FloatVar(_) => write!(f, "{}", "{float}"),
-            ty::FreshTy(v) => write!(f, "FreshTy({})", v),
-            ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
-            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
+define_print! {
+    ('tcx) ty::TyS<'tcx>, (self, f, cx) {
+        display {
+            self.sty.print(f, cx)
+        }
+        debug {
+            self.sty.print_display(f, cx)
         }
     }
 }
 
-impl fmt::Display for ty::ParamTy {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.name)
-    }
-}
-
-impl fmt::Debug for ty::ParamTy {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}/#{}", self, self.idx)
-    }
-}
-
-impl<'tcx, T, U> fmt::Display for ty::OutlivesPredicate<T,U>
-    where T: fmt::Display, U: fmt::Display
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{} : {}", self.0, self.1)
-    }
-}
-
-impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{} == {}", self.0, self.1)
+define_print! {
+    () ty::ParamTy, (self, f, cx) {
+        display {
+            write!(f, "{}", self.name)
+        }
+        debug {
+            write!(f, "{}/#{}", self.name, self.idx)
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{} <: {}", self.a, self.b)
+define_print! {
+    ('tcx, T: Print + fmt::Debug, U: Print + fmt::Debug) ty::OutlivesPredicate<T, U>,
+    (self, f, cx) {
+        display {
+            print!(f, cx, print(self.0), write(" : "), print(self.1))
+        }
     }
 }
 
-impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TraitPredicate({:?})",
-               self.trait_ref)
+define_print! {
+    ('tcx) ty::EquatePredicate<'tcx>, (self, f, cx) {
+        display {
+            print!(f, cx, print(self.0), write(" == "), print(self.1))
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::TraitPredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}: {}", self.trait_ref.self_ty(), self.trait_ref)
+define_print! {
+    ('tcx) ty::SubtypePredicate<'tcx>, (self, f, cx) {
+        display {
+            print!(f, cx, print(self.a), write(" <: "), print(self.b))
+        }
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "ProjectionPredicate({:?}, {:?})",
-               self.projection_ty,
-               self.ty)
+define_print! {
+    ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) {
+        debug {
+            write!(f, "TraitPredicate({:?})",
+                   self.trait_ref)
+        }
+        display {
+            print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::ProjectionPredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{} == {}",
-               self.projection_ty,
-               self.ty)
+define_print! {
+    ('tcx) ty::ProjectionPredicate<'tcx>, (self, f, cx) {
+        debug {
+            print!(f, cx,
+                   write("ProjectionPredicate("),
+                   print(self.projection_ty),
+                   write(", "),
+                   print(self.ty),
+                   write(")"))
+        }
+        display {
+            print!(f, cx, print(self.projection_ty), write(" == "), print(self.ty))
+        }
     }
 }
 
-impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // FIXME(tschottdorf): use something like
-        //   parameterized(f, self.substs, self.item_def_id, &[])
-        // (which currently ICEs).
-        let (trait_ref, item_name) = ty::tls::with(|tcx|
-            (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name)
-        );
-        write!(f, "{:?}::{}",
-               trait_ref,
-               item_name)
+define_print! {
+    ('tcx) ty::ProjectionTy<'tcx>, (self, f, cx) {
+        display {
+            // FIXME(tschottdorf): use something like
+            //   parameterized(f, self.substs, self.item_def_id, &[])
+            // (which currently ICEs).
+            let (trait_ref, item_name) = ty::tls::with(|tcx|
+                (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name)
+            );
+            print!(f, cx, print_debug(trait_ref), write("::{}", item_name))
+        }
     }
 }
 
-impl fmt::Display for ty::ClosureKind {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::ClosureKind::Fn => write!(f, "Fn"),
-            ty::ClosureKind::FnMut => write!(f, "FnMut"),
-            ty::ClosureKind::FnOnce => write!(f, "FnOnce"),
+define_print! {
+    () ty::ClosureKind, (self, f, cx) {
+        display {
+            match *self {
+                ty::ClosureKind::Fn => write!(f, "Fn"),
+                ty::ClosureKind::FnMut => write!(f, "FnMut"),
+                ty::ClosureKind::FnOnce => write!(f, "FnOnce"),
+            }
         }
     }
 }
 
-impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            ty::Predicate::Trait(ref data) => write!(f, "{}", data),
-            ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate),
-            ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate),
-            ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate),
-            ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate),
-            ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate),
-            ty::Predicate::WellFormed(ty) => write!(f, "{} well-formed", ty),
-            ty::Predicate::ObjectSafe(trait_def_id) =>
-                ty::tls::with(|tcx| {
-                    write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id))
-                }),
-            ty::Predicate::ClosureKind(closure_def_id, kind) =>
-                ty::tls::with(|tcx| {
-                    write!(f, "the closure `{}` implements the trait `{}`",
-                           tcx.item_path_str(closure_def_id), kind)
-                }),
-            ty::Predicate::ConstEvaluatable(def_id, substs) => {
-                write!(f, "the constant `")?;
-                parameterized(f, substs, def_id, &[])?;
-                write!(f, "` can be evaluated")
+define_print! {
+    ('tcx) ty::Predicate<'tcx>, (self, f, cx) {
+        display {
+            match *self {
+                ty::Predicate::Trait(ref data) => data.print(f, cx),
+                ty::Predicate::Equate(ref predicate) => predicate.print(f, cx),
+                ty::Predicate::Subtype(ref predicate) => predicate.print(f, cx),
+                ty::Predicate::RegionOutlives(ref predicate) => predicate.print(f, cx),
+                ty::Predicate::TypeOutlives(ref predicate) => predicate.print(f, cx),
+                ty::Predicate::Projection(ref predicate) => predicate.print(f, cx),
+                ty::Predicate::WellFormed(ty) => print!(f, cx, print(ty), write(" well-formed")),
+                ty::Predicate::ObjectSafe(trait_def_id) =>
+                    ty::tls::with(|tcx| {
+                        write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id))
+                    }),
+                ty::Predicate::ClosureKind(closure_def_id, kind) =>
+                    ty::tls::with(|tcx| {
+                        write!(f, "the closure `{}` implements the trait `{}`",
+                               tcx.item_path_str(closure_def_id), kind)
+                    }),
+                ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                    write!(f, "the constant `")?;
+                    cx.parameterized(f, substs, def_id, &[])?;
+                    write!(f, "` can be evaluated")
+                }
+            }
+        }
+        debug {
+            match *self {
+                ty::Predicate::Trait(ref a) => a.print(f, cx),
+                ty::Predicate::Equate(ref pair) => pair.print(f, cx),
+                ty::Predicate::Subtype(ref pair) => pair.print(f, cx),
+                ty::Predicate::RegionOutlives(ref pair) => pair.print(f, cx),
+                ty::Predicate::TypeOutlives(ref pair) => pair.print(f, cx),
+                ty::Predicate::Projection(ref pair) => pair.print(f, cx),
+                ty::Predicate::WellFormed(ty) => ty.print(f, cx),
+                ty::Predicate::ObjectSafe(trait_def_id) => {
+                    write!(f, "ObjectSafe({:?})", trait_def_id)
+                }
+                ty::Predicate::ClosureKind(closure_def_id, kind) => {
+                    write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
+                }
+                ty::Predicate::ConstEvaluatable(def_id, substs) => {
+                    write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
+                }
             }
         }
     }
diff --git a/src/librustc_back/build.rs b/src/librustc_back/build.rs
index 16f0872b25a..6f6fde1e9e7 100644
--- a/src/librustc_back/build.rs
+++ b/src/librustc_back/build.rs
@@ -11,5 +11,4 @@
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
     println!("cargo:rerun-if-env-changed=CFG_DEFAULT_LINKER");
-    println!("cargo:rerun-if-env-changed=CFG_DEFAULT_AR");
 }
diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs
index e93a9a788a4..ba21b1df032 100644
--- a/src/librustc_back/target/arm_linux_androideabi.rs
+++ b/src/librustc_back/target/arm_linux_androideabi.rs
@@ -14,7 +14,7 @@ use target::{Target, TargetOptions, TargetResult};
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
     // https://developer.android.com/ndk/guides/abis.html#armeabi
-    base.features = "+v5te".to_string();
+    base.features = "+strict-align,+v5te".to_string();
     base.max_atomic_width = Some(64);
 
     Ok(Target {
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
index b9f40accaeb..e630376a67d 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
@@ -27,7 +27,7 @@ pub fn target() -> TargetResult {
         linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
-            features: "+v6".to_string(),
+            features: "+strict-align,+v6".to_string(),
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         },
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
index a3ea69caec6..178a948b2b9 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
@@ -27,7 +27,7 @@ pub fn target() -> TargetResult {
         linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
-            features: "+v6,+vfp2".to_string(),
+            features: "+strict-align,+v6,+vfp2".to_string(),
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs
index 598f722d9af..29720ec5efc 100644
--- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabi
     // target.
-    base.features = "+v6".to_string();
+    base.features = "+strict-align,+v6".to_string();
     base.max_atomic_width = Some(64);
     Ok(Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
index ea0bf75b103..fc8313877f6 100644
--- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabihf
     // target.
-    base.features = "+v6,+vfp2".to_string();
+    base.features = "+strict-align,+v6,+vfp2".to_string();
     base.max_atomic_width = Some(64);
     Ok(Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
index b9573721678..97397ca4962 100644
--- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs
@@ -27,8 +27,12 @@ pub fn target() -> TargetResult {
 
         options: TargetOptions {
             features: "+soft-float,+strict-align".to_string(),
-            // No atomic instructions on ARMv5
-            max_atomic_width: Some(0),
+
+            // Atomic operations provided when linked with libgcc.
+            // FIXME: If the following PR is merged, the atomic operations would be
+            // provided by compiler-builtins instead with no change of behavior:
+            // https://github.com/rust-lang-nursery/compiler-builtins/pull/115/files
+            max_atomic_width: Some(32),
             abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs
index 033e840f202..a54627279b0 100644
--- a/src/librustc_back/target/asmjs_unknown_emscripten.rs
+++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs
@@ -20,7 +20,6 @@ pub fn target() -> Result<Target, String> {
 
     let opts = TargetOptions {
         linker: cmd("emcc"),
-        ar: cmd("emar"),
 
         dynamic_linking: false,
         executables: true,
diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs
deleted file mode 100644
index 9af4606f1f1..00000000000
--- a/src/librustc_back/target/le32_unknown_nacl.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use LinkerFlavor;
-use super::{LinkArgs, Target, TargetOptions, TargetResult};
-
-pub fn target() -> TargetResult {
-    let mut pre_link_args = LinkArgs::new();
-    pre_link_args.insert(LinkerFlavor::Gcc,
-                         vec!["--pnacl-exceptions=sjlj".to_string(),
-                              "--target=le32-unknown-nacl".to_string(),
-                              "-Wl,--start-group".to_string()]);
-    let mut post_link_args = LinkArgs::new();
-    post_link_args.insert(LinkerFlavor::Gcc,
-                          vec!["-Wl,--end-group".to_string()]);
-
-    let opts = TargetOptions {
-        linker: "pnacl-clang".to_string(),
-        ar: "pnacl-ar".to_string(),
-
-        pre_link_args,
-        post_link_args,
-        dynamic_linking: false,
-        executables: true,
-        exe_suffix: ".pexe".to_string(),
-        linker_is_gnu: true,
-        allow_asm: false,
-        max_atomic_width: Some(32),
-        .. Default::default()
-    };
-    Ok(Target {
-        llvm_target: "le32-unknown-nacl".to_string(),
-        target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
-        target_c_int_width: "32".to_string(),
-        target_os: "nacl".to_string(),
-        target_env: "newlib".to_string(),
-        target_vendor: "unknown".to_string(),
-        data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(),
-        arch: "le32".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: opts,
-    })
-}
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index b1b208d2de4..a56d0678158 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -135,6 +135,7 @@ macro_rules! supported_targets {
 
 supported_targets! {
     ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu),
+    ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
     ("i686-unknown-linux-gnu", i686_unknown_linux_gnu),
     ("i586-unknown-linux-gnu", i586_unknown_linux_gnu),
     ("mips-unknown-linux-gnu", mips_unknown_linux_gnu),
@@ -215,7 +216,6 @@ supported_targets! {
     ("i686-pc-windows-msvc", i686_pc_windows_msvc),
     ("i586-pc-windows-msvc", i586_pc_windows_msvc),
 
-    ("le32-unknown-nacl", le32_unknown_nacl),
     ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-experimental-emscripten", wasm32_experimental_emscripten),
@@ -269,8 +269,6 @@ pub struct TargetOptions {
 
     /// Linker to invoke. Defaults to "cc".
     pub linker: String,
-    /// Archive utility to use when managing archives. Defaults to "ar".
-    pub ar: String,
 
     /// Linker arguments that are unconditionally passed *before* any
     /// user-defined libraries.
@@ -431,6 +429,9 @@ pub struct TargetOptions {
 
     /// The minimum alignment for global symbols.
     pub min_global_align: Option<u64>,
+
+    /// Default number of codegen units to use in debug mode
+    pub default_codegen_units: Option<u64>,
 }
 
 impl Default for TargetOptions {
@@ -440,7 +441,6 @@ impl Default for TargetOptions {
         TargetOptions {
             is_builtin: false,
             linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(),
-            ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(),
             pre_link_args: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             asm_args: Vec::new(),
@@ -493,6 +493,7 @@ impl Default for TargetOptions {
             crt_static_respected: false,
             stack_probes: false,
             min_global_align: None,
+            default_codegen_units: None,
         }
     }
 }
@@ -681,7 +682,6 @@ impl Target {
 
         key!(is_builtin, bool);
         key!(linker);
-        key!(ar);
         key!(pre_link_args, link_args);
         key!(pre_link_objects_exe, list);
         key!(pre_link_objects_dll, list);
@@ -733,6 +733,7 @@ impl Target {
         key!(crt_static_respected, bool);
         key!(stack_probes, bool);
         key!(min_global_align, Option<u64>);
+        key!(default_codegen_units, Option<u64>);
 
         if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
             for name in array.iter().filter_map(|abi| abi.as_string()) {
@@ -873,7 +874,6 @@ impl ToJson for Target {
 
         target_option_val!(is_builtin);
         target_option_val!(linker);
-        target_option_val!(ar);
         target_option_val!(link_args - pre_link_args);
         target_option_val!(pre_link_objects_exe);
         target_option_val!(pre_link_objects_dll);
@@ -925,6 +925,7 @@ impl ToJson for Target {
         target_option_val!(crt_static_respected);
         target_option_val!(stack_probes);
         target_option_val!(min_global_align);
+        target_option_val!(default_codegen_units);
 
         if default.abi_blacklist != self.options.abi_blacklist {
             d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_back/target/msp430_none_elf.rs
index 9227a96e750..509a7cf5e03 100644
--- a/src/librustc_back/target/msp430_none_elf.rs
+++ b/src/librustc_back/target/msp430_none_elf.rs
@@ -48,6 +48,11 @@ pub fn target() -> TargetResult {
             // code because of the extra costs it involves.
             relocation_model: "static".to_string(),
 
+            // Right now we invoke an external assembler and this isn't
+            // compatible with multiple codegen units, and plus we probably
+            // don't want to invoke that many gcc instances.
+            default_codegen_units: Some(1),
+
             .. Default::default( )
         }
     })
diff --git a/src/librustc_back/target/wasm32_experimental_emscripten.rs b/src/librustc_back/target/wasm32_experimental_emscripten.rs
index 71668444d9a..a261c982b3f 100644
--- a/src/librustc_back/target/wasm32_experimental_emscripten.rs
+++ b/src/librustc_back/target/wasm32_experimental_emscripten.rs
@@ -25,7 +25,6 @@ pub fn target() -> Result<Target, String> {
 
     let opts = TargetOptions {
         linker: cmd("emcc"),
-        ar: cmd("emar"),
 
         dynamic_linking: false,
         executables: true,
diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs
index e6584addf4a..197c1f7a4da 100644
--- a/src/librustc_back/target/wasm32_unknown_emscripten.rs
+++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs
@@ -22,7 +22,6 @@ pub fn target() -> Result<Target, String> {
 
     let opts = TargetOptions {
         linker: cmd("emcc"),
-        ar: cmd("emar"),
 
         dynamic_linking: false,
         executables: true,
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index 42a4e6f5f11..64df6624dd1 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -21,37 +21,6 @@ pub fn opts() -> TargetOptions {
     TargetOptions {
         function_sections: true,
         linker: "link.exe".to_string(),
-        // When taking a look at the value of this `ar` field, one might expect
-        // `lib.exe` to be the value here! The `lib.exe` program is the default
-        // tool for managing `.lib` archives on Windows, but unfortunately the
-        // compiler cannot use it.
-        //
-        // To recap, we use `ar` here to manage rlibs (which are just archives).
-        // LLVM does not expose bindings for modifying archives so we have to
-        // invoke this utility for write operations (e.g. deleting files, adding
-        // files, etc). Normally archives only have object files within them,
-        // but the compiler also uses archives for storing metadata and
-        // compressed bytecode, so we don't exactly fall within "normal use
-        // cases".
-        //
-        // MSVC's `lib.exe` tool by default will choke when adding a non-object
-        // file to an archive, which we do on a regular basis, making it
-        // inoperable for us. Luckily, however, LLVM has already rewritten `ar`
-        // in the form of `llvm-ar` which is built by default when we build
-        // LLVM. This tool, unlike `lib.exe`, works just fine with non-object
-        // files, so we use it instead.
-        //
-        // Note that there's a few caveats associated with this:
-        //
-        // * This still requires that the *linker* (the consumer of rlibs) will
-        //   ignore non-object files. Thankfully `link.exe` on Windows does
-        //   indeed ignore non-object files in archives.
-        // * This requires `llvm-ar.exe` to be distributed with the compiler
-        //   itself, but we already make sure of this elsewhere.
-        //
-        // Perhaps one day we won't even need this tool at all and we'll just be
-        // able to make library calls into LLVM!
-        ar: "llvm-ar.exe".to_string(),
         dynamic_linking: true,
         executables: true,
         dll_prefix: "".to_string(),
diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
index ab5a6f71ebc..18f6380b6ee 100644
--- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs
+++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs
@@ -16,7 +16,6 @@ pub fn target() -> TargetResult {
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
-    base.ar = "x86_64-rumprun-netbsd-ar".to_string();
     base.max_atomic_width = Some(64);
 
     base.dynamic_linking = false;
diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs b/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs
new file mode 100644
index 00000000000..70382032836
--- /dev/null
+++ b/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs
@@ -0,0 +1,35 @@
+// 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 LinkerFlavor;
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::linux_base::opts();
+    base.cpu = "x86-64".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
+    base.stack_probes = true;
+    base.has_elf_tls = false;
+
+    Ok(Target {
+        llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}
diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml
index 25f02537490..4c09a9e003d 100644
--- a/src/librustc_borrowck/Cargo.toml
+++ b/src/librustc_borrowck/Cargo.toml
@@ -15,5 +15,6 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 graphviz = { path = "../libgraphviz" }
 rustc = { path = "../librustc" }
+rustc_back = { path = "../librustc_back" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md
index 034b7cbadd9..b877c5a9cbc 100644
--- a/src/librustc_borrowck/borrowck/README.md
+++ b/src/librustc_borrowck/borrowck/README.md
@@ -781,8 +781,9 @@ the base path, it will still be considered freezable.
 
 
 
-**FIXME #10520: Restrictions against mutating the base pointer.** When
-an `&mut` pointer is frozen or claimed, we currently pass along the
+**FIXME [RFC 1751](https://github.com/rust-lang/rfcs/issues/1751)
+Restrictions against mutating the base pointer.**
+When an `&mut` pointer is frozen or claimed, we currently pass along the
 restriction against MUTATE to the base pointer. I do not believe this
 restriction is needed. It dates from the days when we had a way to
 mutate that preserved the value being mutated (i.e., swap). Nowadays
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index fea662e21fa..6fd9ff4012e 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -206,7 +206,13 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         all_loans,
         param_env,
     };
-    euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, param_env, &bccx.region_scope_tree, bccx.tables)
+    let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
+    euv::ExprUseVisitor::new(&mut clcx,
+                             bccx.tcx,
+                             param_env,
+                             &bccx.region_scope_tree,
+                             bccx.tables,
+                             Some(rvalue_promotable_map))
         .consume_body(body);
 }
 
@@ -659,7 +665,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={:?})",
                id, use_kind, lp);
 
-        // FIXME (22079): if you find yourself tempted to cut and paste
+        // FIXME: if you find yourself tempted to cut and paste
         // the body below and then specializing the error reporting,
         // consider refactoring this instead!
 
@@ -720,7 +726,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                         // the path must be initialized to prevent a case of
                         // partial reinitialization
                         //
-                        // FIXME (22079): could refactor via hypothetical
+                        // FIXME: could refactor via hypothetical
                         // generalized check_if_path_is_moved
                         let loan_path = owned_ptr_base_path_rc(lp_base);
                         self.move_data.each_move_of(id, &loan_path, |_, _| {
@@ -770,7 +776,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             let lp = opt_loan_path(&assignee_cmt).unwrap();
             self.move_data.each_assignment_of(assignment_id, &lp, |assign| {
                 if assignee_cmt.mutbl.is_mutable() {
-                    self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+                    let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id);
+                    self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
                 } else {
                     self.bccx.report_reassigned_immutable_variable(
                         assignment_span,
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index a58b62ba2a7..8654f2a50e4 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -48,7 +48,13 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
 
-    euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_scope_tree, bccx.tables)
+    let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
+    euv::ExprUseVisitor::new(&mut glcx,
+                             bccx.tcx,
+                             param_env,
+                             &bccx.region_scope_tree,
+                             bccx.tables,
+                             Some(rvalue_promotable_map))
         .consume_body(bccx.body);
 
     glcx.report_potential_errors();
@@ -406,7 +412,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
         self.all_loans.push(loan);
 
         // if loan_gen_scope != borrow_id {
-            // FIXME(#6268) Nested method calls
+            // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
             //
             // Typically, the scope of the loan includes the point at
             // which the loan is originated. This
@@ -417,9 +423,8 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
             //let restr = restrictions::compute_restrictions(
             //    self.bccx, borrow_span, cmt, RESTR_EMPTY);
             //let loan = {
-            //    let all_loans = &mut *self.all_loans; // FIXME(#5074)
             //    Loan {
-            //        index: all_loans.len(),
+            //        index: self.all_loans.len(),
             //        loan_path,
             //        cmt,
             //        mutbl: ConstMutability,
@@ -442,13 +447,13 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
             wrapped_path = match current_path.kind {
                 LpVar(local_id) => {
                     if !through_borrow {
-                        self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+                        let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id);
+                        self.bccx.used_mut_nodes.borrow_mut().insert(hir_id);
                     }
                     None
                 }
                 LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => {
-                    let local_id = self.tcx().hir.hir_to_node_id(var_id);
-                    self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
+                    self.bccx.used_mut_nodes.borrow_mut().insert(var_id);
                     None
                 }
                 LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) |
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index de3f6f08325..1f2b917bdb9 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -14,6 +14,7 @@ use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::NoteClosureEnv;
 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
 use rustc::ty;
+use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
 use syntax::ast;
 use syntax_pos;
 use errors::DiagnosticBuilder;
@@ -134,7 +135,7 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec<MoveError<'tcx>>)
 }
 
 // (keep in sync with gather_moves::check_and_get_illegal_move_origin )
-fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
+fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
                                        move_from: mc::cmt<'tcx>)
                                        -> DiagnosticBuilder<'a> {
     match move_from.cat {
@@ -142,43 +143,21 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         Categorization::Deref(_, mc::Implicit(..)) |
         Categorization::Deref(_, mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
-            let mut err = struct_span_err!(bccx, move_from.span, E0507,
-                             "cannot move out of {}",
-                             move_from.descriptive_string(bccx.tcx));
-            err.span_label(
-                move_from.span,
-                format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
-                );
-            err
+            bccx.cannot_move_out_of(
+                move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast)
         }
-
         Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
-            let type_name = match (&b.ty.sty, ik) {
-                (&ty::TyArray(_, _), Kind::Index) => "array",
-                (&ty::TySlice(_), _) => "slice",
-                _ => {
-                    span_bug!(move_from.span, "this path should not cause illegal move");
-                },
-            };
-            let mut err = struct_span_err!(bccx, move_from.span, E0508,
-                                           "cannot move out of type `{}`, \
-                                            a non-copy {}",
-                                           b.ty, type_name);
-            err.span_label(move_from.span, "cannot move out of here");
-            err
+            bccx.cannot_move_out_of_interior_noncopy(
+                move_from.span, b.ty, ik == Kind::Index, Origin::Ast)
         }
 
         Categorization::Downcast(ref b, _) |
         Categorization::Interior(ref b, mc::InteriorField(_)) => {
             match b.ty.sty {
                 ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
-                    let mut err = struct_span_err!(bccx, move_from.span, E0509,
-                                                   "cannot move out of type `{}`, \
-                                                   which implements the `Drop` trait",
-                                                   b.ty);
-                    err.span_label(move_from.span, "cannot move out of here");
-                    err
-                },
+                    bccx.cannot_move_out_of_interior_of_drop(
+                        move_from.span, b.ty, Origin::Ast)
+                }
                 _ => {
                     span_bug!(move_from.span, "this path should not cause illegal move");
                 }
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index a3f1340d429..d29250ac57c 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -20,6 +20,7 @@ pub use self::MovedValueUseKind::*;
 
 use self::InteriorKind::*;
 
+use rustc::hir::HirId;
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::cfg;
@@ -27,6 +28,7 @@ use rustc::middle::dataflow::DataFlowContext;
 use rustc::middle::dataflow::BitwiseOperator;
 use rustc::middle::dataflow::DataFlowOperator;
 use rustc::middle::dataflow::KillFrom;
+use rustc::middle::borrowck::BorrowCheckResult;
 use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
@@ -37,7 +39,9 @@ use rustc::middle::free_region::RegionRelations;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
 use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
+use rustc::util::nodemap::FxHashSet;
 
+use std::cell::RefCell;
 use std::fmt;
 use std::rc::Rc;
 use std::hash::{Hash, Hasher};
@@ -54,6 +58,8 @@ pub mod gather_loans;
 
 pub mod move_data;
 
+mod unused;
+
 #[derive(Clone, Copy)]
 pub struct LoanDataFlowOperator;
 
@@ -79,7 +85,9 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
     pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
 }
 
-fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
+fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
+    -> Rc<BorrowCheckResult>
+{
     debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
 
     let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap();
@@ -91,7 +99,9 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
             // those things (notably the synthesized constructors from
             // tuple structs/variants) do not have an associated body
             // and do not need borrowchecking.
-            return;
+            return Rc::new(BorrowCheckResult {
+                used_mut_nodes: FxHashSet(),
+            })
         }
         _ => { }
     }
@@ -100,7 +110,14 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
     let tables = tcx.typeck_tables_of(owner_def_id);
     let region_scope_tree = tcx.region_scope_tree(owner_def_id);
     let body = tcx.hir.body(body_id);
-    let bccx = &mut BorrowckCtxt { tcx, tables, region_scope_tree, owner_def_id, body };
+    let mut bccx = BorrowckCtxt {
+        tcx,
+        tables,
+        region_scope_tree,
+        owner_def_id,
+        body,
+        used_mut_nodes: RefCell::new(FxHashSet()),
+    };
 
     // Eventually, borrowck will always read the MIR, but at the
     // moment we do not. So, for now, we always force MIR to be
@@ -118,14 +135,19 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
     if let Some(AnalysisData { all_loans,
                                loans: loan_dfcx,
                                move_data: flowed_moves }) =
-        build_borrowck_dataflow_data(bccx, false, body_id,
+        build_borrowck_dataflow_data(&mut bccx, false, body_id,
                                      |bccx| {
                                          cfg = Some(cfg::CFG::new(bccx.tcx, &body));
                                          cfg.as_mut().unwrap()
                                      })
     {
-        check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
+        check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
     }
+    unused::check(&mut bccx, body);
+
+    Rc::new(BorrowCheckResult {
+        used_mut_nodes: bccx.used_mut_nodes.into_inner(),
+    })
 }
 
 fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tcx>,
@@ -198,7 +220,14 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     let tables = tcx.typeck_tables_of(owner_def_id);
     let region_scope_tree = tcx.region_scope_tree(owner_def_id);
     let body = tcx.hir.body(body_id);
-    let mut bccx = BorrowckCtxt { tcx, tables, region_scope_tree, owner_def_id, body };
+    let mut bccx = BorrowckCtxt {
+        tcx,
+        tables,
+        region_scope_tree,
+        owner_def_id,
+        body,
+        used_mut_nodes: RefCell::new(FxHashSet()),
+    };
 
     let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
     (bccx, dataflow_data.unwrap())
@@ -219,6 +248,8 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
     owner_def_id: DefId,
 
     body: &'tcx hir::Body,
+
+    used_mut_nodes: RefCell<FxHashSet<HirId>>,
 }
 
 impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> {
@@ -614,11 +645,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 let partial = moved_lp.depth() > lp.depth();
                 let msg = if !has_fork && partial { "partially " }
                           else if has_fork && !has_common { "collaterally "}
-                          else { "" };
-                let mut err = struct_span_err!(
-                    self.tcx.sess, use_span, E0382,
-                    "{} of {}moved value: `{}`",
-                    verb, msg, nl);
+                else { "" };
+                let mut err = self.cannot_act_on_moved_value(use_span,
+                                                             verb,
+                                                             msg,
+                                                             &format!("{}", nl),
+                                                             Origin::Ast);
                 let need_note = match lp.ty.sty {
                     ty::TypeVariants::TyClosure(id, _) => {
                         let node_id = self.tcx.hir.as_local_node_id(id).unwrap();
@@ -698,10 +730,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             &self,
             span: Span,
             lp: &LoanPath<'tcx>) {
-        span_err!(
-            self.tcx.sess, span, E0383,
-            "partial reinitialization of uninitialized structure `{}`",
-            self.loan_path_to_string(lp));
+        self.cannot_partially_reinit_an_uninit_struct(span,
+                                                      &self.loan_path_to_string(lp),
+                                                      Origin::Ast)
+            .emit();
     }
 
     pub fn report_reassigned_immutable_variable(&self,
@@ -759,11 +791,24 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
                 let mut db = match err.cause {
                     MutabilityViolation => {
-                        self.cannot_assign(error_span, &descr, Origin::Ast)
+                        let mut db = self.cannot_assign(error_span, &descr, Origin::Ast);
+                        if let mc::NoteClosureEnv(upvar_id) = err.cmt.note {
+                            let node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id);
+                            let sp = self.tcx.hir.span(node_id);
+                            match self.tcx.sess.codemap().span_to_snippet(sp) {
+                                Ok(snippet) => {
+                                    let msg = &format!("consider making `{}` mutable", snippet);
+                                    db.span_suggestion(sp, msg, format!("mut {}", snippet));
+                                }
+                                _ => {
+                                    db.span_help(sp, "consider making this binding mutable");
+                                }
+                            }
+                        }
+                        db
                     }
                     BorrowViolation(euv::ClosureCapture(_)) => {
-                        struct_span_err!(self.tcx.sess, error_span, E0595,
-                                         "closure cannot assign to {}", descr)
+                        self.closure_cannot_assign_to_borrowed(error_span, &descr, Origin::Ast)
                     }
                     BorrowViolation(euv::OverloadedOperator) |
                     BorrowViolation(euv::AddrOf) |
@@ -772,8 +817,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     BorrowViolation(euv::AutoUnsafe) |
                     BorrowViolation(euv::ForLoop) |
                     BorrowViolation(euv::MatchDiscriminant) => {
-                        struct_span_err!(self.tcx.sess, error_span, E0596,
-                                         "cannot borrow {} as mutable", descr)
+                        self.cannot_borrow_path_as_mutable(error_span, &descr, Origin::Ast)
                     }
                     BorrowViolation(euv::ClosureInvocation) => {
                         span_bug!(err.span,
@@ -855,21 +899,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
                 if let Some((yield_span, _)) = maybe_borrow_across_yield {
                     debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
-                    struct_span_err!(self.tcx.sess,
-                                     error_span,
-                                     E0626,
-                                     "borrow may still be in use when generator yields")
-                        .span_label(yield_span, "possible yield occurs here")
+                    self.cannot_borrow_across_generator_yield(error_span, yield_span, Origin::Ast)
                         .emit();
                     return;
                 }
 
-                let mut db = struct_span_err!(self.tcx.sess,
-                                              error_span,
-                                              E0597,
-                                              "{} does not live long enough",
-                                              msg);
-
+                let mut db = self.path_does_not_live_long_enough(error_span, &msg, Origin::Ast);
                 let (value_kind, value_msg) = match err.cmt.cat {
                     mc::Categorization::Rvalue(..) =>
                         ("temporary value", "temporary value created here"),
@@ -978,11 +1013,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             }
             err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
                 let descr = self.cmt_to_path_or_string(&err.cmt);
-                let mut db = struct_span_err!(self.tcx.sess, error_span, E0598,
-                                              "lifetime of {} is too short to guarantee \
-                                               its contents can be safely reborrowed",
-                                              descr);
-
+                let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast);
                 let descr = match opt_loan_path(&err.cmt) {
                     Some(lp) => {
                         format!("`{}`", self.loan_path_to_string(&lp))
@@ -1054,12 +1085,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         let blame = cmt.immutability_blame();
         let mut err = match blame {
             Some(ImmutabilityBlame::ClosureEnv(id)) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess, span, E0387,
-                    "{} in a captured outer variable in an `Fn` closure", prefix);
-
                 // FIXME: the distinction between these 2 messages looks wrong.
-                let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
+                let help_msg = if let BorrowViolation(euv::ClosureCapture(_)) = kind {
                     // The aliasability violation with closure captures can
                     // happen for nested closures, so we know the enclosing
                     // closure incorrectly accepts an `Fn` while it needs to
@@ -1070,15 +1097,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     "consider changing this closure to take self by mutable reference"
                 };
                 let node_id = self.tcx.hir.def_index_to_node_id(id);
-                err.span_help(self.tcx.hir.span(node_id), help);
-                err
+                let help_span = self.tcx.hir.span(node_id);
+                self.cannot_act_on_capture_in_sharable_fn(span,
+                                                          prefix,
+                                                          (help_span, help_msg),
+                                                          Origin::Ast)
             }
             _ =>  {
-                let mut err = struct_span_err!(
-                    self.tcx.sess, span, E0389,
-                    "{} in a `&` reference", prefix);
-                err.span_label(span, "assignment into an immutable reference");
-                err
+                self.cannot_assign_into_immutable_reference(span, prefix,
+                                                            Origin::Ast)
             }
         };
         self.note_immutability_blame(&mut err, blame);
@@ -1230,17 +1257,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 Err(_) => format!("move |<args>| <body>")
             };
 
-        struct_span_err!(self.tcx.sess, err.span, E0373,
-                         "closure may outlive the current function, \
-                          but it borrows {}, \
-                          which is owned by the current function",
-                         cmt_path_or_string)
-            .span_label(capture_span,
-                       format!("{} is borrowed here",
-                                cmt_path_or_string))
-            .span_label(err.span,
-                       format!("may outlive borrowed value {}",
-                                cmt_path_or_string))
+        self.cannot_capture_in_long_lived_closure(err.span,
+                                                  &cmt_path_or_string,
+                                                  capture_span,
+                                                  Origin::Ast)
             .span_suggestion(err.span,
                              &format!("to force the closure to take ownership of {} \
                                        (and any other referenced variables), \
diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs
new file mode 100644
index 00000000000..228824b663d
--- /dev/null
+++ b/src/librustc_borrowck/borrowck/unused.rs
@@ -0,0 +1,118 @@
+// 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 rustc::hir::intravisit::{Visitor, NestedVisitorMap};
+use rustc::hir::{self, HirId};
+use rustc::lint::builtin::UNUSED_MUT;
+use rustc::ty;
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc_back::slice;
+use syntax::ptr::P;
+
+use borrowck::BorrowckCtxt;
+
+pub fn check<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &'tcx hir::Body) {
+    let mut used_mut = bccx.used_mut_nodes.borrow().clone();
+    UsedMutFinder {
+        bccx,
+        set: &mut used_mut,
+    }.visit_expr(&body.value);
+    let mut cx = UnusedMutCx { bccx, used_mut };
+    for arg in body.arguments.iter() {
+        cx.check_unused_mut_pat(slice::ref_slice(&arg.pat));
+    }
+    cx.visit_expr(&body.value);
+}
+
+struct UsedMutFinder<'a, 'tcx: 'a> {
+    bccx: &'a BorrowckCtxt<'a, 'tcx>,
+    set: &'a mut FxHashSet<HirId>,
+}
+
+struct UnusedMutCx<'a, 'tcx: 'a> {
+    bccx: &'a BorrowckCtxt<'a, 'tcx>,
+    used_mut: FxHashSet<HirId>,
+}
+
+impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
+    fn check_unused_mut_pat(&self, pats: &[P<hir::Pat>]) {
+        let tcx = self.bccx.tcx;
+        let mut mutables = FxHashMap();
+        for p in pats {
+            p.each_binding(|_, id, span, path1| {
+                let name = path1.node;
+
+                // Skip anything that looks like `_foo`
+                if name.as_str().starts_with("_") {
+                    return
+                }
+
+                // Skip anything that looks like `&foo` or `&mut foo`, only look
+                // for by-value bindings
+                let hir_id = tcx.hir.node_to_hir_id(id);
+                let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) {
+                    Some(&bm) => bm,
+                    None => span_bug!(span, "missing binding mode"),
+                };
+                match bm {
+                    ty::BindByValue(hir::MutMutable) => {}
+                    _ => return,
+                }
+
+                mutables.entry(name).or_insert(Vec::new()).push((id, hir_id, span));
+            });
+        }
+
+        for (_name, ids) in mutables {
+            // If any id for this name was used mutably then consider them all
+            // ok, so move on to the next
+            if ids.iter().any(|&(_, ref id, _)| self.used_mut.contains(id)) {
+                continue
+            }
+
+            let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' ');
+
+            // Ok, every name wasn't used mutably, so issue a warning that this
+            // didn't need to be mutable.
+            tcx.struct_span_lint_node(UNUSED_MUT,
+                                      ids[0].0,
+                                      ids[0].2,
+                                      "variable does not need to be mutable")
+                .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned())
+                .emit();
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for UnusedMutCx<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir)
+    }
+
+    fn visit_arm(&mut self, arm: &hir::Arm) {
+        self.check_unused_mut_pat(&arm.pats)
+    }
+
+    fn visit_local(&mut self, local: &hir::Local) {
+        self.check_unused_mut_pat(slice::ref_slice(&local.pat));
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for UsedMutFinder<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir)
+    }
+
+    fn visit_nested_body(&mut self, id: hir::BodyId) {
+        let def_id = self.bccx.tcx.hir.body_owner_def_id(id);
+        self.set.extend(self.bccx.tcx.borrowck(def_id).used_mut_nodes.iter().cloned());
+        self.visit_body(self.bccx.tcx.hir.body(id));
+    }
+}
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index 29c35e23d4e..3fea01443be 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -9,738 +9,3 @@
 // except according to those terms.
 
 #![allow(non_snake_case)]
-
-register_long_diagnostics! {
-
-E0373: r##"
-This error occurs when an attempt is made to use data captured by a closure,
-when that data may no longer exist. It's most commonly seen when attempting to
-return a closure:
-
-```compile_fail,E0373
-fn foo() -> Box<Fn(u32) -> u32> {
-    let x = 0u32;
-    Box::new(|y| x + y)
-}
-```
-
-Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
-closed-over data by reference. This means that once `foo()` returns, `x` no
-longer exists. An attempt to access `x` within the closure would thus be
-unsafe.
-
-Another situation where this might be encountered is when spawning threads:
-
-```compile_fail,E0373
-fn foo() {
-    let x = 0u32;
-    let y = 1u32;
-
-    let thr = std::thread::spawn(|| {
-        x + y
-    });
-}
-```
-
-Since our new thread runs in parallel, the stack frame containing `x` and `y`
-may well have disappeared by the time we try to use them. Even if we call
-`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
-stack frame won't disappear), we will not succeed: the compiler cannot prove
-that this behaviour is safe, and so won't let us do it.
-
-The solution to this problem is usually to switch to using a `move` closure.
-This approach moves (or copies, where possible) data into the closure, rather
-than taking references to it. For example:
-
-```
-fn foo() -> Box<Fn(u32) -> u32> {
-    let x = 0u32;
-    Box::new(move |y| x + y)
-}
-```
-
-Now that the closure has its own copy of the data, there's no need to worry
-about safety.
-"##,
-
-E0382: r##"
-This error occurs when an attempt is made to use a variable after its contents
-have been moved elsewhere. For example:
-
-```compile_fail,E0382
-struct MyStruct { s: u32 }
-
-fn main() {
-    let mut x = MyStruct{ s: 5u32 };
-    let y = x;
-    x.s = 6;
-    println!("{}", x.s);
-}
-```
-
-Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
-of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
-of workarounds like `Rc`, a value cannot be owned by more than one variable.
-
-If we own the type, the easiest way to address this problem is to implement
-`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
-information in `x`, while leaving the original version owned by `x`. Subsequent
-changes to `x` will not be reflected when accessing `y`.
-
-```
-#[derive(Copy, Clone)]
-struct MyStruct { s: u32 }
-
-fn main() {
-    let mut x = MyStruct{ s: 5u32 };
-    let y = x;
-    x.s = 6;
-    println!("{}", x.s);
-}
-```
-
-Alternatively, if we don't control the struct's definition, or mutable shared
-ownership is truly required, we can use `Rc` and `RefCell`:
-
-```
-use std::cell::RefCell;
-use std::rc::Rc;
-
-struct MyStruct { s: u32 }
-
-fn main() {
-    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
-    let y = x.clone();
-    x.borrow_mut().s = 6;
-    println!("{}", x.borrow().s);
-}
-```
-
-With this approach, x and y share ownership of the data via the `Rc` (reference
-count type). `RefCell` essentially performs runtime borrow checking: ensuring
-that at most one writer or multiple readers can access the data at any one time.
-
-If you wish to learn more about ownership in Rust, start with the chapter in the
-Book:
-
-https://doc.rust-lang.org/book/first-edition/ownership.html
-"##,
-
-E0383: r##"
-This error occurs when an attempt is made to partially reinitialize a
-structure that is currently uninitialized.
-
-For example, this can happen when a drop has taken place:
-
-```compile_fail,E0383
-struct Foo {
-    a: u32,
-}
-impl Drop for Foo {
-    fn drop(&mut self) { /* ... */ }
-}
-
-let mut x = Foo { a: 1 };
-drop(x); // `x` is now uninitialized
-x.a = 2; // error, partial reinitialization of uninitialized structure `t`
-```
-
-This error can be fixed by fully reinitializing the structure in question:
-
-```
-struct Foo {
-    a: u32,
-}
-impl Drop for Foo {
-    fn drop(&mut self) { /* ... */ }
-}
-
-let mut x = Foo { a: 1 };
-drop(x);
-x = Foo { a: 2 };
-```
-"##,
-
-/*E0386: r##"
-This error occurs when an attempt is made to mutate the target of a mutable
-reference stored inside an immutable container.
-
-For example, this can happen when storing a `&mut` inside an immutable `Box`:
-
-```compile_fail,E0386
-let mut x: i64 = 1;
-let y: Box<_> = Box::new(&mut x);
-**y = 2; // error, cannot assign to data in an immutable container
-```
-
-This error can be fixed by making the container mutable:
-
-```
-let mut x: i64 = 1;
-let mut y: Box<_> = Box::new(&mut x);
-**y = 2;
-```
-
-It can also be fixed by using a type with interior mutability, such as `Cell`
-or `RefCell`:
-
-```
-use std::cell::Cell;
-
-let x: i64 = 1;
-let y: Box<Cell<_>> = Box::new(Cell::new(x));
-y.set(2);
-```
-"##,*/
-
-E0387: r##"
-This error occurs when an attempt is made to mutate or mutably reference data
-that a closure has captured immutably. Examples of this error are shown below:
-
-```compile_fail,E0387
-// Accepts a function or a closure that captures its environment immutably.
-// Closures passed to foo will not be able to mutate their closed-over state.
-fn foo<F: Fn()>(f: F) { }
-
-// Attempts to mutate closed-over data. Error message reads:
-// `cannot assign to data in a captured outer variable...`
-fn mutable() {
-    let mut x = 0u32;
-    foo(|| x = 2);
-}
-
-// Attempts to take a mutable reference to closed-over data.  Error message
-// reads: `cannot borrow data mutably in a captured outer variable...`
-fn mut_addr() {
-    let mut x = 0u32;
-    foo(|| { let y = &mut x; });
-}
-```
-
-The problem here is that foo is defined as accepting a parameter of type `Fn`.
-Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
-they capture their context immutably.
-
-If the definition of `foo` is under your control, the simplest solution is to
-capture the data mutably. This can be done by defining `foo` to take FnMut
-rather than Fn:
-
-```
-fn foo<F: FnMut()>(f: F) { }
-```
-
-Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
-interior mutability through a shared reference. Our example's `mutable`
-function could be redefined as below:
-
-```
-use std::cell::Cell;
-
-fn foo<F: Fn()>(f: F) { }
-
-fn mutable() {
-    let x = Cell::new(0u32);
-    foo(|| x.set(2));
-}
-```
-
-You can read more about cell types in the API documentation:
-
-https://doc.rust-lang.org/std/cell/
-"##,
-
-E0388: r##"
-E0388 was removed and is no longer issued.
-"##,
-
-E0389: r##"
-An attempt was made to mutate data using a non-mutable reference. This
-commonly occurs when attempting to assign to a non-mutable reference of a
-mutable reference (`&(&mut T)`).
-
-Example of erroneous code:
-
-```compile_fail,E0389
-struct FancyNum {
-    num: u8,
-}
-
-fn main() {
-    let mut fancy = FancyNum{ num: 5 };
-    let fancy_ref = &(&mut fancy);
-    fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
-    println!("{}", fancy_ref.num);
-}
-```
-
-Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
-immutable reference to a value borrows it immutably. There can be multiple
-references of type `&(&mut T)` that point to the same value, so they must be
-immutable to prevent multiple mutable references to the same value.
-
-To fix this, either remove the outer reference:
-
-```
-struct FancyNum {
-    num: u8,
-}
-
-fn main() {
-    let mut fancy = FancyNum{ num: 5 };
-
-    let fancy_ref = &mut fancy;
-    // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
-
-    fancy_ref.num = 6; // No error!
-
-    println!("{}", fancy_ref.num);
-}
-```
-
-Or make the outer reference mutable:
-
-```
-struct FancyNum {
-    num: u8
-}
-
-fn main() {
-    let mut fancy = FancyNum{ num: 5 };
-
-    let fancy_ref = &mut (&mut fancy);
-    // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
-
-    fancy_ref.num = 6; // No error!
-
-    println!("{}", fancy_ref.num);
-}
-```
-"##,
-
-E0507: r##"
-You tried to move out of a value which was borrowed. Erroneous code example:
-
-```compile_fail,E0507
-use std::cell::RefCell;
-
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-
-    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
-}
-```
-
-Here, the `nothing_is_true` method takes the ownership of `self`. However,
-`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
-which is a borrow of the content owned by the `RefCell`. To fix this error,
-you have three choices:
-
-* Try to avoid moving the variable.
-* Somehow reclaim the ownership.
-* Implement the `Copy` trait on the type.
-
-Examples:
-
-```
-use std::cell::RefCell;
-
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(&self) {} // First case, we don't take ownership
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-
-    x.borrow().nothing_is_true(); // ok!
-}
-```
-
-Or:
-
-```
-use std::cell::RefCell;
-
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-    let x = x.into_inner(); // we get back ownership
-
-    x.nothing_is_true(); // ok!
-}
-```
-
-Or:
-
-```
-use std::cell::RefCell;
-
-#[derive(Clone, Copy)] // we implement the Copy trait
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-fn main() {
-    let x = RefCell::new(TheDarkKnight);
-
-    x.borrow().nothing_is_true(); // ok!
-}
-```
-
-Moving a member out of a mutably borrowed struct will also cause E0507 error:
-
-```compile_fail,E0507
-struct TheDarkKnight;
-
-impl TheDarkKnight {
-    fn nothing_is_true(self) {}
-}
-
-struct Batcave {
-    knight: TheDarkKnight
-}
-
-fn main() {
-    let mut cave = Batcave {
-        knight: TheDarkKnight
-    };
-    let borrowed = &mut cave;
-
-    borrowed.knight.nothing_is_true(); // E0507
-}
-```
-
-It is fine only if you put something back. `mem::replace` can be used for that:
-
-```
-# struct TheDarkKnight;
-# impl TheDarkKnight { fn nothing_is_true(self) {} }
-# struct Batcave { knight: TheDarkKnight }
-use std::mem;
-
-let mut cave = Batcave {
-    knight: TheDarkKnight
-};
-let borrowed = &mut cave;
-
-mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
-```
-
-You can find more information about borrowing in the rust-book:
-http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
-"##,
-
-E0508: r##"
-A value was moved out of a non-copy fixed-size array.
-
-Example of erroneous code:
-
-```compile_fail,E0508
-struct NonCopy;
-
-fn main() {
-    let array = [NonCopy; 1];
-    let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
-                           //        a non-copy fixed-size array
-}
-```
-
-The first element was moved out of the array, but this is not
-possible because `NonCopy` does not implement the `Copy` trait.
-
-Consider borrowing the element instead of moving it:
-
-```
-struct NonCopy;
-
-fn main() {
-    let array = [NonCopy; 1];
-    let _value = &array[0]; // Borrowing is allowed, unlike moving.
-}
-```
-
-Alternatively, if your type implements `Clone` and you need to own the value,
-consider borrowing and then cloning:
-
-```
-#[derive(Clone)]
-struct NonCopy;
-
-fn main() {
-    let array = [NonCopy; 1];
-    // Now you can clone the array element.
-    let _value = array[0].clone();
-}
-```
-"##,
-
-E0509: r##"
-This error occurs when an attempt is made to move out of a value whose type
-implements the `Drop` trait.
-
-Example of erroneous code:
-
-```compile_fail,E0509
-struct FancyNum {
-    num: usize
-}
-
-struct DropStruct {
-    fancy: FancyNum
-}
-
-impl Drop for DropStruct {
-    fn drop(&mut self) {
-        // Destruct DropStruct, possibly using FancyNum
-    }
-}
-
-fn main() {
-    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
-    let fancy_field = drop_struct.fancy; // Error E0509
-    println!("Fancy: {}", fancy_field.num);
-    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
-}
-```
-
-Here, we tried to move a field out of a struct of type `DropStruct` which
-implements the `Drop` trait. However, a struct cannot be dropped if one or
-more of its fields have been moved.
-
-Structs implementing the `Drop` trait have an implicit destructor that gets
-called when they go out of scope. This destructor may use the fields of the
-struct, so moving out of the struct could make it impossible to run the
-destructor. Therefore, we must think of all values whose type implements the
-`Drop` trait as single units whose fields cannot be moved.
-
-This error can be fixed by creating a reference to the fields of a struct,
-enum, or tuple using the `ref` keyword:
-
-```
-struct FancyNum {
-    num: usize
-}
-
-struct DropStruct {
-    fancy: FancyNum
-}
-
-impl Drop for DropStruct {
-    fn drop(&mut self) {
-        // Destruct DropStruct, possibly using FancyNum
-    }
-}
-
-fn main() {
-    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
-    let ref fancy_field = drop_struct.fancy; // No more errors!
-    println!("Fancy: {}", fancy_field.num);
-    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
-}
-```
-
-Note that this technique can also be used in the arms of a match expression:
-
-```
-struct FancyNum {
-    num: usize
-}
-
-enum DropEnum {
-    Fancy(FancyNum)
-}
-
-impl Drop for DropEnum {
-    fn drop(&mut self) {
-        // Destruct DropEnum, possibly using FancyNum
-    }
-}
-
-fn main() {
-    // Creates and enum of type `DropEnum`, which implements `Drop`
-    let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
-    match drop_enum {
-        // Creates a reference to the inside of `DropEnum::Fancy`
-        DropEnum::Fancy(ref fancy_field) => // No error!
-            println!("It was fancy-- {}!", fancy_field.num),
-    }
-    // implicit call to `drop_enum.drop()` as drop_enum goes out of scope
-}
-```
-"##,
-
-E0595: r##"
-Closures cannot mutate immutable captured variables.
-
-Erroneous code example:
-
-```compile_fail,E0595
-let x = 3; // error: closure cannot assign to immutable local variable `x`
-let mut c = || { x += 1 };
-```
-
-Make the variable binding mutable:
-
-```
-let mut x = 3; // ok!
-let mut c = || { x += 1 };
-```
-"##,
-
-E0596: r##"
-This error occurs because you tried to mutably borrow a non-mutable variable.
-
-Example of erroneous code:
-
-```compile_fail,E0596
-let x = 1;
-let y = &mut x; // error: cannot borrow mutably
-```
-
-In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
-fails. To fix this error, you need to make `x` mutable:
-
-```
-let mut x = 1;
-let y = &mut x; // ok!
-```
-"##,
-
-E0597: r##"
-This error occurs because a borrow was made inside a variable which has a
-greater lifetime than the borrowed one.
-
-Example of erroneous code:
-
-```compile_fail,E0597
-struct Foo<'a> {
-    x: Option<&'a u32>,
-}
-
-let mut x = Foo { x: None };
-let y = 0;
-x.x = Some(&y); // error: `y` does not live long enough
-```
-
-In here, `x` is created before `y` and therefore has a greater lifetime. Always
-keep in mind that values in a scope are dropped in the opposite order they are
-created. So to fix the previous example, just make the `y` lifetime greater than
-the `x`'s one:
-
-```
-struct Foo<'a> {
-    x: Option<&'a u32>,
-}
-
-let y = 0;
-let mut x = Foo { x: None };
-x.x = Some(&y);
-```
-"##,
-
-E0626: r##"
-This error occurs because a borrow in a generator persists across a
-yield point.
-
-```compile_fail,E0626
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
-    let a = &String::new(); // <-- This borrow...
-    yield (); // ...is still in scope here, when the yield occurs.
-    println!("{}", a);
-};
-b.resume();
-```
-
-At present, it is not permitted to have a yield that occurs while a
-borrow is still in scope. To resolve this error, the borrow must
-either be "contained" to a smaller scope that does not overlap the
-yield or else eliminated in another way. So, for example, we might
-resolve the previous example by removing the borrow and just storing
-the integer by value:
-
-```
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
-    let a = 3;
-    yield ();
-    println!("{}", a);
-};
-b.resume();
-```
-
-This is a very simple case, of course. In more complex cases, we may
-wish to have more than one reference to the value that was borrowed --
-in those cases, something like the `Rc` or `Arc` types may be useful.
-
-This error also frequently arises with iteration:
-
-```compile_fail,E0626
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
-  let v = vec![1,2,3];
-  for &x in &v { // <-- borrow of `v` is still in scope...
-    yield x; // ...when this yield occurs.
-  }
-};
-b.resume();
-```
-
-Such cases can sometimes be resolved by iterating "by value" (or using
-`into_iter()`) to avoid borrowing:
-
-```
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
-  let v = vec![1,2,3];
-  for x in v { // <-- Take ownership of the values instead!
-    yield x; // <-- Now yield is OK.
-  }
-};
-b.resume();
-```
-
-If taking ownership is not an option, using indices can work too:
-
-```
-# #![feature(generators, generator_trait)]
-# use std::ops::Generator;
-let mut b = || {
-  let v = vec![1,2,3];
-  let len = v.len(); // (*)
-  for i in 0..len {
-    let x = v[i]; // (*)
-    yield x; // <-- Now yield is OK.
-  }
-};
-b.resume();
-
-// (*) -- Unfortunately, these temporaries are currently required.
-// See <https://github.com/rust-lang/rust/issues/43122>.
-```
-"##,
-
-}
-
-register_diagnostics! {
-//    E0385, // {} in an aliasable location
-    E0598, // lifetime of {} is too short to guarantee its contents can be...
-}
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 9bedbfed5db..78aacd49f80 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -16,12 +16,12 @@
 #![allow(non_camel_case_types)]
 
 #![feature(quote)]
-#![feature(rustc_diagnostic_macros)]
 
 #[macro_use] extern crate log;
-#[macro_use] extern crate syntax;
+extern crate syntax;
 extern crate syntax_pos;
 extern crate rustc_errors as errors;
+extern crate rustc_back;
 
 // for "clarity", rename the graphviz crate to dot; graphviz within `borrowck`
 // refers to the borrowck-specific graphviz adapter traits.
@@ -33,14 +33,8 @@ extern crate rustc_mir;
 pub use borrowck::check_crate;
 pub use borrowck::build_borrowck_dataflow_data_for_fn;
 
-// NB: This module needs to be declared first so diagnostics are
-// registered before they are used.
-mod diagnostics;
-
 mod borrowck;
 
 pub mod graphviz;
 
 pub use borrowck::provide;
-
-__build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index b836b71e74b..08f3b0a4c5f 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -25,7 +25,7 @@ use pattern::{PatternFoldable, PatternFolder};
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::RangeEnd;
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 
 use rustc::mir::Field;
 use rustc::util::common::ErrorReported;
@@ -202,7 +202,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
 
     fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
         if self.tcx.sess.features.borrow().never_type {
-            ty.is_uninhabited_from(self.module, self.tcx)
+            self.tcx.is_ty_uninhabited_from(self.module, ty)
         } else {
             false
         }
@@ -210,13 +210,11 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
 
     fn is_variant_uninhabited(&self,
                               variant: &'tcx ty::VariantDef,
-                              substs: &'tcx ty::subst::Substs<'tcx>) -> bool
+                              substs: &'tcx ty::subst::Substs<'tcx>)
+                              -> bool
     {
         if self.tcx.sess.features.borrow().never_type {
-            let forest = variant.uninhabited_from(
-                &mut FxHashMap::default(), self.tcx, substs, AdtKind::Enum
-            );
-            forest.contains(self.tcx, self.module)
+            self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
         } else {
             false
         }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 0339969f2b4..e6a04c9c57a 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -192,7 +192,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
             let module = self.tcx.hir.get_module_parent(scrut.id);
             if inlined_arms.is_empty() {
                 let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
-                    pat_ty.is_uninhabited_from(module, self.tcx)
+                    self.tcx.is_ty_uninhabited_from(module, pat_ty)
                 } else {
                     self.conservative_is_uninhabited(pat_ty)
                 };
@@ -526,7 +526,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
     let mut checker = MutationChecker {
         cx,
     };
-    ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables)
+    ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
         .walk_expr(guard);
 }
 
diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs
index 474622f3669..56d5f5ffa3f 100644
--- a/src/librustc_data_structures/graph/mod.rs
+++ b/src/librustc_data_structures/graph/mod.rs
@@ -31,7 +31,7 @@
 //! be indexed by the direction (see the type `Direction`).
 
 use bitvec::BitVector;
-use std::fmt::{Formatter, Error, Debug};
+use std::fmt::Debug;
 use std::usize;
 use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
 
@@ -48,6 +48,7 @@ pub struct Node<N> {
     pub data: N,
 }
 
+#[derive(Debug)]
 pub struct Edge<E> {
     next_edge: [EdgeIndex; 2], // see module comment
     source: NodeIndex,
@@ -69,18 +70,6 @@ impl<N> SnapshotVecDelegate for Edge<N> {
     fn reverse(_: &mut Vec<Edge<N>>, _: ()) {}
 }
 
-impl<E: Debug> Debug for Edge<E> {
-    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
-        write!(f,
-               "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}",
-               self.next_edge[0],
-               self.next_edge[1],
-               self.source,
-               self.target,
-               self.data)
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub struct NodeIndex(pub usize);
 
diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs
index 4b7f55eba06..1d1b367de20 100644
--- a/src/librustc_data_structures/indexed_vec.rs
+++ b/src/librustc_data_structures/indexed_vec.rs
@@ -40,39 +40,80 @@ impl Idx for u32 {
 
 #[macro_export]
 macro_rules! newtype_index {
+    // ---- public rules ----
+
+    // Use default constants
     ($name:ident) => (
-        newtype_index!($name, unsafe { ::std::intrinsics::type_name::<$name>() });
+        newtype_index!(
+            @type[$name]
+            @max[::std::u32::MAX]
+            @debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]);
+    );
+
+    // Define any constants
+    ($name:ident { $($tokens:tt)+ }) => (
+        newtype_index!(
+            @type[$name]
+            @max[::std::u32::MAX]
+            @debug_name[unsafe {::std::intrinsics::type_name::<$name>() }]
+            $($tokens)+);
     );
 
-    ($name:ident, $debug_name:expr) => (
+    // ---- private rules ----
+
+    // Base case, user-defined constants (if any) have already been defined
+    (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]) => (
         #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
-         RustcEncodable, RustcDecodable)]
-        pub struct $name(u32);
-
-        impl $name {
-            // HACK use for constants
-            #[allow(unused)]
-            const fn const_new(x: u32) -> Self {
-                $name(x)
-            }
-        }
+            RustcEncodable, RustcDecodable)]
+        pub struct $type(pub u32);
 
-        impl Idx for $name {
+        impl Idx for $type {
             fn new(value: usize) -> Self {
-                assert!(value < (::std::u32::MAX) as usize);
-                $name(value as u32)
+                assert!(value < ($max) as usize);
+                $type(value as u32)
             }
             fn index(self) -> usize {
                 self.0 as usize
             }
         }
 
-        impl ::std::fmt::Debug for $name {
+        impl ::std::fmt::Debug for $type {
             fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                 write!(fmt, "{}{}", $debug_name, self.0)
             }
         }
-    )
+    );
+
+    // Rewrite final without comma to one that includes comma
+    (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]
+            $name:ident = $constant:expr) => (
+        newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $name = $constant,);
+    );
+
+    // Rewrite final const without comma to one that includes comma
+    (@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
+            const $name:ident = $constant:expr) => (
+        newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] const $name = $constant,);
+    );
+
+    // Replace existing default for max
+    (@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
+            MAX = $max:expr, $($tokens:tt)*) => (
+        newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
+    );
+
+    // Replace existing default for debug_name
+    (@type[$type:ident] @max[$max:expr] @debug_name[$_debug_name:expr]
+            DEBUG_NAME = $debug_name:expr, $($tokens:tt)*) => (
+        newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
+    );
+
+    // Assign a user-defined constant (as final param)
+    (@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]
+            const $name:ident = $constant:expr, $($tokens:tt)*) => (
+        pub const $name: $type = $type($constant);
+        newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
+    );
 }
 
 #[derive(Clone, PartialEq, Eq)]
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 47061883425..3a20343033c 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -28,6 +28,7 @@
 #![feature(fn_traits)]
 #![feature(unsize)]
 #![feature(i128_type)]
+#![feature(i128)]
 #![feature(conservative_impl_trait)]
 #![feature(specialization)]
 
@@ -54,6 +55,7 @@ pub mod graph;
 pub mod indexed_set;
 pub mod indexed_vec;
 pub mod obligation_forest;
+pub mod sip128;
 pub mod snapshot_map;
 pub mod snapshot_vec;
 pub mod stable_hasher;
diff --git a/src/librustc_data_structures/sip128.rs b/src/librustc_data_structures/sip128.rs
new file mode 100644
index 00000000000..1f0b0d9cbfb
--- /dev/null
+++ b/src/librustc_data_structures/sip128.rs
@@ -0,0 +1,533 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.
+
+use std::cmp;
+use std::hash::Hasher;
+use std::slice;
+use std::ptr;
+use std::mem;
+
+#[derive(Debug, Clone)]
+pub struct SipHasher128 {
+    k0: u64,
+    k1: u64,
+    length: usize, // how many bytes we've processed
+    state: State, // hash State
+    tail: u64, // unprocessed bytes le
+    ntail: usize, // how many bytes in tail are valid
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+struct State {
+    // v0, v2 and v1, v3 show up in pairs in the algorithm,
+    // and simd implementations of SipHash will use vectors
+    // of v02 and v13. By placing them in this order in the struct,
+    // the compiler can pick up on just a few simd optimizations by itself.
+    v0: u64,
+    v2: u64,
+    v1: u64,
+    v3: u64,
+}
+
+macro_rules! compress {
+    ($state:expr) => ({
+        compress!($state.v0, $state.v1, $state.v2, $state.v3)
+    });
+    ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
+    ({
+        $v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
+        $v0 = $v0.rotate_left(32);
+        $v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
+        $v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
+        $v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
+        $v2 = $v2.rotate_left(32);
+    });
+}
+
+/// Load an integer of the desired type from a byte stream, in LE order. Uses
+/// `copy_nonoverlapping` to let the compiler generate the most efficient way
+/// to load it from a possibly unaligned address.
+///
+/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
+macro_rules! load_int_le {
+    ($buf:expr, $i:expr, $int_ty:ident) =>
+    ({
+       debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
+       let mut data = 0 as $int_ty;
+       ptr::copy_nonoverlapping($buf.get_unchecked($i),
+                                &mut data as *mut _ as *mut u8,
+                                mem::size_of::<$int_ty>());
+       data.to_le()
+    });
+}
+
+/// Load an u64 using up to 7 bytes of a byte slice.
+///
+/// Unsafe because: unchecked indexing at start..start+len
+#[inline]
+unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
+    debug_assert!(len < 8);
+    let mut i = 0; // current byte index (from LSB) in the output u64
+    let mut out = 0;
+    if i + 3 < len {
+        out = load_int_le!(buf, start + i, u32) as u64;
+        i += 4;
+    }
+    if i + 1 < len {
+        out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
+        i += 2
+    }
+    if i < len {
+        out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
+        i += 1;
+    }
+    debug_assert_eq!(i, len);
+    out
+}
+
+
+impl SipHasher128 {
+    #[inline]
+    pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
+        let mut state = SipHasher128 {
+            k0: key0,
+            k1: key1,
+            length: 0,
+            state: State {
+                v0: 0,
+                v1: 0,
+                v2: 0,
+                v3: 0,
+            },
+            tail: 0,
+            ntail: 0,
+        };
+        state.reset();
+        state
+    }
+
+    #[inline]
+    fn reset(&mut self) {
+        self.length = 0;
+        self.state.v0 = self.k0 ^ 0x736f6d6570736575;
+        self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
+        self.state.v2 = self.k0 ^ 0x6c7967656e657261;
+        self.state.v3 = self.k1 ^ 0x7465646279746573;
+        self.ntail = 0;
+
+        // This is only done in the 128 bit version:
+        self.state.v1 ^= 0xee;
+    }
+
+    // Specialized write function that is only valid for buffers with len <= 8.
+    // It's used to force inlining of write_u8 and write_usize, those would normally be inlined
+    // except for composite types (that includes slices and str hashing because of delimiter).
+    // Without this extra push the compiler is very reluctant to inline delimiter writes,
+    // degrading performance substantially for the most common use cases.
+    #[inline]
+    fn short_write(&mut self, msg: &[u8]) {
+        debug_assert!(msg.len() <= 8);
+        let length = msg.len();
+        self.length += length;
+
+        let needed = 8 - self.ntail;
+        let fill = cmp::min(length, needed);
+        if fill == 8 {
+            self.tail = unsafe { load_int_le!(msg, 0, u64) };
+        } else {
+            self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail);
+            if length < needed {
+                self.ntail += length;
+                return;
+            }
+        }
+        self.state.v3 ^= self.tail;
+        Sip24Rounds::c_rounds(&mut self.state);
+        self.state.v0 ^= self.tail;
+
+        // Buffered tail is now flushed, process new input.
+        self.ntail = length - needed;
+        self.tail = unsafe { u8to64_le(msg, needed, self.ntail) };
+    }
+
+    #[inline(always)]
+    fn short_write_gen<T>(&mut self, x: T) {
+        let bytes = unsafe {
+            slice::from_raw_parts(&x as *const T as *const u8, mem::size_of::<T>())
+        };
+        self.short_write(bytes);
+    }
+
+    #[inline]
+    pub fn finish128(mut self) -> (u64, u64) {
+        let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
+
+        self.state.v3 ^= b;
+        Sip24Rounds::c_rounds(&mut self.state);
+        self.state.v0 ^= b;
+
+        self.state.v2 ^= 0xee;
+        Sip24Rounds::d_rounds(&mut self.state);
+        let _0 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;
+
+        self.state.v1 ^= 0xdd;
+        Sip24Rounds::d_rounds(&mut self.state);
+        let _1 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;
+        (_0, _1)
+    }
+}
+
+impl Hasher for SipHasher128 {
+    #[inline]
+    fn write_u8(&mut self, i: u8) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_u16(&mut self, i: u16) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_u32(&mut self, i: u32) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_u64(&mut self, i: u64) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_usize(&mut self, i: usize) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_i8(&mut self, i: i8) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_i16(&mut self, i: i16) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_i32(&mut self, i: i32) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_i64(&mut self, i: i64) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write_isize(&mut self, i: isize) {
+        self.short_write_gen(i);
+    }
+
+    #[inline]
+    fn write(&mut self, msg: &[u8]) {
+        let length = msg.len();
+        self.length += length;
+
+        let mut needed = 0;
+
+        if self.ntail != 0 {
+            needed = 8 - self.ntail;
+            self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail;
+            if length < needed {
+                self.ntail += length;
+                return
+            } else {
+                self.state.v3 ^= self.tail;
+                Sip24Rounds::c_rounds(&mut self.state);
+                self.state.v0 ^= self.tail;
+                self.ntail = 0;
+            }
+        }
+
+        // Buffered tail is now flushed, process new input.
+        let len = length - needed;
+        let left = len & 0x7;
+
+        let mut i = needed;
+        while i < len - left {
+            let mi = unsafe { load_int_le!(msg, i, u64) };
+
+            self.state.v3 ^= mi;
+            Sip24Rounds::c_rounds(&mut self.state);
+            self.state.v0 ^= mi;
+
+            i += 8;
+        }
+
+        self.tail = unsafe { u8to64_le(msg, i, left) };
+        self.ntail = left;
+    }
+
+    fn finish(&self) -> u64 {
+        panic!("SipHasher128 cannot provide valid 64 bit hashes")
+    }
+}
+
+#[derive(Debug, Clone, Default)]
+struct Sip24Rounds;
+
+impl Sip24Rounds {
+    #[inline]
+    fn c_rounds(state: &mut State) {
+        compress!(state);
+        compress!(state);
+    }
+
+    #[inline]
+    fn d_rounds(state: &mut State) {
+        compress!(state);
+        compress!(state);
+        compress!(state);
+        compress!(state);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::hash::{Hash, Hasher};
+    use std::{slice, mem};
+    use super::SipHasher128;
+
+    // Hash just the bytes of the slice, without length prefix
+    struct Bytes<'a>(&'a [u8]);
+
+    impl<'a> Hash for Bytes<'a> {
+        #[allow(unused_must_use)]
+        fn hash<H: Hasher>(&self, state: &mut H) {
+            for byte in self.0 {
+                state.write_u8(*byte);
+            }
+        }
+    }
+
+    fn hash_with<T: Hash>(mut st: SipHasher128, x: &T) -> (u64, u64) {
+        x.hash(&mut st);
+        st.finish128()
+    }
+
+    fn hash<T: Hash>(x: &T) -> (u64, u64) {
+        hash_with(SipHasher128::new_with_keys(0, 0), x)
+    }
+
+    const TEST_VECTOR : [[u8; 16]; 64] = [
+        [0xa3,0x81,0x7f,0x04,0xba,0x25,0xa8,0xe6,0x6d,0xf6,0x72,0x14,0xc7,0x55,0x02,0x93],
+        [0xda,0x87,0xc1,0xd8,0x6b,0x99,0xaf,0x44,0x34,0x76,0x59,0x11,0x9b,0x22,0xfc,0x45],
+        [0x81,0x77,0x22,0x8d,0xa4,0xa4,0x5d,0xc7,0xfc,0xa3,0x8b,0xde,0xf6,0x0a,0xff,0xe4],
+        [0x9c,0x70,0xb6,0x0c,0x52,0x67,0xa9,0x4e,0x5f,0x33,0xb6,0xb0,0x29,0x85,0xed,0x51],
+        [0xf8,0x81,0x64,0xc1,0x2d,0x9c,0x8f,0xaf,0x7d,0x0f,0x6e,0x7c,0x7b,0xcd,0x55,0x79],
+        [0x13,0x68,0x87,0x59,0x80,0x77,0x6f,0x88,0x54,0x52,0x7a,0x07,0x69,0x0e,0x96,0x27],
+        [0x14,0xee,0xca,0x33,0x8b,0x20,0x86,0x13,0x48,0x5e,0xa0,0x30,0x8f,0xd7,0xa1,0x5e],
+        [0xa1,0xf1,0xeb,0xbe,0xd8,0xdb,0xc1,0x53,0xc0,0xb8,0x4a,0xa6,0x1f,0xf0,0x82,0x39],
+        [0x3b,0x62,0xa9,0xba,0x62,0x58,0xf5,0x61,0x0f,0x83,0xe2,0x64,0xf3,0x14,0x97,0xb4],
+        [0x26,0x44,0x99,0x06,0x0a,0xd9,0xba,0xab,0xc4,0x7f,0x8b,0x02,0xbb,0x6d,0x71,0xed],
+        [0x00,0x11,0x0d,0xc3,0x78,0x14,0x69,0x56,0xc9,0x54,0x47,0xd3,0xf3,0xd0,0xfb,0xba],
+        [0x01,0x51,0xc5,0x68,0x38,0x6b,0x66,0x77,0xa2,0xb4,0xdc,0x6f,0x81,0xe5,0xdc,0x18],
+        [0xd6,0x26,0xb2,0x66,0x90,0x5e,0xf3,0x58,0x82,0x63,0x4d,0xf6,0x85,0x32,0xc1,0x25],
+        [0x98,0x69,0xe2,0x47,0xe9,0xc0,0x8b,0x10,0xd0,0x29,0x93,0x4f,0xc4,0xb9,0x52,0xf7],
+        [0x31,0xfc,0xef,0xac,0x66,0xd7,0xde,0x9c,0x7e,0xc7,0x48,0x5f,0xe4,0x49,0x49,0x02],
+        [0x54,0x93,0xe9,0x99,0x33,0xb0,0xa8,0x11,0x7e,0x08,0xec,0x0f,0x97,0xcf,0xc3,0xd9],
+        [0x6e,0xe2,0xa4,0xca,0x67,0xb0,0x54,0xbb,0xfd,0x33,0x15,0xbf,0x85,0x23,0x05,0x77],
+        [0x47,0x3d,0x06,0xe8,0x73,0x8d,0xb8,0x98,0x54,0xc0,0x66,0xc4,0x7a,0xe4,0x77,0x40],
+        [0xa4,0x26,0xe5,0xe4,0x23,0xbf,0x48,0x85,0x29,0x4d,0xa4,0x81,0xfe,0xae,0xf7,0x23],
+        [0x78,0x01,0x77,0x31,0xcf,0x65,0xfa,0xb0,0x74,0xd5,0x20,0x89,0x52,0x51,0x2e,0xb1],
+        [0x9e,0x25,0xfc,0x83,0x3f,0x22,0x90,0x73,0x3e,0x93,0x44,0xa5,0xe8,0x38,0x39,0xeb],
+        [0x56,0x8e,0x49,0x5a,0xbe,0x52,0x5a,0x21,0x8a,0x22,0x14,0xcd,0x3e,0x07,0x1d,0x12],
+        [0x4a,0x29,0xb5,0x45,0x52,0xd1,0x6b,0x9a,0x46,0x9c,0x10,0x52,0x8e,0xff,0x0a,0xae],
+        [0xc9,0xd1,0x84,0xdd,0xd5,0xa9,0xf5,0xe0,0xcf,0x8c,0xe2,0x9a,0x9a,0xbf,0x69,0x1c],
+        [0x2d,0xb4,0x79,0xae,0x78,0xbd,0x50,0xd8,0x88,0x2a,0x8a,0x17,0x8a,0x61,0x32,0xad],
+        [0x8e,0xce,0x5f,0x04,0x2d,0x5e,0x44,0x7b,0x50,0x51,0xb9,0xea,0xcb,0x8d,0x8f,0x6f],
+        [0x9c,0x0b,0x53,0xb4,0xb3,0xc3,0x07,0xe8,0x7e,0xae,0xe0,0x86,0x78,0x14,0x1f,0x66],
+        [0xab,0xf2,0x48,0xaf,0x69,0xa6,0xea,0xe4,0xbf,0xd3,0xeb,0x2f,0x12,0x9e,0xeb,0x94],
+        [0x06,0x64,0xda,0x16,0x68,0x57,0x4b,0x88,0xb9,0x35,0xf3,0x02,0x73,0x58,0xae,0xf4],
+        [0xaa,0x4b,0x9d,0xc4,0xbf,0x33,0x7d,0xe9,0x0c,0xd4,0xfd,0x3c,0x46,0x7c,0x6a,0xb7],
+        [0xea,0x5c,0x7f,0x47,0x1f,0xaf,0x6b,0xde,0x2b,0x1a,0xd7,0xd4,0x68,0x6d,0x22,0x87],
+        [0x29,0x39,0xb0,0x18,0x32,0x23,0xfa,0xfc,0x17,0x23,0xde,0x4f,0x52,0xc4,0x3d,0x35],
+        [0x7c,0x39,0x56,0xca,0x5e,0xea,0xfc,0x3e,0x36,0x3e,0x9d,0x55,0x65,0x46,0xeb,0x68],
+        [0x77,0xc6,0x07,0x71,0x46,0xf0,0x1c,0x32,0xb6,0xb6,0x9d,0x5f,0x4e,0xa9,0xff,0xcf],
+        [0x37,0xa6,0x98,0x6c,0xb8,0x84,0x7e,0xdf,0x09,0x25,0xf0,0xf1,0x30,0x9b,0x54,0xde],
+        [0xa7,0x05,0xf0,0xe6,0x9d,0xa9,0xa8,0xf9,0x07,0x24,0x1a,0x2e,0x92,0x3c,0x8c,0xc8],
+        [0x3d,0xc4,0x7d,0x1f,0x29,0xc4,0x48,0x46,0x1e,0x9e,0x76,0xed,0x90,0x4f,0x67,0x11],
+        [0x0d,0x62,0xbf,0x01,0xe6,0xfc,0x0e,0x1a,0x0d,0x3c,0x47,0x51,0xc5,0xd3,0x69,0x2b],
+        [0x8c,0x03,0x46,0x8b,0xca,0x7c,0x66,0x9e,0xe4,0xfd,0x5e,0x08,0x4b,0xbe,0xe7,0xb5],
+        [0x52,0x8a,0x5b,0xb9,0x3b,0xaf,0x2c,0x9c,0x44,0x73,0xcc,0xe5,0xd0,0xd2,0x2b,0xd9],
+        [0xdf,0x6a,0x30,0x1e,0x95,0xc9,0x5d,0xad,0x97,0xae,0x0c,0xc8,0xc6,0x91,0x3b,0xd8],
+        [0x80,0x11,0x89,0x90,0x2c,0x85,0x7f,0x39,0xe7,0x35,0x91,0x28,0x5e,0x70,0xb6,0xdb],
+        [0xe6,0x17,0x34,0x6a,0xc9,0xc2,0x31,0xbb,0x36,0x50,0xae,0x34,0xcc,0xca,0x0c,0x5b],
+        [0x27,0xd9,0x34,0x37,0xef,0xb7,0x21,0xaa,0x40,0x18,0x21,0xdc,0xec,0x5a,0xdf,0x89],
+        [0x89,0x23,0x7d,0x9d,0xed,0x9c,0x5e,0x78,0xd8,0xb1,0xc9,0xb1,0x66,0xcc,0x73,0x42],
+        [0x4a,0x6d,0x80,0x91,0xbf,0x5e,0x7d,0x65,0x11,0x89,0xfa,0x94,0xa2,0x50,0xb1,0x4c],
+        [0x0e,0x33,0xf9,0x60,0x55,0xe7,0xae,0x89,0x3f,0xfc,0x0e,0x3d,0xcf,0x49,0x29,0x02],
+        [0xe6,0x1c,0x43,0x2b,0x72,0x0b,0x19,0xd1,0x8e,0xc8,0xd8,0x4b,0xdc,0x63,0x15,0x1b],
+        [0xf7,0xe5,0xae,0xf5,0x49,0xf7,0x82,0xcf,0x37,0x90,0x55,0xa6,0x08,0x26,0x9b,0x16],
+        [0x43,0x8d,0x03,0x0f,0xd0,0xb7,0xa5,0x4f,0xa8,0x37,0xf2,0xad,0x20,0x1a,0x64,0x03],
+        [0xa5,0x90,0xd3,0xee,0x4f,0xbf,0x04,0xe3,0x24,0x7e,0x0d,0x27,0xf2,0x86,0x42,0x3f],
+        [0x5f,0xe2,0xc1,0xa1,0x72,0xfe,0x93,0xc4,0xb1,0x5c,0xd3,0x7c,0xae,0xf9,0xf5,0x38],
+        [0x2c,0x97,0x32,0x5c,0xbd,0x06,0xb3,0x6e,0xb2,0x13,0x3d,0xd0,0x8b,0x3a,0x01,0x7c],
+        [0x92,0xc8,0x14,0x22,0x7a,0x6b,0xca,0x94,0x9f,0xf0,0x65,0x9f,0x00,0x2a,0xd3,0x9e],
+        [0xdc,0xe8,0x50,0x11,0x0b,0xd8,0x32,0x8c,0xfb,0xd5,0x08,0x41,0xd6,0x91,0x1d,0x87],
+        [0x67,0xf1,0x49,0x84,0xc7,0xda,0x79,0x12,0x48,0xe3,0x2b,0xb5,0x92,0x25,0x83,0xda],
+        [0x19,0x38,0xf2,0xcf,0x72,0xd5,0x4e,0xe9,0x7e,0x94,0x16,0x6f,0xa9,0x1d,0x2a,0x36],
+        [0x74,0x48,0x1e,0x96,0x46,0xed,0x49,0xfe,0x0f,0x62,0x24,0x30,0x16,0x04,0x69,0x8e],
+        [0x57,0xfc,0xa5,0xde,0x98,0xa9,0xd6,0xd8,0x00,0x64,0x38,0xd0,0x58,0x3d,0x8a,0x1d],
+        [0x9f,0xec,0xde,0x1c,0xef,0xdc,0x1c,0xbe,0xd4,0x76,0x36,0x74,0xd9,0x57,0x53,0x59],
+        [0xe3,0x04,0x0c,0x00,0xeb,0x28,0xf1,0x53,0x66,0xca,0x73,0xcb,0xd8,0x72,0xe7,0x40],
+        [0x76,0x97,0x00,0x9a,0x6a,0x83,0x1d,0xfe,0xcc,0xa9,0x1c,0x59,0x93,0x67,0x0f,0x7a],
+        [0x58,0x53,0x54,0x23,0x21,0xf5,0x67,0xa0,0x05,0xd5,0x47,0xa4,0xf0,0x47,0x59,0xbd],
+        [0x51,0x50,0xd1,0x77,0x2f,0x50,0x83,0x4a,0x50,0x3e,0x06,0x9a,0x97,0x3f,0xbd,0x7c],
+    ];
+
+    // Test vector from reference implementation
+    #[test]
+    fn test_siphash_2_4_test_vector() {
+        let k0 = 0x_07_06_05_04_03_02_01_00;
+        let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08;
+
+        let mut input: Vec<u8> = Vec::new();
+
+        for i in 0 .. 64 {
+            let out = hash_with(SipHasher128::new_with_keys(k0, k1),
+                                &Bytes(&input[..]));
+            let expected = (
+                ((TEST_VECTOR[i][0] as u64) <<  0) |
+                ((TEST_VECTOR[i][1] as u64) <<  8) |
+                ((TEST_VECTOR[i][2] as u64) << 16) |
+                ((TEST_VECTOR[i][3] as u64) << 24) |
+                ((TEST_VECTOR[i][4] as u64) << 32) |
+                ((TEST_VECTOR[i][5] as u64) << 40) |
+                ((TEST_VECTOR[i][6] as u64) << 48) |
+                ((TEST_VECTOR[i][7] as u64) << 56),
+
+                ((TEST_VECTOR[i][8] as u64) <<  0) |
+                ((TEST_VECTOR[i][9] as u64) <<  8) |
+                ((TEST_VECTOR[i][10] as u64) << 16) |
+                ((TEST_VECTOR[i][11] as u64) << 24) |
+                ((TEST_VECTOR[i][12] as u64) << 32) |
+                ((TEST_VECTOR[i][13] as u64) << 40) |
+                ((TEST_VECTOR[i][14] as u64) << 48) |
+                ((TEST_VECTOR[i][15] as u64) << 56),
+            );
+
+            assert_eq!(out, expected);
+            input.push(i as u8);
+        }
+    }
+
+    #[test] #[cfg(target_arch = "arm")]
+    fn test_hash_usize() {
+        let val = 0xdeadbeef_deadbeef_u64;
+        assert!(hash(&(val as u64)) != hash(&(val as usize)));
+        assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
+    }
+    #[test] #[cfg(target_arch = "x86_64")]
+    fn test_hash_usize() {
+        let val = 0xdeadbeef_deadbeef_u64;
+        assert_eq!(hash(&(val as u64)), hash(&(val as usize)));
+        assert!(hash(&(val as u32)) != hash(&(val as usize)));
+    }
+    #[test] #[cfg(target_arch = "x86")]
+    fn test_hash_usize() {
+        let val = 0xdeadbeef_deadbeef_u64;
+        assert!(hash(&(val as u64)) != hash(&(val as usize)));
+        assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
+    }
+
+    #[test]
+    fn test_hash_idempotent() {
+        let val64 = 0xdeadbeef_deadbeef_u64;
+        assert_eq!(hash(&val64), hash(&val64));
+        let val32 = 0xdeadbeef_u32;
+        assert_eq!(hash(&val32), hash(&val32));
+    }
+
+    #[test]
+    fn test_hash_no_bytes_dropped_64() {
+        let val = 0xdeadbeef_deadbeef_u64;
+
+        assert!(hash(&val) != hash(&zero_byte(val, 0)));
+        assert!(hash(&val) != hash(&zero_byte(val, 1)));
+        assert!(hash(&val) != hash(&zero_byte(val, 2)));
+        assert!(hash(&val) != hash(&zero_byte(val, 3)));
+        assert!(hash(&val) != hash(&zero_byte(val, 4)));
+        assert!(hash(&val) != hash(&zero_byte(val, 5)));
+        assert!(hash(&val) != hash(&zero_byte(val, 6)));
+        assert!(hash(&val) != hash(&zero_byte(val, 7)));
+
+        fn zero_byte(val: u64, byte: usize) -> u64 {
+            assert!(byte < 8);
+            val & !(0xff << (byte * 8))
+        }
+    }
+
+    #[test]
+    fn test_hash_no_bytes_dropped_32() {
+        let val = 0xdeadbeef_u32;
+
+        assert!(hash(&val) != hash(&zero_byte(val, 0)));
+        assert!(hash(&val) != hash(&zero_byte(val, 1)));
+        assert!(hash(&val) != hash(&zero_byte(val, 2)));
+        assert!(hash(&val) != hash(&zero_byte(val, 3)));
+
+        fn zero_byte(val: u32, byte: usize) -> u32 {
+            assert!(byte < 4);
+            val & !(0xff << (byte * 8))
+        }
+    }
+
+    #[test]
+    fn test_hash_no_concat_alias() {
+        let s = ("aa", "bb");
+        let t = ("aabb", "");
+        let u = ("a", "abb");
+
+        assert!(s != t && t != u);
+        assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u));
+
+        let u = [1, 0, 0, 0];
+        let v = (&u[..1], &u[1..3], &u[3..]);
+        let w = (&u[..], &u[4..4], &u[4..4]);
+
+        assert!(v != w);
+        assert!(hash(&v) != hash(&w));
+    }
+
+    #[test]
+    fn test_write_short_works() {
+        let test_usize = 0xd0c0b0a0usize;
+        let mut h1 = SipHasher128::new_with_keys(0, 0);
+        h1.write_usize(test_usize);
+        h1.write(b"bytes");
+        h1.write(b"string");
+        h1.write_u8(0xFFu8);
+        h1.write_u8(0x01u8);
+        let mut h2 = SipHasher128::new_with_keys(0, 0);
+        h2.write(unsafe {
+            slice::from_raw_parts(&test_usize as *const _ as *const u8,
+                                  mem::size_of::<usize>())
+        });
+        h2.write(b"bytes");
+        h2.write(b"string");
+        h2.write(&[0xFFu8, 0x01u8]);
+        assert_eq!(h1.finish128(), h2.finish128());
+    }
+
+}
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index 9aba48c5bef..831e113016f 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -11,16 +11,7 @@
 use std::hash::{Hash, Hasher, BuildHasher};
 use std::marker::PhantomData;
 use std::mem;
-use blake2b::Blake2bHasher;
-use rustc_serialize::leb128;
-
-fn write_unsigned_leb128_to_buf(buf: &mut [u8; 16], value: u64) -> usize {
-    leb128::write_unsigned_leb128_to(value as u128, |i, v| buf[i] = v)
-}
-
-fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize {
-    leb128::write_signed_leb128_to(value as i128, |i, v| buf[i] = v)
-}
+use sip128::SipHasher128;
 
 /// When hashing something that ends up affecting properties like symbol names. We
 /// want these symbol names to be calculated independent of other factors like
@@ -41,7 +32,7 @@ fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize {
 /// and allows for variable output lengths through its type
 /// parameter.
 pub struct StableHasher<W> {
-    state: Blake2bHasher,
+    state: SipHasher128,
     bytes_hashed: u64,
     width: PhantomData<W>,
 }
@@ -59,7 +50,7 @@ pub trait StableHasherResult: Sized {
 impl<W: StableHasherResult> StableHasher<W> {
     pub fn new() -> Self {
         StableHasher {
-            state: Blake2bHasher::new(mem::size_of::<W>(), &[]),
+            state: SipHasher128::new_with_keys(0, 0),
             bytes_hashed: 0,
             width: PhantomData,
         }
@@ -70,58 +61,29 @@ impl<W: StableHasherResult> StableHasher<W> {
     }
 }
 
-impl StableHasherResult for [u8; 20] {
-    fn finish(mut hasher: StableHasher<Self>) -> Self {
-        let mut result: [u8; 20] = [0; 20];
-        result.copy_from_slice(hasher.state.finalize());
-        result
-    }
-}
-
 impl StableHasherResult for u128 {
-    fn finish(mut hasher: StableHasher<Self>) -> Self {
-        let hash_bytes: &[u8] = hasher.finalize();
-        assert!(hash_bytes.len() >= mem::size_of::<u128>());
-
-        unsafe {
-            ::std::ptr::read_unaligned(hash_bytes.as_ptr() as *const u128)
-        }
+    fn finish(hasher: StableHasher<Self>) -> Self {
+        let (_0, _1) = hasher.finalize();
+        (_0 as u128) | ((_1 as u128) << 64)
     }
 }
 
 impl StableHasherResult for u64 {
-    fn finish(mut hasher: StableHasher<Self>) -> Self {
-        hasher.state.finalize();
-        hasher.state.finish()
+    fn finish(hasher: StableHasher<Self>) -> Self {
+        hasher.finalize().0
     }
 }
 
 impl<W> StableHasher<W> {
     #[inline]
-    pub fn finalize(&mut self) -> &[u8] {
-        self.state.finalize()
+    pub fn finalize(self) -> (u64, u64) {
+        self.state.finish128()
     }
 
     #[inline]
     pub fn bytes_hashed(&self) -> u64 {
         self.bytes_hashed
     }
-
-    #[inline]
-    fn write_uleb128(&mut self, value: u64) {
-        let mut buf = [0; 16];
-        let len = write_unsigned_leb128_to_buf(&mut buf, value);
-        self.state.write(&buf[..len]);
-        self.bytes_hashed += len as u64;
-    }
-
-    #[inline]
-    fn write_ileb128(&mut self, value: i64) {
-        let mut buf = [0; 16];
-        let len = write_signed_leb128_to_buf(&mut buf, value);
-        self.state.write(&buf[..len]);
-        self.bytes_hashed += len as u64;
-    }
 }
 
 // For the non-u8 integer cases we leb128 encode them first. Because small
@@ -129,7 +91,7 @@ impl<W> StableHasher<W> {
 // bytes hashed, which is good because blake2b is expensive.
 impl<W> Hasher for StableHasher<W> {
     fn finish(&self) -> u64 {
-        panic!("use StableHasher::finish instead");
+        panic!("use StableHasher::finalize instead");
     }
 
     #[inline]
@@ -146,22 +108,32 @@ impl<W> Hasher for StableHasher<W> {
 
     #[inline]
     fn write_u16(&mut self, i: u16) {
-        self.write_uleb128(i as u64);
+        self.state.write_u16(i.to_le());
+        self.bytes_hashed += 2;
     }
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        self.write_uleb128(i as u64);
+        self.state.write_u32(i.to_le());
+        self.bytes_hashed += 4;
     }
 
     #[inline]
     fn write_u64(&mut self, i: u64) {
-        self.write_uleb128(i);
+        self.state.write_u64(i.to_le());
+        self.bytes_hashed += 8;
+    }
+
+    #[inline]
+    fn write_u128(&mut self, i: u128) {
+        self.state.write_u128(i.to_le());
+        self.bytes_hashed += 16;
     }
 
     #[inline]
     fn write_usize(&mut self, i: usize) {
-        self.write_uleb128(i as u64);
+        self.state.write_usize(i.to_le());
+        self.bytes_hashed += ::std::mem::size_of::<usize>() as u64;
     }
 
     #[inline]
@@ -172,22 +144,32 @@ impl<W> Hasher for StableHasher<W> {
 
     #[inline]
     fn write_i16(&mut self, i: i16) {
-        self.write_ileb128(i as i64);
+        self.state.write_i16(i.to_le());
+        self.bytes_hashed += 2;
     }
 
     #[inline]
     fn write_i32(&mut self, i: i32) {
-        self.write_ileb128(i as i64);
+        self.state.write_i32(i.to_le());
+        self.bytes_hashed += 4;
     }
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        self.write_ileb128(i);
+        self.state.write_i64(i.to_le());
+        self.bytes_hashed += 8;
+    }
+
+    #[inline]
+    fn write_i128(&mut self, i: i128) {
+        self.state.write_i128(i.to_le());
+        self.bytes_hashed += 16;
     }
 
     #[inline]
     fn write_isize(&mut self, i: isize) {
-        self.write_ileb128(i as i64);
+        self.state.write_isize(i.to_le());
+        self.bytes_hashed += ::std::mem::size_of::<isize>() as u64;
     }
 }
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index ad6f7fbf111..7dbf93da385 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -38,7 +38,7 @@ use rustc_typeck as typeck;
 use rustc_privacy;
 use rustc_plugin::registry::Registry;
 use rustc_plugin as plugin;
-use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats};
+use rustc_passes::{self, ast_validation, no_asm, loops, consts, static_recursion, hir_stats};
 use rustc_const_eval::{self, check_match};
 use super::Compilation;
 use ::DefaultTransCrate;
@@ -973,6 +973,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     traits::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
     rustc_const_eval::provide(&mut local_providers);
+    rustc_passes::provide(&mut local_providers);
     middle::region::provide(&mut local_providers);
     cstore::provide_local(&mut local_providers);
     lint::provide(&mut local_providers);
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 6bdad0b212c..3514302c6c8 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -1238,7 +1238,7 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
                              errors::Level::Note);
             }
 
-            writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap();
+            eprintln!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
         }
 
         exit_on_err();
@@ -1259,7 +1259,6 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     let mut all_errors = Vec::new();
     all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
-    all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
     #[cfg(feature="llvm")]
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 33a9cb58c51..0cb920a111d 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -13,12 +13,12 @@
 //! we will compare the fingerprint from the current and from the previous
 //! compilation session as appropriate:
 //!
-//! - `#[rustc_dirty(label="TypeckTables", cfg="rev2")]` if we are
+//! - `#[rustc_clean(cfg="rev2", except="TypeckTables")]` if we are
 //!   in `#[cfg(rev2)]`, then the fingerprints associated with
 //!   `DepNode::TypeckTables(X)` must be DIFFERENT (`X` is the def-id of the
 //!   current node).
-//! - `#[rustc_clean(label="TypeckTables", cfg="rev2")]` same as above,
-//!   except that the fingerprints must be the SAME.
+//! - `#[rustc_clean(cfg="rev2")]` same as above, except that the
+//!   fingerprints must be the SAME (along with all other fingerprints).
 //!
 //! Errors are reported if we are in the suitable configuration but
 //! the required condition is not met.
@@ -39,8 +39,13 @@
 //! previous revision to compare things to.
 //!
 
-use rustc::dep_graph::DepNode;
+use std::collections::HashSet;
+use std::iter::FromIterator;
+use std::vec::Vec;
+use rustc::dep_graph::{DepNode, label_strs};
 use rustc::hir;
+use rustc::hir::{Item_ as HirItem, ImplItemKind, TraitItemKind};
+use rustc::hir::map::Node as HirNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit;
@@ -51,8 +56,182 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use syntax_pos::Span;
 use rustc::ty::TyCtxt;
 
-const LABEL: &'static str = "label";
-const CFG: &'static str = "cfg";
+const EXCEPT: &str = "except";
+const LABEL: &str = "label";
+const CFG: &str = "cfg";
+
+// Base and Extra labels to build up the labels
+
+/// For typedef, constants, and statics
+const BASE_CONST: &[&str] = &[
+    label_strs::TypeOfItem,
+];
+
+/// DepNodes for functions + methods
+const BASE_FN: &[&str] = &[
+    // Callers will depend on the signature of these items, so we better test
+    label_strs::FnSignature,
+    label_strs::GenericsOfItem,
+    label_strs::PredicatesOfItem,
+    label_strs::TypeOfItem,
+
+    // And a big part of compilation (that we eventually want to cache) is type inference
+    // information:
+    label_strs::TypeckTables,
+];
+
+/// DepNodes for Hir, which is pretty much everything
+const BASE_HIR: &[&str] = &[
+    // Hir and HirBody should be computed for all nodes
+    label_strs::Hir,
+    label_strs::HirBody,
+];
+
+/// `impl` implementation of struct/trait
+const BASE_IMPL: &[&str] = &[
+    label_strs::AssociatedItemDefIds,
+    label_strs::GenericsOfItem,
+    label_strs::ImplTraitRef,
+];
+
+/// DepNodes for MirValidated/Optimized, which is relevant in "executable"
+/// code, i.e. functions+methods
+const BASE_MIR: &[&str] = &[
+    label_strs::MirOptimized,
+    label_strs::MirValidated,
+];
+
+/// Struct, Enum and Union DepNodes
+///
+/// Note that changing the type of a field does not change the type of the struct or enum, but
+/// adding/removing fields or changing a fields name or visibility does.
+const BASE_STRUCT: &[&str] = &[
+    label_strs::GenericsOfItem,
+    label_strs::PredicatesOfItem,
+    label_strs::TypeOfItem,
+];
+
+/// Trait Definition DepNodes
+const BASE_TRAIT_DEF: &[&str] = &[
+    label_strs::AssociatedItemDefIds,
+    label_strs::GenericsOfItem,
+    label_strs::ObjectSafety,
+    label_strs::PredicatesOfItem,
+    label_strs::SpecializationGraph,
+    label_strs::TraitDefOfItem,
+    label_strs::TraitImpls,
+];
+
+/// extra DepNodes for methods (+fn)
+const EXTRA_ASSOCIATED: &[&str] = &[
+    label_strs::AssociatedItems,
+];
+
+const EXTRA_TRAIT: &[&str] = &[
+    label_strs::TraitOfItem,
+];
+
+// Fully Built Labels
+
+const LABELS_CONST: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_CONST,
+];
+
+/// Constant/Typedef in an impl
+const LABELS_CONST_IN_IMPL: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_CONST,
+    EXTRA_ASSOCIATED,
+];
+
+/// Trait-Const/Typedef DepNodes
+const LABELS_CONST_IN_TRAIT: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_CONST,
+    EXTRA_ASSOCIATED,
+    EXTRA_TRAIT,
+];
+
+/// Function DepNode
+const LABELS_FN: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_MIR,
+    BASE_FN,
+];
+
+/// Method DepNodes
+const LABELS_FN_IN_IMPL: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_MIR,
+    BASE_FN,
+    EXTRA_ASSOCIATED,
+];
+
+/// Trait-Method DepNodes
+const LABELS_FN_IN_TRAIT: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_MIR,
+    BASE_FN,
+    EXTRA_ASSOCIATED,
+    EXTRA_TRAIT,
+];
+
+/// For generic cases like inline-assemply/mod/etc
+const LABELS_HIR_ONLY: &[&[&str]] = &[
+    BASE_HIR,
+];
+
+/// Impl DepNodes
+const LABELS_IMPL: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_IMPL,
+];
+
+/// Abstract Data Type (Struct, Enum, Unions) DepNodes
+const LABELS_ADT: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_STRUCT,
+];
+
+/// Trait Definition DepNodes
+#[allow(dead_code)]
+const LABELS_TRAIT: &[&[&str]] = &[
+    BASE_HIR,
+    BASE_TRAIT_DEF,
+];
+
+
+// FIXME: Struct/Enum/Unions Fields (there is currently no way to attach these)
+//
+// Fields are kind of separate from their containers, as they can change independently from
+// them. We should at least check
+//
+//     TypeOfItem for these.
+
+type Labels = HashSet<String>;
+
+/// Represents the requested configuration by rustc_clean/dirty
+struct Assertion {
+    clean: Labels,
+    dirty: Labels,
+}
+
+impl Assertion {
+    fn from_clean_labels(labels: Labels) -> Assertion {
+        Assertion {
+            clean: labels,
+            dirty: Labels::new(),
+        }
+    }
+
+    fn from_dirty_labels(labels: Labels) -> Assertion {
+        Assertion {
+            clean: Labels::new(),
+            dirty: labels,
+        }
+    }
+}
 
 pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // can't add `#[rustc_dirty]` etc without opting in to this feature
@@ -87,23 +266,221 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
-    fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode {
-        let def_path_hash = self.tcx.def_path_hash(def_id);
+
+    /// Possibly "deserialize" the attribute into a clean/dirty assertion
+    fn assertion_maybe(&mut self, item_id: ast::NodeId, attr: &Attribute)
+        -> Option<Assertion>
+    {
+        let is_clean = if attr.check_name(ATTR_DIRTY) {
+            false
+        } else if attr.check_name(ATTR_CLEAN) {
+            true
+        } else {
+            // skip: not rustc_clean/dirty
+            return None
+        };
+        if !check_config(self.tcx, attr) {
+            // skip: not the correct `cfg=`
+            return None;
+        }
+        let assertion = if let Some(labels) = self.labels(attr) {
+            if is_clean {
+                Assertion::from_clean_labels(labels)
+            } else {
+                Assertion::from_dirty_labels(labels)
+            }
+        } else {
+            self.assertion_auto(item_id, attr, is_clean)
+        };
+        Some(assertion)
+    }
+
+    /// Get the "auto" assertion on pre-validated attr, along with the `except` labels
+    fn assertion_auto(&mut self, item_id: ast::NodeId, attr: &Attribute, is_clean: bool)
+        -> Assertion
+    {
+        let (name, mut auto) = self.auto_labels(item_id, attr);
+        let except = self.except(attr);
+        for e in except.iter() {
+            if !auto.remove(e) {
+                let msg = format!(
+                    "`except` specified DepNodes that can not be affected for \"{}\": \"{}\"",
+                    name,
+                    e
+                );
+                self.tcx.sess.span_fatal(attr.span, &msg);
+            }
+        }
+        if is_clean {
+            Assertion {
+                clean: auto,
+                dirty: except,
+            }
+        } else {
+            Assertion {
+                clean: except,
+                dirty: auto,
+            }
+        }
+    }
+
+    fn labels(&self, attr: &Attribute) -> Option<Labels> {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
             if item.check_name(LABEL) {
                 let value = expect_associated_value(self.tcx, &item);
-                match DepNode::from_label_string(&value.as_str(), def_path_hash) {
-                    Ok(dep_node) => return dep_node,
-                    Err(()) => {
-                        self.tcx.sess.span_fatal(
-                            item.span,
-                            &format!("dep-node label `{}` not recognized", value));
-                    }
+                return Some(self.resolve_labels(&item, value.as_str().as_ref()));
+            }
+        }
+        None
+    }
+
+    /// `except=` attribute value
+    fn except(&self, attr: &Attribute) -> Labels {
+        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+            if item.check_name(EXCEPT) {
+                let value = expect_associated_value(self.tcx, &item);
+                return self.resolve_labels(&item, value.as_str().as_ref());
+            }
+        }
+        // if no `label` or `except` is given, only the node's group are asserted
+        Labels::new()
+    }
+
+    /// Return all DepNode labels that should be asserted for this item.
+    /// index=0 is the "name" used for error messages
+    fn auto_labels(&mut self, item_id: ast::NodeId, attr: &Attribute) -> (&'static str, Labels) {
+        let node = self.tcx.hir.get(item_id);
+        let (name, labels) = match node {
+            HirNode::NodeItem(item) => {
+                match item.node {
+                    // note: these are in the same order as hir::Item_;
+                    // FIXME(michaelwoerister): do commented out ones
+
+                    // // An `extern crate` item, with optional original crate name,
+                    // HirItem::ItemExternCrate(..),  // intentionally no assertions
+
+                    // // `use foo::bar::*;` or `use foo::bar::baz as quux;`
+                    // HirItem::ItemUse(..),  // intentionally no assertions
+
+                    // A `static` item
+                    HirItem::ItemStatic(..) => ("ItemStatic", LABELS_CONST),
+
+                    // A `const` item
+                    HirItem::ItemConst(..) => ("ItemConst", LABELS_CONST),
+
+                    // A function declaration
+                    HirItem::ItemFn(..) => ("ItemFn", LABELS_FN),
+
+                    // // A module
+                    HirItem::ItemMod(..) =>("ItemMod", LABELS_HIR_ONLY),
+
+                    // // An external module
+                    HirItem::ItemForeignMod(..) => ("ItemForeignMod", LABELS_HIR_ONLY),
+
+                    // Module-level inline assembly (from global_asm!)
+                    HirItem::ItemGlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY),
+
+                    // A type alias, e.g. `type Foo = Bar<u8>`
+                    HirItem::ItemTy(..) => ("ItemTy", LABELS_HIR_ONLY),
+
+                    // An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
+                    HirItem::ItemEnum(..) => ("ItemEnum", LABELS_ADT),
+
+                    // A struct definition, e.g. `struct Foo<A> {x: A}`
+                    HirItem::ItemStruct(..) => ("ItemStruct", LABELS_ADT),
+
+                    // A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
+                    HirItem::ItemUnion(..) => ("ItemUnion", LABELS_ADT),
+
+                    // Represents a Trait Declaration
+                    // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of
+                    // the depnodes don't exist (because they legitametely didn't need to be
+                    // calculated)
+                    //
+                    // michaelwoerister and vitiral came up with a possible solution,
+                    // to just do this before every query
+                    // ```
+                    // ::rustc::ty::maps::plumbing::force_from_dep_node(tcx, dep_node)
+                    // ```
+                    //
+                    // However, this did not seem to work effectively and more bugs were hit.
+                    // Nebie @vitiral gave up :)
+                    //
+                    //HirItem::ItemTrait(..) => ("ItemTrait", LABELS_TRAIT),
+
+                    // `impl Trait for .. {}`
+                    HirItem::ItemDefaultImpl(..) => ("ItemDefaultImpl", LABELS_IMPL),
+
+                    // An implementation, eg `impl<A> Trait for Foo { .. }`
+                    HirItem::ItemImpl(..) => ("ItemImpl", LABELS_IMPL),
+
+                    _ => self.tcx.sess.span_fatal(
+                        attr.span,
+                        &format!(
+                            "clean/dirty auto-assertions not yet defined for NodeItem.node={:?}",
+                            item.node
+                        )
+                    ),
+                }
+            },
+            HirNode::NodeTraitItem(item) => {
+                match item.node {
+                    TraitItemKind::Method(..) => ("NodeTraitItem", LABELS_FN_IN_TRAIT),
+                    TraitItemKind::Const(..) => ("NodeTraitConst", LABELS_CONST_IN_TRAIT),
+                    TraitItemKind::Type(..) => ("NodeTraitType", LABELS_CONST_IN_TRAIT),
+                }
+            },
+            HirNode::NodeImplItem(item) => {
+                match item.node {
+                    ImplItemKind::Method(..) => ("NodeImplItem", LABELS_FN_IN_IMPL),
+                    ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
+                    ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
+                }
+            },
+            _ => self.tcx.sess.span_fatal(
+                attr.span,
+                &format!(
+                    "clean/dirty auto-assertions not yet defined for {:?}",
+                    node
+                )
+            ),
+        };
+        let labels = Labels::from_iter(
+            labels.iter().flat_map(|s| s.iter().map(|l| l.to_string()))
+        );
+        (name, labels)
+    }
+
+    fn resolve_labels(&self, item: &NestedMetaItem, value: &str) -> Labels {
+        let mut out: Labels = HashSet::new();
+        for label in value.split(',') {
+            let label = label.trim();
+            if DepNode::has_label_string(label) {
+                if out.contains(label) {
+                    self.tcx.sess.span_fatal(
+                        item.span,
+                        &format!("dep-node label `{}` is repeated", label));
                 }
+                out.insert(label.to_string());
+            } else {
+                self.tcx.sess.span_fatal(
+                    item.span,
+                    &format!("dep-node label `{}` not recognized", label));
             }
         }
+        out
+    }
 
-        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+    fn dep_nodes(&self, labels: &Labels, def_id: DefId) -> Vec<DepNode> {
+        let mut out = Vec::with_capacity(labels.len());
+        let def_path_hash = self.tcx.def_path_hash(def_id);
+        for label in labels.iter() {
+            match DepNode::from_label_string(label, def_path_hash) {
+                Ok(dep_node) => out.push(dep_node),
+                Err(()) => unreachable!(),
+            }
+        }
+        out
     }
 
     fn dep_node_str(&self, dep_node: &DepNode) -> String {
@@ -147,16 +524,16 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
     fn check_item(&mut self, item_id: ast::NodeId, item_span: Span) {
         let def_id = self.tcx.hir.local_def_id(item_id);
         for attr in self.tcx.get_attrs(def_id).iter() {
-            if attr.check_name(ATTR_DIRTY) {
-                if check_config(self.tcx, attr) {
-                    self.checked_attrs.insert(attr.id);
-                    self.assert_dirty(item_span, self.dep_node(attr, def_id));
-                }
-            } else if attr.check_name(ATTR_CLEAN) {
-                if check_config(self.tcx, attr) {
-                    self.checked_attrs.insert(attr.id);
-                    self.assert_clean(item_span, self.dep_node(attr, def_id));
-                }
+            let assertion = match self.assertion_maybe(item_id, attr) {
+                Some(a) => a,
+                None => continue,
+            };
+            self.checked_attrs.insert(attr.id);
+            for dep_node in self.dep_nodes(&assertion.clean, def_id) {
+                self.assert_clean(item_span, dep_node);
+            }
+            for dep_node in self.dep_nodes(&assertion.dirty, def_id) {
+                self.assert_dirty(item_span, dep_node);
             }
         }
     }
@@ -330,21 +707,42 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
 /// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
 /// for a `cfg="foo"` attribute and check whether we have a cfg
 /// flag called `foo`.
+///
+/// Also make sure that the `label` and `except` fields do not
+/// both exist.
 fn check_config(tcx: TyCtxt, attr: &Attribute) -> bool {
     debug!("check_config(attr={:?})", attr);
     let config = &tcx.sess.parse_sess.config;
     debug!("check_config: config={:?}", config);
+    let (mut cfg, mut except, mut label) = (None, false, false);
     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
         if item.check_name(CFG) {
             let value = expect_associated_value(tcx, &item);
             debug!("check_config: searching for cfg {:?}", value);
-            return config.contains(&(value, None));
+            cfg = Some(config.contains(&(value, None)));
+        }
+        if item.check_name(LABEL) {
+            label = true;
+        }
+        if item.check_name(EXCEPT) {
+            except = true;
         }
     }
 
-    tcx.sess.span_fatal(
-        attr.span,
-        "no cfg attribute");
+    if label && except {
+        tcx.sess.span_fatal(
+            attr.span,
+            "must specify only one of: `label`, `except`"
+        );
+    }
+
+    match cfg {
+        None => tcx.sess.span_fatal(
+            attr.span,
+            "no cfg attribute"
+        ),
+        Some(c) => c,
+    }
 }
 
 fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name {
diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs
index 13b019af2ea..7d1400b6b95 100644
--- a/src/librustc_incremental/persist/file_format.rs
+++ b/src/librustc_incremental/persist/file_format.rs
@@ -117,7 +117,7 @@ fn report_format_mismatch(sess: &Session, file: &Path, message: &str) {
     debug!("read_file: {}", message);
 
     if sess.opts.debugging_opts.incremental_info {
-        eprintln!("incremental: ignoring cache artifact `{}`: {}",
+        println!("[incremental] ignoring cache artifact `{}`: {}",
                   file.file_name().unwrap().to_string_lossy(),
                   message);
     }
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index 9b12b755581..d53ee5c804f 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -256,11 +256,12 @@ pub fn prepare_session_directory(sess: &Session,
         debug!("attempting to copy data from source: {}",
                source_directory.display());
 
-        let print_file_copy_stats = sess.opts.debugging_opts.incremental_info;
+
 
         // Try copying over all files from the source directory
-        if let Ok(allows_links) = copy_files(&session_dir, &source_directory,
-                                             print_file_copy_stats) {
+        if let Ok(allows_links) = copy_files(sess,
+                                             &session_dir,
+                                             &source_directory) {
             debug!("successfully copied data from: {}",
                    source_directory.display());
 
@@ -390,9 +391,9 @@ pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> {
     Ok(())
 }
 
-fn copy_files(target_dir: &Path,
-              source_dir: &Path,
-              print_stats_on_success: bool)
+fn copy_files(sess: &Session,
+              target_dir: &Path,
+              source_dir: &Path)
               -> Result<bool, ()> {
     // We acquire a shared lock on the lock file of the directory, so that
     // nobody deletes it out from under us while we are reading from it.
@@ -440,9 +441,11 @@ fn copy_files(target_dir: &Path,
         }
     }
 
-    if print_stats_on_success {
-        eprintln!("incremental: session directory: {} files hard-linked", files_linked);
-        eprintln!("incremental: session directory: {} files copied", files_copied);
+    if sess.opts.debugging_opts.incremental_info {
+        println!("[incremental] session directory: \
+                  {} files hard-linked", files_linked);
+        println!("[incremental] session directory: \
+                 {} files copied", files_copied);
     }
 
     Ok(files_linked > 0 || files_copied == 0)
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index cdfc9f2edc3..63cfbcac145 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -177,8 +177,8 @@ pub fn load_dep_graph(sess: &Session) -> PreviousDepGraph {
 
         if prev_commandline_args_hash != sess.opts.dep_tracking_hash() {
             if sess.opts.debugging_opts.incremental_info {
-                eprintln!("incremental: completely ignoring cache because of \
-                           differing commandline arguments");
+                println!("[incremental] completely ignoring cache because of \
+                          differing commandline arguments");
             }
             // We can't reuse the cache, purge it.
             debug!("load_dep_graph_new: differing commandline arg hashes");
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 4919870fcd5..b9f73500e27 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::dep_graph::DepGraph;
+use rustc::dep_graph::{DepGraph, DepKind};
 use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
 use rustc::ich::Fingerprint;
@@ -170,6 +170,77 @@ fn encode_dep_graph(tcx: TyCtxt,
 
     // Encode the graph data.
     let serialized_graph = tcx.dep_graph.serialize();
+
+    if tcx.sess.opts.debugging_opts.incremental_info {
+        #[derive(Clone)]
+        struct Stat {
+            kind: DepKind,
+            node_counter: u64,
+            edge_counter: u64,
+        }
+
+        let total_node_count = serialized_graph.nodes.len();
+        let total_edge_count = serialized_graph.edge_list_data.len();
+
+        let mut counts: FxHashMap<_, Stat> = FxHashMap();
+
+        for (i, &(node, _)) in serialized_graph.nodes.iter_enumerated() {
+            let stat = counts.entry(node.kind).or_insert(Stat {
+                kind: node.kind,
+                node_counter: 0,
+                edge_counter: 0,
+            });
+
+            stat.node_counter += 1;
+            let (edge_start, edge_end) = serialized_graph.edge_list_indices[i];
+            stat.edge_counter += (edge_end - edge_start) as u64;
+        }
+
+        let mut counts: Vec<_> = counts.values().cloned().collect();
+        counts.sort_by_key(|s| -(s.node_counter as i64));
+
+        let percentage_of_all_nodes: Vec<f64> = counts.iter().map(|s| {
+            (100.0 * (s.node_counter as f64)) / (total_node_count as f64)
+        }).collect();
+
+        let average_edges_per_kind: Vec<f64> = counts.iter().map(|s| {
+            (s.edge_counter as f64) / (s.node_counter as f64)
+        }).collect();
+
+        println!("[incremental]");
+        println!("[incremental] DepGraph Statistics");
+
+        const SEPARATOR: &str = "[incremental] --------------------------------\
+                                 ----------------------------------------------\
+                                 ------------";
+
+        println!("{}", SEPARATOR);
+        println!("[incremental]");
+        println!("[incremental] Total Node Count: {}", total_node_count);
+        println!("[incremental] Total Edge Count: {}", total_edge_count);
+        println!("[incremental]");
+        println!("[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
+                 "Node Kind",
+                 "Node Frequency",
+                 "Node Count",
+                 "Avg. Edge Count");
+        println!("[incremental] -------------------------------------\
+                  |------------------\
+                  |-------------\
+                  |------------------|");
+
+        for (i, stat) in counts.iter().enumerate() {
+            println!("[incremental]  {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
+                format!("{:?}", stat.kind),
+                percentage_of_all_nodes[i],
+                stat.node_counter,
+                average_edges_per_kind[i]);
+        }
+
+        println!("{}", SEPARATOR);
+        println!("[incremental]");
+    }
+
     serialized_graph.encode(encoder)?;
 
     Ok(())
diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs
index 9865e8fb173..f23b8dc85b8 100644
--- a/src/librustc_incremental/persist/work_product.rs
+++ b/src/librustc_incremental/persist/work_product.rs
@@ -11,9 +11,8 @@
 //! This module contains files for saving intermediate work-products.
 
 use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph};
+use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
 use rustc::session::Session;
-use rustc::session::config::OutputType;
 use rustc::util::fs::link_or_copy;
 use std::path::PathBuf;
 use std::fs as std_fs;
@@ -21,19 +20,24 @@ use std::fs as std_fs;
 pub fn save_trans_partition(sess: &Session,
                             dep_graph: &DepGraph,
                             cgu_name: &str,
-                            files: &[(OutputType, PathBuf)]) {
+                            files: &[(WorkProductFileKind, PathBuf)]) {
     debug!("save_trans_partition({:?},{:?})",
            cgu_name,
            files);
     if sess.opts.incremental.is_none() {
-        return;
+        return
     }
     let work_product_id = WorkProductId::from_cgu_name(cgu_name);
 
     let saved_files: Option<Vec<_>> =
         files.iter()
              .map(|&(kind, ref path)| {
-                 let file_name = format!("cgu-{}.{}", cgu_name, kind.extension());
+                 let extension = match kind {
+                     WorkProductFileKind::Object => "o",
+                     WorkProductFileKind::Bytecode => "bc",
+                     WorkProductFileKind::BytecodeCompressed => "bc-compressed",
+                 };
+                 let file_name = format!("cgu-{}.{}", cgu_name, extension);
                  let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
                  match link_or_copy(path, &path_in_incr_dir) {
                      Ok(_) => Some((kind, file_name)),
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index c3c5461ff7c..cebf52d5af7 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -12,7 +12,6 @@ test = false
 [dependencies]
 log = "0.3"
 rustc = { path = "../librustc" }
-rustc_back = { path = "../librustc_back" }
 rustc_const_eval = { path = "../librustc_const_eval" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 7f331418d42..bc2a1f08441 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -44,7 +44,7 @@ use std::collections::HashSet;
 use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
-use syntax_pos::{Span, SyntaxContext};
+use syntax_pos::{BytePos, Span, SyntaxContext};
 use syntax::symbol::keywords;
 
 use rustc::hir::{self, PatKind};
@@ -153,7 +153,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers {
 declare_lint! {
     NON_SHORTHAND_FIELD_PATTERNS,
     Warn,
-    "using `Struct { x: x }` instead of `Struct { x }`"
+    "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
 }
 
 #[derive(Copy, Clone)]
@@ -174,11 +174,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
                 }
                 if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node {
                     if ident.node == fieldpat.node.name {
-                        cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
+                        let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS,
                                      fieldpat.span,
-                                     &format!("the `{}:` in this pattern is redundant and can \
-                                              be removed",
-                                              ident.node))
+                                     &format!("the `{}:` in this pattern is redundant",
+                                              ident.node));
+                        let subspan = cx.tcx.sess.codemap().span_through_char(fieldpat.span, ':');
+                        err.span_suggestion_short(subspan,
+                                                  "remove this",
+                                                  format!("{}", ident.node));
+                        err.emit();
                     }
                 }
             }
@@ -894,7 +898,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
                                              sp,
                                              "function cannot return without recurring");
-            // FIXME #19668: these could be span_lint_note's instead of this manual guard.
             // offer some help to the programmer.
             for call in &self_call_spans {
                 db.span_note(*call, "recursive call site");
@@ -1130,35 +1133,55 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
             hir::ItemFn(.., ref generics, _) => {
-                if attr::contains_name(&it.attrs, "no_mangle") &&
-                   !attr::contains_name(&it.attrs, "linkage") {
+                if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, "no_mangle") {
+                    if attr::contains_name(&it.attrs, "linkage") {
+                        return;
+                    }
                     if !cx.access_levels.is_reachable(it.id) {
-                        let msg = format!("function {} is marked #[no_mangle], but not exported",
-                                          it.name);
-                        cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
+                        let msg = "function is marked #[no_mangle], but not exported";
+                        let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg);
+                        let insertion_span = it.span.with_hi(it.span.lo());
+                        err.span_suggestion(insertion_span,
+                                            "try making it public",
+                                            "pub ".to_owned());
+                        err.emit();
                     }
                     if generics.is_type_parameterized() {
-                        cx.span_lint(NO_MANGLE_GENERIC_ITEMS,
-                                     it.span,
-                                     "functions generic over types must be mangled");
+                        let mut err = cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS,
+                                                          it.span,
+                                                          "functions generic over \
+                                                           types must be mangled");
+                        err.span_suggestion_short(no_mangle_attr.span,
+                                                  "remove this attribute",
+                                                  "".to_owned());
+                        err.emit();
                     }
                 }
             }
             hir::ItemStatic(..) => {
                 if attr::contains_name(&it.attrs, "no_mangle") &&
                    !cx.access_levels.is_reachable(it.id) {
-                    let msg = format!("static {} is marked #[no_mangle], but not exported",
-                                      it.name);
-                    cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
+                       let msg = "static is marked #[no_mangle], but not exported";
+                       let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg);
+                       let insertion_span = it.span.with_hi(it.span.lo());
+                       err.span_suggestion(insertion_span,
+                                           "try making it public",
+                                           "pub ".to_owned());
+                       err.emit();
                 }
             }
             hir::ItemConst(..) => {
                 if attr::contains_name(&it.attrs, "no_mangle") {
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
-                    let msg = "const items should never be #[no_mangle], consider instead using \
-                               `pub static`";
-                    cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
+                    let msg = "const items should never be #[no_mangle]";
+                    let mut err = cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
+                    // `const` is 5 chars
+                    let const_span = it.span.with_hi(BytePos(it.span.lo().0 + 5));
+                    err.span_suggestion(const_span,
+                                        "try a static value",
+                                        "pub static".to_owned());
+                    err.emit();
                 }
             }
             _ => {}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index fbf993f4557..4ba7f7aa951 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -38,7 +38,6 @@ extern crate syntax;
 extern crate rustc;
 #[macro_use]
 extern crate log;
-extern crate rustc_back;
 extern crate rustc_const_eval;
 extern crate syntax_pos;
 
@@ -129,7 +128,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                  NonUpperCaseGlobals,
                  NonShorthandFieldPatterns,
                  UnsafeCode,
-                 UnusedMut,
                  UnusedAllocation,
                  MissingCopyImplementations,
                  UnstableFeatures,
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index d3a5d52b295..38461b0b364 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -431,7 +431,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         // fields are actually safe.
                         let mut all_phantom = true;
                         for field in &def.struct_variant().fields {
-                            let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+                            let field_ty = cx.fully_normalize_associated_types_in(
+                                &field.ty(cx, substs)
+                            );
                             let r = self.check_type_for_ffi(cache, field_ty);
                             match r {
                                 FfiSafe => {
@@ -463,7 +465,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
                         let mut all_phantom = true;
                         for field in &def.struct_variant().fields {
-                            let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+                            let field_ty = cx.fully_normalize_associated_types_in(
+                                &field.ty(cx, substs)
+                            );
                             let r = self.check_type_for_ffi(cache, field_ty);
                             match r {
                                 FfiSafe => {
@@ -516,7 +520,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         // Check the contained variants.
                         for variant in &def.variants {
                             for field in &variant.fields {
-                                let arg = cx.normalize_associated_type(&field.ty(cx, substs));
+                                let arg = cx.fully_normalize_associated_types_in(
+                                    &field.ty(cx, substs)
+                                );
                                 let r = self.check_type_for_ffi(cache, arg);
                                 match r {
                                     FfiSafe => {}
@@ -629,7 +635,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
         // it is only OK to use this function because extern fns cannot have
         // any generic types right now:
-        let ty = self.cx.tcx.normalize_associated_type(&ty);
+        let ty = self.cx.tcx.fully_normalize_associated_types_in(&ty);
 
         match self.check_type_for_ffi(&mut FxHashSet(), ty) {
             FfiResult::FfiSafe => {}
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index e2ade19b6e2..a058f84e588 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -11,105 +11,18 @@
 use rustc::hir::def_id::DefId;
 use rustc::ty;
 use rustc::ty::adjustment;
-use util::nodemap::FxHashMap;
 use lint::{LateContext, EarlyContext, LintContext, LintArray};
 use lint::{LintPass, EarlyLintPass, LateLintPass};
 
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-
 use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
-use syntax::symbol::keywords;
-use syntax::ptr::P;
 use syntax::print::pprust;
+use syntax::symbol::keywords;
 use syntax::util::parser;
 use syntax_pos::Span;
 
-use rustc_back::slice;
 use rustc::hir;
-use rustc::hir::intravisit::FnKind;
-
-declare_lint! {
-    pub UNUSED_MUT,
-    Warn,
-    "detect mut variables which don't need to be mutable"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedMut;
-
-impl UnusedMut {
-    fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
-        // collect all mutable pattern and group their NodeIDs by their Identifier to
-        // avoid false warnings in match arms with multiple patterns
-
-        let mut mutables = FxHashMap();
-        for p in pats {
-            p.each_binding(|_, id, span, path1| {
-                let hir_id = cx.tcx.hir.node_to_hir_id(id);
-                let bm = match cx.tables.pat_binding_modes().get(hir_id) {
-                    Some(&bm) => bm,
-                    None => span_bug!(span, "missing binding mode"),
-                };
-                let name = path1.node;
-                if let ty::BindByValue(hir::MutMutable) = bm {
-                    if !name.as_str().starts_with("_") {
-                        match mutables.entry(name) {
-                            Vacant(entry) => {
-                                entry.insert(vec![id]);
-                            }
-                            Occupied(mut entry) => {
-                                entry.get_mut().push(id);
-                            }
-                        }
-                    }
-                }
-            });
-        }
-
-        let used_mutables = cx.tcx.used_mut_nodes.borrow();
-        for (_, v) in &mutables {
-            if !v.iter().any(|e| used_mutables.contains(e)) {
-                let binding_span = cx.tcx.hir.span(v[0]);
-                let mut_span = cx.tcx.sess.codemap().span_until_char(binding_span, ' ');
-                let mut err = cx.struct_span_lint(UNUSED_MUT,
-                                                  binding_span,
-                                                  "variable does not need to be mutable");
-                err.span_suggestion_short(mut_span, "remove this `mut`", "".to_owned());
-                err.emit();
-            }
-        }
-    }
-}
-
-impl LintPass for UnusedMut {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNUSED_MUT)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
-    fn check_arm(&mut self, cx: &LateContext, a: &hir::Arm) {
-        self.check_unused_mut_pat(cx, &a.pats)
-    }
-
-    fn check_local(&mut self, cx: &LateContext, l: &hir::Local) {
-        self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
-    }
-
-    fn check_fn(&mut self,
-                cx: &LateContext,
-                _: FnKind,
-                _: &hir::FnDecl,
-                body: &hir::Body,
-                _: Span,
-                _: ast::NodeId) {
-        for a in &body.arguments {
-            self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
-        }
-    }
-}
 
 declare_lint! {
     pub UNUSED_MUST_USE,
diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml
index de5add56b76..a9566c4bcac 100644
--- a/src/librustc_llvm/Cargo.toml
+++ b/src/librustc_llvm/Cargo.toml
@@ -18,4 +18,4 @@ rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0"
+cc = "1.0.1"
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index dde7a38efc7..75efe135f65 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -88,7 +88,7 @@ fn main() {
     let is_crossed = target != host;
 
     let mut optional_components =
-        vec!["x86", "arm", "aarch64", "mips", "powerpc", "pnacl",
+        vec!["x86", "arm", "aarch64", "mips", "powerpc",
              "systemz", "jsbackend", "webassembly", "msp430", "sparc", "nvptx"];
 
     let mut version_cmd = Command::new(&llvm_config);
@@ -115,6 +115,7 @@ fn main() {
                                 "linker",
                                 "asmparser",
                                 "mcjit",
+                                "lto",
                                 "interpreter",
                                 "instrumentation"];
 
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index fd4a136f50b..3399bf2acd8 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -345,6 +345,20 @@ pub enum PassKind {
     Module,
 }
 
+/// LLVMRustThinLTOData
+pub enum ThinLTOData {}
+
+/// LLVMRustThinLTOBuffer
+pub enum ThinLTOBuffer {}
+
+/// LLVMRustThinLTOModule
+#[repr(C)]
+pub struct ThinLTOModule {
+    pub identifier: *const c_char,
+    pub data: *const u8,
+    pub len: usize,
+}
+
 // Opaque pointer types
 #[allow(missing_copy_implementations)]
 pub enum Module_opaque {}
@@ -1271,6 +1285,9 @@ extern "C" {
                                                         PM: PassManagerRef,
                                                         Internalize: Bool,
                                                         RunInliner: Bool);
+    pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
+        PMB: PassManagerBuilderRef,
+        PM: PassManagerRef) -> bool;
 
     // Stuff that's in rustllvm/ because it's not upstream yet.
 
@@ -1685,4 +1702,43 @@ extern "C" {
     pub fn LLVMRustModuleBufferLen(p: *const ModuleBuffer) -> usize;
     pub fn LLVMRustModuleBufferFree(p: *mut ModuleBuffer);
     pub fn LLVMRustModuleCost(M: ModuleRef) -> u64;
+
+    pub fn LLVMRustThinLTOAvailable() -> bool;
+    pub fn LLVMRustWriteThinBitcodeToFile(PMR: PassManagerRef,
+                                          M: ModuleRef,
+                                          BC: *const c_char) -> bool;
+    pub fn LLVMRustThinLTOBufferCreate(M: ModuleRef) -> *mut ThinLTOBuffer;
+    pub fn LLVMRustThinLTOBufferFree(M: *mut ThinLTOBuffer);
+    pub fn LLVMRustThinLTOBufferPtr(M: *const ThinLTOBuffer) -> *const c_char;
+    pub fn LLVMRustThinLTOBufferLen(M: *const ThinLTOBuffer) -> size_t;
+    pub fn LLVMRustCreateThinLTOData(
+        Modules: *const ThinLTOModule,
+        NumModules: c_uint,
+        PreservedSymbols: *const *const c_char,
+        PreservedSymbolsLen: c_uint,
+    ) -> *mut ThinLTOData;
+    pub fn LLVMRustPrepareThinLTORename(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustPrepareThinLTOResolveWeak(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustPrepareThinLTOInternalize(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustPrepareThinLTOImport(
+        Data: *const ThinLTOData,
+        Module: ModuleRef,
+    ) -> bool;
+    pub fn LLVMRustFreeThinLTOData(Data: *mut ThinLTOData);
+    pub fn LLVMRustParseBitcodeForThinLTO(
+        Context: ContextRef,
+        Data: *const u8,
+        len: usize,
+        Identifier: *const c_char,
+    ) -> ModuleRef;
+    pub fn LLVMGetModuleIdentifier(M: ModuleRef, size: *mut usize) -> *const c_char;
 }
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 9be5f5b5486..98172bca177 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -346,10 +346,6 @@ pub fn initialize_available_targets() {
                  LLVMInitializePowerPCTargetMC,
                  LLVMInitializePowerPCAsmPrinter,
                  LLVMInitializePowerPCAsmParser);
-    init_target!(llvm_component = "pnacl",
-                 LLVMInitializePNaClTargetInfo,
-                 LLVMInitializePNaClTarget,
-                 LLVMInitializePNaClTargetMC);
     init_target!(llvm_component = "systemz",
                  LLVMInitializeSystemZTargetInfo,
                  LLVMInitializeSystemZTarget,
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index d9ab2562eff..722d0cad238 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -56,7 +56,8 @@ impl<'a, 'b, 'tcx> IsolatedEncoder<'a, 'b, 'tcx> {
         };
 
         let lazy_body = self.lazy(body);
-        let tables = self.tcx.body_tables(body_id);
+        let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
+        let tables = self.tcx.typeck_tables_of(body_owner_def_id);
         let lazy_tables = self.lazy(tables);
 
         let mut visitor = NestedBodyCollector {
@@ -67,7 +68,7 @@ impl<'a, 'b, 'tcx> IsolatedEncoder<'a, 'b, 'tcx> {
         let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found);
 
         let rvalue_promotable_to_static =
-            self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
+            self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id);
 
         self.lazy(&Ast {
             body: lazy_body,
diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index 14b6e319132..ff923ce259f 100644
--- a/src/librustc_mir/borrow_check.rs
+++ b/src/librustc_mir/borrow_check.rs
@@ -14,7 +14,7 @@ use rustc::hir::def_id::{DefId};
 use rustc::infer::{InferCtxt};
 use rustc::ty::{self, TyCtxt, ParamEnv};
 use rustc::ty::maps::Providers;
-use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue};
+use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Lvalue, Local};
 use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
 use rustc::mir::{Statement, StatementKind, Terminator, TerminatorKind};
 use rustc::mir::transform::{MirSource};
@@ -30,6 +30,7 @@ use dataflow::{MoveDataParamEnv};
 use dataflow::{BitDenotation, BlockSets, DataflowResults, DataflowResultsConsumer};
 use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
 use dataflow::{Borrows, BorrowData, BorrowIndex};
+use dataflow::move_paths::{MoveError, IllegalMoveOriginKind};
 use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult};
 use util::borrowck_errors::{BorrowckErrors, Origin};
 
@@ -59,7 +60,33 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
     let param_env = tcx.param_env(def_id);
     tcx.infer_ctxt().enter(|_infcx| {
 
-        let move_data = MoveData::gather_moves(mir, tcx, param_env);
+        let move_data = match MoveData::gather_moves(mir, tcx, param_env) {
+            Ok(move_data) => move_data,
+            Err((move_data, move_errors)) => {
+                for move_error in move_errors {
+                    let (span, kind): (Span, IllegalMoveOriginKind) = match move_error {
+                        MoveError::UnionMove { .. } =>
+                            unimplemented!("dont know how to report union move errors yet."),
+                        MoveError::IllegalMove { cannot_move_out_of: o } => (o.span, o.kind),
+                    };
+                    let origin = Origin::Mir;
+                    let mut err = match kind {
+                        IllegalMoveOriginKind::Static =>
+                            tcx.cannot_move_out_of(span, "static item", origin),
+                        IllegalMoveOriginKind::BorrowedContent =>
+                            tcx.cannot_move_out_of(span, "borrowed_content", origin),
+                        IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } =>
+                            tcx.cannot_move_out_of_interior_of_drop(span, ty, origin),
+                        IllegalMoveOriginKind::InteriorOfSlice { elem_ty: ty, is_index } =>
+                            tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin),
+                        IllegalMoveOriginKind::InteriorOfArray { elem_ty: ty, is_index } =>
+                            tcx.cannot_move_out_of_interior_noncopy(span, ty, is_index, origin),
+                    };
+                    err.emit();
+                }
+                move_data
+            }
+        };
         let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
         let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
         let flow_borrows = do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
@@ -559,7 +586,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
                                                 context: Context,
                                                 (lvalue, span): (&Lvalue<'gcx>, Span),
                                                 flow_state: &InProgress<'b, 'gcx>) {
-        let move_data = flow_state.inits.base_results.operator().move_data();
+        let move_data = self.move_data;
 
         // determine if this path has a non-mut owner (and thus needs checking).
         let mut l = lvalue;
@@ -584,7 +611,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
             }
         }
 
-        if let Some(mpi) = self.move_path_for_lvalue(context, move_data, lvalue) {
+        if let Some(mpi) = self.move_path_for_lvalue(lvalue) {
             if flow_state.inits.curr_state.contains(&mpi) {
                 // may already be assigned before reaching this statement;
                 // report error.
@@ -615,21 +642,107 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
         let lvalue = self.base_path(lvalue_span.0);
 
         let maybe_uninits = &flow_state.uninits;
-        let move_data = maybe_uninits.base_results.operator().move_data();
-        if let Some(mpi) = self.move_path_for_lvalue(context, move_data, lvalue) {
-            if maybe_uninits.curr_state.contains(&mpi) {
-                // find and report move(s) that could cause this to be uninitialized
+
+        // Bad scenarios:
+        //
+        // 1. Move of `a.b.c`, use of `a.b.c`
+        // 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`)
+        // 3. Move of `a.b.c`, use of `a` or `a.b`
+        // 4. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
+        //    partial initialization support, one might have `a.x`
+        //    initialized but not `a.b`.
+        //
+        // OK scenarios:
+        //
+        // 5. Move of `a.b.c`, use of `a.b.d`
+        // 6. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
+        // 7. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
+        //    must have been initialized for the use to be sound.
+        // 8. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
+
+        // The dataflow tracks shallow prefixes distinctly (that is,
+        // field-accesses on P distinctly from P itself), in order to
+        // track substructure initialization separately from the whole
+        // structure.
+        //
+        // E.g., when looking at (*a.b.c).d, if the closest prefix for
+        // which we have a MovePath is `a.b`, then that means that the
+        // initialization state of `a.b` is all we need to inspect to
+        // know if `a.b.c` is valid (and from that we infer that the
+        // dereference and `.d` access is also valid, since we assume
+        // `a.b.c` is assigned a reference to a initialized and
+        // well-formed record structure.)
+
+        // Therefore, if we seek out the *closest* prefix for which we
+        // have a MovePath, that should capture the initialization
+        // state for the lvalue scenario.
+        //
+        // This code covers scenarios 1, 2, and 4.
+
+        debug!("check_if_path_is_moved part1 lvalue: {:?}", lvalue);
+        match self.move_path_closest_to(lvalue) {
+            Ok(mpi) => {
+                if maybe_uninits.curr_state.contains(&mpi) {
+                    self.report_use_of_moved(context, desired_action, lvalue_span);
+                    return; // don't bother finding other problems.
+                }
+            }
+            Err(NoMovePathFound::ReachedStatic) => {
+                // Okay: we do not build MoveData for static variables
+            }
+
+            // Only query longest prefix with a MovePath, not further
+            // ancestors; dataflow recurs on children when parents
+            // move (to support partial (re)inits).
+            //
+            // (I.e. querying parents breaks scenario 8; but may want
+            // to do such a query based on partial-init feature-gate.)
+        }
+
+        // A move of any shallow suffix of `lvalue` also interferes
+        // with an attempt to use `lvalue`. This is scenario 3 above.
+        //
+        // (Distinct from handling of scenarios 1+2+4 above because
+        // `lvalue` does not interfere with suffixes of its prefixes,
+        // e.g. `a.b.c` does not interfere with `a.b.d`)
+
+        debug!("check_if_path_is_moved part2 lvalue: {:?}", lvalue);
+        if let Some(mpi) = self.move_path_for_lvalue(lvalue) {
+            if let Some(_) = maybe_uninits.has_any_child_of(mpi) {
                 self.report_use_of_moved(context, desired_action, lvalue_span);
-            } else {
-                // sanity check: initialized on *some* path, right?
-                assert!(flow_state.inits.curr_state.contains(&mpi));
+                return; // don't bother finding other problems.
             }
         }
     }
 
+    /// Currently MoveData does not store entries for all lvalues in
+    /// the input MIR. For example it will currently filter out
+    /// lvalues that are Copy; thus we do not track lvalues of shared
+    /// reference type. This routine will walk up an lvalue along its
+    /// prefixes, searching for a foundational lvalue that *is*
+    /// tracked in the MoveData.
+    ///
+    /// An Err result includes a tag indicated why the search failed.
+    /// Currenly this can only occur if the lvalue is built off of a
+    /// static variable, as we do not track those in the MoveData.
+    fn move_path_closest_to(&mut self, lvalue: &Lvalue<'gcx>)
+                            -> Result<MovePathIndex, NoMovePathFound>
+    {
+        let mut last_prefix = lvalue;
+        for prefix in self.prefixes(lvalue, PrefixSet::All) {
+            if let Some(mpi) = self.move_path_for_lvalue(prefix) {
+                return Ok(mpi);
+            }
+            last_prefix = prefix;
+        }
+        match *last_prefix {
+            Lvalue::Local(_) => panic!("should have move path for every Local"),
+            Lvalue::Projection(_) => panic!("PrefixSet::All meant dont stop for Projection"),
+            Lvalue::Static(_) => return Err(NoMovePathFound::ReachedStatic),
+        }
+    }
+
     fn move_path_for_lvalue(&mut self,
-                            _context: Context,
-                            move_data: &MoveData<'gcx>,
                             lvalue: &Lvalue<'gcx>)
                             -> Option<MovePathIndex>
     {
@@ -637,7 +750,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
         // to a direct owner of `lvalue` (which means there is nothing
         // that borrowck tracks for its analysis).
 
-        match move_data.rev_lookup.find(lvalue) {
+        match self.move_data.rev_lookup.find(lvalue) {
             LookupResult::Parent(_) => None,
             LookupResult::Exact(mpi) => Some(mpi),
         }
@@ -706,6 +819,11 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum NoMovePathFound {
+    ReachedStatic,
+}
+
 impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> {
     fn each_borrow_involving_path<F>(&mut self,
                                      _context: Context,
@@ -819,12 +937,19 @@ mod prefixes {
 
     #[derive(Copy, Clone, PartialEq, Eq, Debug)]
     pub(super) enum PrefixSet {
+        /// Doesn't stop until it returns the base case (a Local or
+        /// Static prefix).
         All,
+        /// Stops at any dereference.
         Shallow,
+        /// Stops at the deref of a shared reference.
         Supporting,
     }
 
     impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx> {
+        /// Returns an iterator over the prefixes of `lvalue`
+        /// (inclusive) from longest to smallest, potentially
+        /// terminating the iteration early based on `kind`.
         pub(super) fn prefixes<'d>(&self,
                                    lvalue: &'d Lvalue<'gcx>,
                                    kind: PrefixSet)
@@ -1053,49 +1178,52 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
     // End-user visible description of `lvalue`
     fn describe_lvalue(&self, lvalue: &Lvalue) -> String {
         let mut buf = String::new();
-        self.append_lvalue_to_string(lvalue, &mut buf);
+        self.append_lvalue_to_string(lvalue, &mut buf, None);
         buf
     }
 
     // Appends end-user visible description of `lvalue` to `buf`.
-    fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String) {
+    fn append_lvalue_to_string(&self, lvalue: &Lvalue, buf: &mut String, autoderef: Option<bool>) {
         match *lvalue {
             Lvalue::Local(local) => {
-                let local = &self.mir.local_decls[local];
-                match local.name {
-                    Some(name) => buf.push_str(&format!("{}", name)),
-                    None => buf.push_str("_"),
-                }
+                self.append_local_to_string(local, buf, "_");
             }
             Lvalue::Static(ref static_) => {
                 buf.push_str(&format!("{}", &self.tcx.item_name(static_.def_id)));
             }
             Lvalue::Projection(ref proj) => {
+                let mut autoderef = autoderef.unwrap_or(false);
                 let (prefix, suffix, index_operand) = match proj.elem {
-                    ProjectionElem::Deref =>
-                        ("(*", format!(")"), None),
+                    ProjectionElem::Deref => {
+                        if autoderef {
+                            ("", format!(""), None)
+                        } else {
+                            ("(*", format!(")"), None)
+                        }
+                    },
                     ProjectionElem::Downcast(..) =>
                         ("",   format!(""), None), // (dont emit downcast info)
-                    ProjectionElem::Field(field, _ty) =>
-                        ("",   format!(".{}", field.index()), None), // FIXME: report name of field
-                    ProjectionElem::Index(index) =>
-                        ("",   format!(""), Some(index)),
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
-                        ("",   format!("[{} of {}]", offset, min_length), None),
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
-                        ("",   format!("[-{} of {}]", offset, min_length), None),
-                    ProjectionElem::Subslice { from, to: 0 } =>
-                        ("",   format!("[{}:]", from), None),
-                    ProjectionElem::Subslice { from: 0, to } =>
-                        ("",   format!("[:-{}]", to), None),
-                    ProjectionElem::Subslice { from, to } =>
-                        ("",   format!("[{}:-{}]", from, to), None),
+                    ProjectionElem::Field(field, _ty) => {
+                        autoderef = true;
+                        ("", format!(".{}", self.describe_field(&proj.base, field.index())), None)
+                    },
+                    ProjectionElem::Index(index) => {
+                        autoderef = true;
+                        ("",   format!(""), Some(index))
+                    },
+                    ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
+                        autoderef = true;
+                        // Since it isn't possible to borrow an element on a particular index and
+                        // then use another while the borrow is held, don't output indices details
+                        // to avoid confusing the end-user
+                        ("",   format!("[..]"), None)
+                    },
                 };
                 buf.push_str(prefix);
-                self.append_lvalue_to_string(&proj.base, buf);
+                self.append_lvalue_to_string(&proj.base, buf, Some(autoderef));
                 if let Some(index) = index_operand {
                     buf.push_str("[");
-                    self.append_lvalue_to_string(&Lvalue::Local(index), buf);
+                    self.append_local_to_string(index, buf, "..");
                     buf.push_str("]");
                 } else {
                     buf.push_str(&suffix);
@@ -1104,11 +1232,80 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
         }
     }
 
+    // Appends end-user visible description of the `local` lvalue to `buf`. If `local` doesn't have
+    // a name, then `none_string` is appended instead
+    fn append_local_to_string(&self, local_index: Local, buf: &mut String, none_string: &str) {
+        let local = &self.mir.local_decls[local_index];
+        match local.name {
+            Some(name) => buf.push_str(&format!("{}", name)),
+            None => buf.push_str(none_string)
+        }
+    }
+
+    // End-user visible description of the `field_index`nth field of `base`
+    fn describe_field(&self, base: &Lvalue, field_index: usize) -> String {
+        match *base {
+            Lvalue::Local(local) => {
+                let local = &self.mir.local_decls[local];
+                self.describe_field_from_ty(&local.ty, field_index)
+            },
+            Lvalue::Static(ref static_) => {
+                self.describe_field_from_ty(&static_.ty, field_index)
+            },
+            Lvalue::Projection(ref proj) => {
+                match proj.elem {
+                    ProjectionElem::Deref =>
+                        self.describe_field(&proj.base, field_index),
+                    ProjectionElem::Downcast(def, variant_index) =>
+                        format!("{}", def.variants[variant_index].fields[field_index].name),
+                    ProjectionElem::Field(_, field_type) =>
+                        self.describe_field_from_ty(&field_type, field_index),
+                    ProjectionElem::Index(..)
+                    | ProjectionElem::ConstantIndex { .. }
+                    | ProjectionElem::Subslice { .. } =>
+                        format!("{}", self.describe_field(&proj.base, field_index)),
+                }
+            }
+        }
+    }
+
+    // End-user visible description of the `field_index`nth field of `ty`
+    fn describe_field_from_ty(&self, ty: &ty::Ty, field_index: usize) -> String {
+        if ty.is_box() {
+            // If the type is a box, the field is described from the boxed type
+            self.describe_field_from_ty(&ty.boxed_ty(), field_index)
+        }
+        else {
+            match ty.sty {
+                ty::TyAdt(def, _) => {
+                    if def.is_enum() {
+                        format!("{}", field_index)
+                    }
+                    else {
+                        format!("{}", def.struct_variant().fields[field_index].name)
+                    }
+                },
+                ty::TyTuple(_, _) => {
+                    format!("{}", field_index)
+                },
+                ty::TyRef(_, tnm) | ty::TyRawPtr(tnm) => {
+                    self.describe_field_from_ty(&tnm.ty, field_index)
+                },
+                ty::TyArray(ty, _) | ty::TySlice(ty) => {
+                    self.describe_field_from_ty(&ty, field_index)
+                }
+                _ => {
+                    // Might need a revision when the fields in trait RFC is implemented
+                    // (https://github.com/rust-lang/rfcs/pull/1546)
+                    bug!("End-user description not implemented for field access on `{:?}`", ty.sty);
+                }
+            }
+        }
+    }
+
     // Retrieve span of given borrow from the current MIR representation
     fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
-        self.mir.basic_blocks()[borrow.location.block]
-            .statements[borrow.location.statement_index]
-            .source_info.span
+        self.mir.source_info(borrow.location).span
     }
 }
 
@@ -1241,6 +1438,35 @@ impl<'b, 'tcx: 'b> InProgress<'b, 'tcx> {
     }
 }
 
+impl<'b, 'tcx> FlowInProgress<MaybeUninitializedLvals<'b, 'tcx>> {
+    fn has_any_child_of(&self, mpi: MovePathIndex) -> Option<MovePathIndex> {
+        let move_data = self.base_results.operator().move_data();
+
+        let mut todo = vec![mpi];
+        let mut push_siblings = false; // don't look at siblings of original `mpi`.
+        while let Some(mpi) = todo.pop() {
+            if self.curr_state.contains(&mpi) {
+                return Some(mpi);
+            }
+            let move_path = &move_data.move_paths[mpi];
+            if let Some(child) = move_path.first_child {
+                todo.push(child);
+            }
+            if push_siblings {
+                if let Some(sibling) = move_path.next_sibling {
+                    todo.push(sibling);
+                }
+            } else {
+                // after we've processed the original `mpi`, we should
+                // always traverse the siblings of any of its
+                // children.
+                push_siblings = true;
+            }
+        }
+        return None;
+    }
+}
+
 impl<BD> FlowInProgress<BD> where BD: BitDenotation {
     fn each_state_bit<F>(&self, f: F) where F: FnMut(BD::Idx) {
         self.curr_state.each_bit(self.base_results.operator().bits_per_block(), f)
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index f04dede6e40..56c926eaa61 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -21,7 +21,7 @@ use rustc::mir::*;
 use rustc::hir;
 use hair::*;
 use syntax::ast::{Name, NodeId};
-use syntax_pos::Span;
+use syntax_pos::{DUMMY_SP, Span};
 
 // helper functions, broken out by category:
 mod simplify;
@@ -398,10 +398,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             candidates.iter().take_while(|c| c.match_pairs.is_empty()).count();
         debug!("match_candidates: {:?} candidates fully matched", fully_matched);
         let mut unmatched_candidates = candidates.split_off(fully_matched);
-        for candidate in candidates {
+        for (index, candidate) in candidates.into_iter().enumerate() {
             // If so, apply any bindings, test the guard (if any), and
             // branch to the arm.
-            if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
+            let is_last = index == fully_matched - 1;
+            if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks,
+                                                                   candidate, is_last) {
                 block = b;
             } else {
                 // if None is returned, then any remaining candidates
@@ -664,7 +666,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     fn bind_and_guard_matched_candidate<'pat>(&mut self,
                                               mut block: BasicBlock,
                                               arm_blocks: &mut ArmBlocks,
-                                              candidate: Candidate<'pat, 'tcx>)
+                                              candidate: Candidate<'pat, 'tcx>,
+                                              is_last_arm: bool)
                                               -> Option<BasicBlock> {
         debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
                block, candidate);
@@ -685,10 +688,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             self.cfg.terminate(block, source_info,
                                TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
             Some(otherwise)
+        } else if !is_last_arm {
+            // Add always true guard in case of more than one arm
+            // it creates false edges and allow MIR borrowck detects errors
+            // FIXME(#45184) -- permit "false edges"
+            let source_info = self.source_info(candidate.span);
+            let true_expr = Expr {
+                temp_lifetime: None,
+                ty: self.hir.tcx().types.bool,
+                span: DUMMY_SP,
+                kind: ExprKind::Literal{literal: self.hir.true_literal()},
+            };
+            let cond = unpack!(block = self.as_local_operand(block, true_expr));
+            let otherwise = self.cfg.start_new_block();
+            self.cfg.terminate(block, source_info,
+                               TerminatorKind::if_(self.hir.tcx(), cond, arm_block, otherwise));
+            Some(otherwise)
         } else {
             let source_info = self.source_info(candidate.span);
             self.cfg.terminate(block, source_info,
-                               TerminatorKind::Goto { target: arm_block });
+                               TerminatorKind::Goto { target: arm_block  });
             None
         }
     }
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 6e3eef57352..9b3f16f1ab4 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -26,7 +26,6 @@ use build::{BlockAnd, BlockAndExtension, Builder};
 use build::matches::{Binding, MatchPair, Candidate};
 use hair::*;
 use rustc::mir::*;
-use rustc_data_structures::fx::FxHashMap;
 
 use std::mem;
 
@@ -102,12 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 if self.hir.tcx().sess.features.borrow().never_type {
                     let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
                         i == variant_index || {
-                            let mut visited = FxHashMap::default();
-                            let node_set = v.uninhabited_from(&mut visited,
-                                                              self.hir.tcx(),
-                                                              substs,
-                                                              adt_def.adt_kind());
-                            !node_set.is_empty()
+                            self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
                         }
                     });
                     if irrefutable {
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 46a5e5abbdd..b8bb2a40462 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -149,7 +149,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
             mem::transmute::<Mir, Mir<'tcx>>(mir)
         };
 
-        mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
+        mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) );
 
         mir
     })
@@ -227,7 +227,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 mem::transmute::<Mir, Mir<'tcx>>(mir)
             };
 
-            mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
+            mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir, |_, _| Ok(()) );
 
             mir
         })
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 03273419432..c0d17a1590f 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -131,6 +131,9 @@ pub struct Scope<'tcx> {
 
     /// The cache for drop chain on "generator drop" exit.
     cached_generator_drop: Option<BasicBlock>,
+
+    /// The cache for drop chain on "unwind" exit.
+    cached_unwind: CachedBlock,
 }
 
 #[derive(Debug)]
@@ -154,6 +157,11 @@ struct CachedBlock {
     unwind: Option<BasicBlock>,
 
     /// The cached block for unwinds during cleanups-on-generator-drop path
+    ///
+    /// This is split from the standard unwind path here to prevent drop
+    /// elaboration from creating drop flags that would have to be captured
+    /// by the generator. I'm not sure how important this optimization is,
+    /// but it is here.
     generator_drop: Option<BasicBlock>,
 }
 
@@ -217,34 +225,29 @@ impl<'tcx> Scope<'tcx> {
     /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
     /// larger extent of code.
     ///
-    /// `unwind` controls whether caches for the unwind branch are also invalidated.
-    fn invalidate_cache(&mut self, unwind: bool) {
+    /// `storage_only` controls whether to invalidate only drop paths run `StorageDead`.
+    /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
+    /// top-of-scope (as opposed to dependent scopes).
+    fn invalidate_cache(&mut self, storage_only: bool, this_scope_only: bool) {
+        // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
+        // with lots of `try!`?
+
+        // cached exits drop storage and refer to the top-of-scope
         self.cached_exits.clear();
-        if !unwind { return; }
-        for dropdata in &mut self.drops {
-            if let DropKind::Value { ref mut cached_block } = dropdata.kind {
-                cached_block.invalidate();
-            }
+
+        if !storage_only {
+            // the current generator drop and unwind ignore
+            // storage but refer to top-of-scope
+            self.cached_generator_drop = None;
+            self.cached_unwind.invalidate();
         }
-    }
 
-    /// Returns the cached entrypoint for diverging exit from this scope.
-    ///
-    /// Precondition: the caches must be fully filled (i.e. diverge_cleanup is called) in order for
-    /// this method to work correctly.
-    fn cached_block(&self, generator_drop: bool) -> Option<BasicBlock> {
-        let mut drops = self.drops.iter().rev().filter_map(|data| {
-            match data.kind {
-                DropKind::Value { cached_block } => {
-                    Some(cached_block.get(generator_drop))
+        if !storage_only && !this_scope_only {
+            for dropdata in &mut self.drops {
+                if let DropKind::Value { ref mut cached_block } = dropdata.kind {
+                    cached_block.invalidate();
                 }
-                DropKind::Storage => None
             }
-        });
-        if let Some(cached_block) = drops.next() {
-            Some(cached_block.expect("drop cache is not filled"))
-        } else {
-            None
         }
     }
 
@@ -356,7 +359,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             needs_cleanup: false,
             drops: vec![],
             cached_generator_drop: None,
-            cached_exits: FxHashMap()
+            cached_exits: FxHashMap(),
+            cached_unwind: CachedBlock::default(),
         });
     }
 
@@ -482,15 +486,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                    TerminatorKind::Goto { target: b });
                 b
             };
+
+            // End all regions for scopes out of which we are breaking.
+            self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_scope);
+
             unpack!(block = build_scope_drops(&mut self.cfg,
                                               scope,
                                               rest,
                                               block,
                                               self.arg_count,
                                               true));
-
-            // End all regions for scopes out of which we are breaking.
-            self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_scope);
         }
 
         self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
@@ -672,8 +677,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             // invalidating caches of each scope visited. This way bare minimum of the
             // caches gets invalidated. i.e. if a new drop is added into the middle scope, the
             // cache of outer scpoe stays intact.
-            let invalidate_unwind = needs_drop && !this_scope;
-            scope.invalidate_cache(invalidate_unwind);
+            scope.invalidate_cache(!needs_drop, this_scope);
             if this_scope {
                 if let DropKind::Value { .. } = drop_kind {
                     scope.needs_cleanup = true;
@@ -819,30 +823,50 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
                            generator_drop: bool)
                            -> BlockAnd<()> {
     debug!("build_scope_drops({:?} -> {:?})", block, scope);
-    let mut iter = scope.drops.iter().rev().peekable();
+    let mut iter = scope.drops.iter().rev();
     while let Some(drop_data) = iter.next() {
         let source_info = scope.source_info(drop_data.span);
         match drop_data.kind {
             DropKind::Value { .. } => {
-                // Try to find the next block with its cached block
-                // for us to diverge into in case the drop panics.
-                let on_diverge = iter.peek().iter().filter_map(|dd| {
+                // Try to find the next block with its cached block for us to
+                // diverge into, either a previous block in this current scope or
+                // the top of the previous scope.
+                //
+                // If it wasn't for EndRegion, we could just chain all the DropData
+                // together and pick the first DropKind::Value. Please do that
+                // when we replace EndRegion with NLL.
+                let on_diverge = iter.clone().filter_map(|dd| {
                     match dd.kind {
-                        DropKind::Value { cached_block } => {
-                            let result = cached_block.get(generator_drop);
-                            if result.is_none() {
-                                span_bug!(drop_data.span, "cached block not present?")
-                            }
-                            result
-                        },
+                        DropKind::Value { cached_block } => Some(cached_block),
                         DropKind::Storage => None
                     }
-                }).next();
-                // If there’s no `cached_block`s within current scope,
-                // we must look for one in the enclosing scope.
-                let on_diverge = on_diverge.or_else(|| {
-                    earlier_scopes.iter().rev().flat_map(|s| s.cached_block(generator_drop)).next()
+                }).next().or_else(|| {
+                    if earlier_scopes.iter().any(|scope| scope.needs_cleanup) {
+                        // If *any* scope requires cleanup code to be run,
+                        // we must use the cached unwind from the *topmost*
+                        // scope, to ensure all EndRegions from surrounding
+                        // scopes are executed before the drop code runs.
+                        Some(earlier_scopes.last().unwrap().cached_unwind)
+                    } else {
+                        // We don't need any further cleanup, so return None
+                        // to avoid creating a landing pad. We can skip
+                        // EndRegions because all local regions end anyway
+                        // when the function unwinds.
+                        //
+                        // This is an important optimization because LLVM is
+                        // terrible at optimizing landing pads. FIXME: I think
+                        // it would be cleaner and better to do this optimization
+                        // in SimplifyCfg instead of here.
+                        None
+                    }
+                });
+
+                let on_diverge = on_diverge.map(|cached_block| {
+                    cached_block.get(generator_drop).unwrap_or_else(|| {
+                        span_bug!(drop_data.span, "cached block not present?")
+                    })
                 });
+
                 let next = cfg.start_new_block();
                 cfg.terminate(block, source_info, TerminatorKind::Drop {
                     location: drop_data.location.clone(),
@@ -933,14 +957,23 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         };
     }
 
-    // Finally, push the EndRegion block, used by mir-borrowck. (Block
-    // becomes trivial goto after pass that removes all EndRegions.)
-    {
-        let block = cfg.start_new_cleanup_block();
-        cfg.push_end_region(tcx, block, source_info(span), scope.region_scope);
-        cfg.terminate(block, source_info(span), TerminatorKind::Goto { target: target });
-        target = block
-    }
+    // Finally, push the EndRegion block, used by mir-borrowck, and set
+    // `cached_unwind` to point to it (Block becomes trivial goto after
+    // pass that removes all EndRegions).
+    target = {
+        let cached_block = scope.cached_unwind.ref_mut(generator_drop);
+        if let Some(cached_block) = *cached_block {
+            cached_block
+        } else {
+            let block = cfg.start_new_cleanup_block();
+            cfg.push_end_region(tcx, block, source_info(span), scope.region_scope);
+            cfg.terminate(block, source_info(span), TerminatorKind::Goto { target: target });
+            *cached_block = Some(block);
+            block
+        }
+    };
+
+    debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
 
     target
 }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index 86298c3b83e..0790d937ceb 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -22,17 +22,15 @@ use std::mem;
 use super::abs_domain::Lift;
 
 use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
+use super::{MoveError};
+use super::IllegalMoveOriginKind::*;
 
-pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
+struct MoveDataBuilder<'a, 'tcx: 'a> {
     mir: &'a Mir<'tcx>,
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     data: MoveData<'tcx>,
-}
-
-pub enum MovePathError {
-    IllegalMove,
-    UnionMove { path: MovePathIndex },
+    errors: Vec<MoveError<'tcx>>,
 }
 
 impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -47,6 +45,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             mir,
             tcx,
             param_env,
+            errors: Vec::new(),
             data: MoveData {
                 moves: IndexVec::new(),
                 loc_map: LocationMap::new(mir),
@@ -85,7 +84,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         assert_eq!(path_map_ent, move_path);
         move_path
     }
+}
 
+impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
     /// This creates a MovePath for a given lvalue, returning an `MovePathError`
     /// if that lvalue can't be moved from.
     ///
@@ -94,13 +95,15 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
     ///
     /// Maybe we should have separate "borrowck" and "moveck" modes.
     fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
-                     -> Result<MovePathIndex, MovePathError>
+                     -> Result<MovePathIndex, MoveError<'tcx>>
     {
         debug!("lookup({:?})", lval);
         match *lval {
-            Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
-            // error: can't move out of a static
-            Lvalue::Static(..) => Err(MovePathError::IllegalMove),
+            Lvalue::Local(local) => Ok(self.builder.data.rev_lookup.locals[local]),
+            Lvalue::Static(..) => {
+                let span = self.builder.mir.source_info(self.loc).span;
+                Err(MoveError::cannot_move_out_of(span, Static))
+            }
             Lvalue::Projection(ref proj) => {
                 self.move_path_for_projection(lval, proj)
             }
@@ -116,37 +119,52 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
     fn move_path_for_projection(&mut self,
                                 lval: &Lvalue<'tcx>,
                                 proj: &LvalueProjection<'tcx>)
-                                -> Result<MovePathIndex, MovePathError>
+                                -> Result<MovePathIndex, MoveError<'tcx>>
     {
         let base = try!(self.move_path_for(&proj.base));
-        let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
+        let mir = self.builder.mir;
+        let tcx = self.builder.tcx;
+        let lv_ty = proj.base.ty(mir, tcx).to_ty(tcx);
         match lv_ty.sty {
-            // error: can't move out of borrowed content
-            ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
-            // error: can't move out of struct with destructor
-            ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
-                return Err(MovePathError::IllegalMove),
+            ty::TyRef(..) | ty::TyRawPtr(..) =>
+                return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
+                                                         BorrowedContent)),
+            ty::TyAdt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
+                return Err(MoveError::cannot_move_out_of(mir.source_info(self.loc).span,
+                                                         InteriorOfTypeWithDestructor {
+                    container_ty: lv_ty
+                })),
             // move out of union - always move the entire union
             ty::TyAdt(adt, _) if adt.is_union() =>
-                return Err(MovePathError::UnionMove { path: base }),
-            // error: can't move out of a slice
-            ty::TySlice(..) =>
-                return Err(MovePathError::IllegalMove),
-            ty::TyArray(..) => match proj.elem {
-                // error: can't move out of an array
-                ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove),
+                return Err(MoveError::UnionMove { path: base }),
+            ty::TySlice(elem_ty) =>
+                return Err(MoveError::cannot_move_out_of(
+                    mir.source_info(self.loc).span,
+                    InteriorOfSlice {
+                        elem_ty, is_index: match proj.elem {
+                            ProjectionElem::Index(..) => true,
+                            _ => false
+                        },
+                    })),
+            ty::TyArray(elem_ty, _num_elems) => match proj.elem {
+                ProjectionElem::Index(..) =>
+                    return Err(MoveError::cannot_move_out_of(
+                        mir.source_info(self.loc).span,
+                        InteriorOfArray {
+                            elem_ty, is_index: true
+                        })),
                 _ => {
                     // FIXME: still badly broken
                 }
             },
             _ => {}
         };
-        match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
+        match self.builder.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
             Entry::Occupied(ent) => Ok(*ent.get()),
             Entry::Vacant(ent) => {
-                let path = Self::new_move_path(
-                    &mut self.data.move_paths,
-                    &mut self.data.path_map,
+                let path = MoveDataBuilder::new_move_path(
+                    &mut self.builder.data.move_paths,
+                    &mut self.builder.data.path_map,
                     Some(base),
                     lval.clone()
                 );
@@ -155,8 +173,10 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             }
         }
     }
+}
 
-    fn finalize(self) -> MoveData<'tcx> {
+impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+    fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
         debug!("{}", {
             debug!("moves for {:?}:", self.mir.span);
             for (j, mo) in self.data.moves.iter_enumerated() {
@@ -168,14 +188,20 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             }
             "done dumping moves"
         });
-        self.data
+
+        if self.errors.len() > 0 {
+            Err((self.data, self.errors))
+        } else {
+            Ok(self.data)
+        }
     }
 }
 
 pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
                                      tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      param_env: ty::ParamEnv<'tcx>)
-                                     -> MoveData<'tcx> {
+                                     -> Result<MoveData<'tcx>,
+                                               (MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
     let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
 
     for (bb, block) in mir.basic_blocks().iter_enumerated() {
@@ -197,6 +223,22 @@ pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
 impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
     fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) {
         debug!("gather_statement({:?}, {:?})", loc, stmt);
+        (Gatherer { builder: self, loc }).gather_statement(stmt);
+    }
+
+    fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
+        debug!("gather_terminator({:?}, {:?})", loc, term);
+        (Gatherer { builder: self, loc }).gather_terminator(term);
+    }
+}
+
+struct Gatherer<'b, 'a: 'b, 'tcx: 'a> {
+    builder: &'b mut MoveDataBuilder<'a, 'tcx>,
+    loc: Location,
+}
+
+impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
+    fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
         match stmt.kind {
             StatementKind::Assign(ref lval, ref rval) => {
                 self.create_move_path(lval);
@@ -206,7 +248,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
                     // the exterior.
                     self.create_move_path(&lval.clone().deref());
                 }
-                self.gather_rvalue(loc, rval);
+                self.gather_rvalue(rval);
             }
             StatementKind::StorageLive(_) |
             StatementKind::StorageDead(_) => {}
@@ -221,22 +263,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         }
     }
 
-    fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) {
+    fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
         match *rvalue {
             Rvalue::Use(ref operand) |
             Rvalue::Repeat(ref operand, _) |
             Rvalue::Cast(_, ref operand, _) |
             Rvalue::UnaryOp(_, ref operand) => {
-                self.gather_operand(loc, operand)
+                self.gather_operand(operand)
             }
             Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) |
             Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
-                self.gather_operand(loc, lhs);
-                self.gather_operand(loc, rhs);
+                self.gather_operand(lhs);
+                self.gather_operand(rhs);
             }
             Rvalue::Aggregate(ref _kind, ref operands) => {
                 for operand in operands {
-                    self.gather_operand(loc, operand);
+                    self.gather_operand(operand);
                 }
             }
             Rvalue::Ref(..) |
@@ -258,8 +300,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         }
     }
 
-    fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
-        debug!("gather_terminator({:?}, {:?})", loc, term);
+    fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
         match term.kind {
             TerminatorKind::Goto { target: _ } |
             TerminatorKind::Resume |
@@ -267,7 +308,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             TerminatorKind::Unreachable => { }
 
             TerminatorKind::Return => {
-                self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
+                self.gather_move(&Lvalue::Local(RETURN_POINTER));
             }
 
             TerminatorKind::Assert { .. } |
@@ -276,20 +317,20 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
             }
 
             TerminatorKind::Yield { ref value, .. } => {
-                self.gather_operand(loc, value);
+                self.gather_operand(value);
             }
 
             TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
-                self.gather_move(loc, location);
+                self.gather_move(location);
             }
             TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
                 self.create_move_path(location);
-                self.gather_operand(loc, value);
+                self.gather_operand(value);
             }
             TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
-                self.gather_operand(loc, func);
+                self.gather_operand(func);
                 for arg in args {
-                    self.gather_operand(loc, arg);
+                    self.gather_operand(arg);
                 }
                 if let Some((ref destination, _bb)) = *destination {
                     self.create_move_path(destination);
@@ -298,40 +339,38 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
         }
     }
 
-    fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) {
+    fn gather_operand(&mut self, operand: &Operand<'tcx>) {
         match *operand {
             Operand::Constant(..) => {} // not-a-move
             Operand::Consume(ref lval) => { // a move
-                self.gather_move(loc, lval);
+                self.gather_move(lval);
             }
         }
     }
 
-    fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) {
-        debug!("gather_move({:?}, {:?})", loc, lval);
+    fn gather_move(&mut self, lval: &Lvalue<'tcx>) {
+        debug!("gather_move({:?}, {:?})", self.loc, lval);
 
-        let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx);
-        if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) {
-            debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty);
+        let tcx = self.builder.tcx;
+        let lv_ty = lval.ty(self.builder.mir, tcx).to_ty(tcx);
+        if !lv_ty.moves_by_default(tcx, self.builder.param_env, DUMMY_SP) {
+            debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", self.loc, lval, lv_ty);
             return
         }
 
         let path = match self.move_path_for(lval) {
-            Ok(path) | Err(MovePathError::UnionMove { path }) => path,
-            Err(MovePathError::IllegalMove) => {
-                // Moving out of a bad path. Eventually, this should be a MIR
-                // borrowck error instead of a bug.
-                span_bug!(self.mir.span,
-                          "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}",
-                          lval, lv_ty, loc);
+            Ok(path) | Err(MoveError::UnionMove { path }) => path,
+            Err(error @ MoveError::IllegalMove { .. }) => {
+                self.builder.errors.push(error);
+                return;
             }
         };
-        let move_out = self.data.moves.push(MoveOut { path: path, source: loc });
+        let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
 
         debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
-               loc, lval, move_out, path);
+               self.loc, lval, move_out, path);
 
-        self.data.path_map[path].push(move_out);
-        self.data.loc_map[loc].push(move_out);
+        self.builder.data.path_map[path].push(move_out);
+        self.builder.data.loc_map[self.loc].push(move_out);
     }
 }
diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs
index d2d80649846..9369156a223 100644
--- a/src/librustc_mir/dataflow/move_paths/mod.rs
+++ b/src/librustc_mir/dataflow/move_paths/mod.rs
@@ -13,6 +13,7 @@ use rustc::ty::{self, TyCtxt};
 use rustc::mir::*;
 use rustc::util::nodemap::FxHashMap;
 use rustc_data_structures::indexed_vec::{IndexVec};
+use syntax_pos::{Span};
 
 use std::fmt;
 use std::ops::{Index, IndexMut};
@@ -227,11 +228,39 @@ impl<'tcx> MovePathLookup<'tcx> {
     }
 }
 
+#[derive(Debug)]
+pub struct IllegalMoveOrigin<'tcx> {
+    pub(crate) span: Span,
+    pub(crate) kind: IllegalMoveOriginKind<'tcx>,
+}
+
+#[derive(Debug)]
+pub(crate) enum IllegalMoveOriginKind<'tcx> {
+    Static,
+    BorrowedContent,
+    InteriorOfTypeWithDestructor { container_ty: ty::Ty<'tcx> },
+    InteriorOfSlice { elem_ty: ty::Ty<'tcx>, is_index: bool, },
+    InteriorOfArray { elem_ty: ty::Ty<'tcx>, is_index: bool, },
+}
+
+#[derive(Debug)]
+pub enum MoveError<'tcx> {
+    IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> },
+    UnionMove { path: MovePathIndex },
+}
+
+impl<'tcx> MoveError<'tcx> {
+    fn cannot_move_out_of(span: Span, kind: IllegalMoveOriginKind<'tcx>) -> Self {
+        let origin = IllegalMoveOrigin { span, kind };
+        MoveError::IllegalMove { cannot_move_out_of: origin }
+    }
+}
+
 impl<'a, 'tcx> MoveData<'tcx> {
     pub fn gather_moves(mir: &Mir<'tcx>,
                         tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         param_env: ty::ParamEnv<'tcx>)
-                        -> Self {
+                        -> Result<Self, (Self, Vec<MoveError<'tcx>>)> {
         builder::gather_moves(mir, tcx, param_env)
     }
 }
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 950bdff1d0f..0f67f7bf6de 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -229,6 +229,57 @@ fn main() {
 See also https://doc.rust-lang.org/book/first-edition/unsafe.html
 "##,
 
+E0373: r##"
+This error occurs when an attempt is made to use data captured by a closure,
+when that data may no longer exist. It's most commonly seen when attempting to
+return a closure:
+
+```compile_fail,E0373
+fn foo() -> Box<Fn(u32) -> u32> {
+    let x = 0u32;
+    Box::new(|y| x + y)
+}
+```
+
+Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
+closed-over data by reference. This means that once `foo()` returns, `x` no
+longer exists. An attempt to access `x` within the closure would thus be
+unsafe.
+
+Another situation where this might be encountered is when spawning threads:
+
+```compile_fail,E0373
+fn foo() {
+    let x = 0u32;
+    let y = 1u32;
+
+    let thr = std::thread::spawn(|| {
+        x + y
+    });
+}
+```
+
+Since our new thread runs in parallel, the stack frame containing `x` and `y`
+may well have disappeared by the time we try to use them. Even if we call
+`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
+stack frame won't disappear), we will not succeed: the compiler cannot prove
+that this behaviour is safe, and so won't let us do it.
+
+The solution to this problem is usually to switch to using a `move` closure.
+This approach moves (or copies, where possible) data into the closure, rather
+than taking references to it. For example:
+
+```
+fn foo() -> Box<Fn(u32) -> u32> {
+    let x = 0u32;
+    Box::new(move |y| x + y)
+}
+```
+
+Now that the closure has its own copy of the data, there's no need to worry
+about safety.
+"##,
+
 E0381: r##"
 It is not allowed to use or capture an uninitialized variable. For example:
 
@@ -250,6 +301,152 @@ fn main() {
 ```
 "##,
 
+E0382: r##"
+This error occurs when an attempt is made to use a variable after its contents
+have been moved elsewhere. For example:
+
+```compile_fail,E0382
+struct MyStruct { s: u32 }
+
+fn main() {
+    let mut x = MyStruct{ s: 5u32 };
+    let y = x;
+    x.s = 6;
+    println!("{}", x.s);
+}
+```
+
+Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
+of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
+of workarounds like `Rc`, a value cannot be owned by more than one variable.
+
+Sometimes we don't need to move the value. Using a reference, we can let another
+function borrow the value without changing its ownership. In the example below,
+we don't actually have to move our string to `calculate_length`, we can give it
+a reference to it with `&` instead.
+
+```
+fn main() {
+    let s1 = String::from("hello");
+
+    let len = calculate_length(&s1);
+
+    println!("The length of '{}' is {}.", s1, len);
+}
+
+fn calculate_length(s: &String) -> usize {
+    s.len()
+}
+```
+
+A mutable reference can be created with `&mut`.
+
+Sometimes we don't want a reference, but a duplicate. All types marked `Clone`
+can be duplicated by calling `.clone()`. Subsequent changes to a clone do not
+affect the original variable.
+
+Most types in the standard library are marked `Clone`. The example below
+demonstrates using `clone()` on a string. `s1` is first set to "many", and then
+copied to `s2`. Then the first character of `s1` is removed, without affecting
+`s2`. "any many" is printed to the console.
+
+```
+fn main() {
+    let mut s1 = String::from("many");
+    let s2 = s1.clone();
+    s1.remove(0);
+    println!("{} {}", s1, s2);
+}
+```
+
+If we control the definition of a type, we can implement `Clone` on it ourselves
+with `#[derive(Clone)]`.
+
+Some types have no ownership semantics at all and are trivial to duplicate. An
+example is `i32` and the other number types. We don't have to call `.clone()` to
+clone them, because they are marked `Copy` in addition to `Clone`.  Implicit
+cloning is more convienient in this case. We can mark our own types `Copy` if
+all their members also are marked `Copy`.
+
+In the example below, we implement a `Point` type. Because it only stores two
+integers, we opt-out of ownership semantics with `Copy`. Then we can
+`let p2 = p1` without `p1` being moved.
+
+```
+#[derive(Copy, Clone)]
+struct Point { x: i32, y: i32 }
+
+fn main() {
+    let mut p1 = Point{ x: -1, y: 2 };
+    let p2 = p1;
+    p1.x = 1;
+    println!("p1: {}, {}", p1.x, p1.y);
+    println!("p2: {}, {}", p2.x, p2.y);
+}
+```
+
+Alternatively, if we don't control the struct's definition, or mutable shared
+ownership is truly required, we can use `Rc` and `RefCell`:
+
+```
+use std::cell::RefCell;
+use std::rc::Rc;
+
+struct MyStruct { s: u32 }
+
+fn main() {
+    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
+    let y = x.clone();
+    x.borrow_mut().s = 6;
+    println!("{}", x.borrow().s);
+}
+```
+
+With this approach, x and y share ownership of the data via the `Rc` (reference
+count type). `RefCell` essentially performs runtime borrow checking: ensuring
+that at most one writer or multiple readers can access the data at any one time.
+
+If you wish to learn more about ownership in Rust, start with the chapter in the
+Book:
+
+https://doc.rust-lang.org/book/first-edition/ownership.html
+"##,
+
+E0383: r##"
+This error occurs when an attempt is made to partially reinitialize a
+structure that is currently uninitialized.
+
+For example, this can happen when a drop has taken place:
+
+```compile_fail,E0383
+struct Foo {
+    a: u32,
+}
+impl Drop for Foo {
+    fn drop(&mut self) { /* ... */ }
+}
+
+let mut x = Foo { a: 1 };
+drop(x); // `x` is now uninitialized
+x.a = 2; // error, partial reinitialization of uninitialized structure `t`
+```
+
+This error can be fixed by fully reinitializing the structure in question:
+
+```
+struct Foo {
+    a: u32,
+}
+impl Drop for Foo {
+    fn drop(&mut self) { /* ... */ }
+}
+
+let mut x = Foo { a: 1 };
+drop(x);
+x = Foo { a: 2 };
+```
+"##,
+
 E0384: r##"
 This error occurs when an attempt is made to reassign an immutable variable.
 For example:
@@ -272,6 +469,161 @@ fn main() {
 ```
 "##,
 
+/*E0386: r##"
+This error occurs when an attempt is made to mutate the target of a mutable
+reference stored inside an immutable container.
+
+For example, this can happen when storing a `&mut` inside an immutable `Box`:
+
+```compile_fail,E0386
+let mut x: i64 = 1;
+let y: Box<_> = Box::new(&mut x);
+**y = 2; // error, cannot assign to data in an immutable container
+```
+
+This error can be fixed by making the container mutable:
+
+```
+let mut x: i64 = 1;
+let mut y: Box<_> = Box::new(&mut x);
+**y = 2;
+```
+
+It can also be fixed by using a type with interior mutability, such as `Cell`
+or `RefCell`:
+
+```
+use std::cell::Cell;
+
+let x: i64 = 1;
+let y: Box<Cell<_>> = Box::new(Cell::new(x));
+y.set(2);
+```
+"##,*/
+
+E0387: r##"
+This error occurs when an attempt is made to mutate or mutably reference data
+that a closure has captured immutably. Examples of this error are shown below:
+
+```compile_fail,E0387
+// Accepts a function or a closure that captures its environment immutably.
+// Closures passed to foo will not be able to mutate their closed-over state.
+fn foo<F: Fn()>(f: F) { }
+
+// Attempts to mutate closed-over data. Error message reads:
+// `cannot assign to data in a captured outer variable...`
+fn mutable() {
+    let mut x = 0u32;
+    foo(|| x = 2);
+}
+
+// Attempts to take a mutable reference to closed-over data.  Error message
+// reads: `cannot borrow data mutably in a captured outer variable...`
+fn mut_addr() {
+    let mut x = 0u32;
+    foo(|| { let y = &mut x; });
+}
+```
+
+The problem here is that foo is defined as accepting a parameter of type `Fn`.
+Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
+they capture their context immutably.
+
+If the definition of `foo` is under your control, the simplest solution is to
+capture the data mutably. This can be done by defining `foo` to take FnMut
+rather than Fn:
+
+```
+fn foo<F: FnMut()>(f: F) { }
+```
+
+Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
+interior mutability through a shared reference. Our example's `mutable`
+function could be redefined as below:
+
+```
+use std::cell::Cell;
+
+fn foo<F: Fn()>(f: F) { }
+
+fn mutable() {
+    let x = Cell::new(0u32);
+    foo(|| x.set(2));
+}
+```
+
+You can read more about cell types in the API documentation:
+
+https://doc.rust-lang.org/std/cell/
+"##,
+
+E0388: r##"
+E0388 was removed and is no longer issued.
+"##,
+
+E0389: r##"
+An attempt was made to mutate data using a non-mutable reference. This
+commonly occurs when attempting to assign to a non-mutable reference of a
+mutable reference (`&(&mut T)`).
+
+Example of erroneous code:
+
+```compile_fail,E0389
+struct FancyNum {
+    num: u8,
+}
+
+fn main() {
+    let mut fancy = FancyNum{ num: 5 };
+    let fancy_ref = &(&mut fancy);
+    fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
+    println!("{}", fancy_ref.num);
+}
+```
+
+Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
+immutable reference to a value borrows it immutably. There can be multiple
+references of type `&(&mut T)` that point to the same value, so they must be
+immutable to prevent multiple mutable references to the same value.
+
+To fix this, either remove the outer reference:
+
+```
+struct FancyNum {
+    num: u8,
+}
+
+fn main() {
+    let mut fancy = FancyNum{ num: 5 };
+
+    let fancy_ref = &mut fancy;
+    // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)
+
+    fancy_ref.num = 6; // No error!
+
+    println!("{}", fancy_ref.num);
+}
+```
+
+Or make the outer reference mutable:
+
+```
+struct FancyNum {
+    num: u8
+}
+
+fn main() {
+    let mut fancy = FancyNum{ num: 5 };
+
+    let fancy_ref = &mut (&mut fancy);
+    // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)
+
+    fancy_ref.num = 6; // No error!
+
+    println!("{}", fancy_ref.num);
+}
+```
+"##,
 
 E0394: r##"
 A static was referred to by value by another static.
@@ -999,12 +1351,435 @@ fn print_fancy_ref(fancy_ref: &FancyNum){
 ```
 "##,
 
+E0507: r##"
+You tried to move out of a value which was borrowed. Erroneous code example:
+
+```compile_fail,E0507
+use std::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
+}
+```
+
+Here, the `nothing_is_true` method takes the ownership of `self`. However,
+`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
+which is a borrow of the content owned by the `RefCell`. To fix this error,
+you have three choices:
+
+* Try to avoid moving the variable.
+* Somehow reclaim the ownership.
+* Implement the `Copy` trait on the type.
+
+Examples:
+
+```
+use std::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(&self) {} // First case, we don't take ownership
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); // ok!
+}
+```
+
+Or:
+
+```
+use std::cell::RefCell;
+
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+    let x = x.into_inner(); // we get back ownership
+
+    x.nothing_is_true(); // ok!
+}
+```
+
+Or:
+
+```
+use std::cell::RefCell;
+
+#[derive(Clone, Copy)] // we implement the Copy trait
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+fn main() {
+    let x = RefCell::new(TheDarkKnight);
+
+    x.borrow().nothing_is_true(); // ok!
+}
+```
+
+Moving a member out of a mutably borrowed struct will also cause E0507 error:
+
+```compile_fail,E0507
+struct TheDarkKnight;
+
+impl TheDarkKnight {
+    fn nothing_is_true(self) {}
+}
+
+struct Batcave {
+    knight: TheDarkKnight
+}
+
+fn main() {
+    let mut cave = Batcave {
+        knight: TheDarkKnight
+    };
+    let borrowed = &mut cave;
+
+    borrowed.knight.nothing_is_true(); // E0507
+}
+```
+
+It is fine only if you put something back. `mem::replace` can be used for that:
+
+```
+# struct TheDarkKnight;
+# impl TheDarkKnight { fn nothing_is_true(self) {} }
+# struct Batcave { knight: TheDarkKnight }
+use std::mem;
+
+let mut cave = Batcave {
+    knight: TheDarkKnight
+};
+let borrowed = &mut cave;
+
+mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
+```
+
+You can find more information about borrowing in the rust-book:
+http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
+"##,
+
+E0508: r##"
+A value was moved out of a non-copy fixed-size array.
+
+Example of erroneous code:
+
+```compile_fail,E0508
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
+                           //        a non-copy fixed-size array
+}
+```
+
+The first element was moved out of the array, but this is not
+possible because `NonCopy` does not implement the `Copy` trait.
+
+Consider borrowing the element instead of moving it:
+
+```
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = &array[0]; // Borrowing is allowed, unlike moving.
+}
+```
+
+Alternatively, if your type implements `Clone` and you need to own the value,
+consider borrowing and then cloning:
+
+```
+#[derive(Clone)]
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    // Now you can clone the array element.
+    let _value = array[0].clone();
+}
+```
+"##,
+
+E0509: r##"
+This error occurs when an attempt is made to move out of a value whose type
+implements the `Drop` trait.
+
+Example of erroneous code:
+
+```compile_fail,E0509
+struct FancyNum {
+    num: usize
+}
+
+struct DropStruct {
+    fancy: FancyNum
+}
+
+impl Drop for DropStruct {
+    fn drop(&mut self) {
+        // Destruct DropStruct, possibly using FancyNum
+    }
+}
+
+fn main() {
+    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
+    let fancy_field = drop_struct.fancy; // Error E0509
+    println!("Fancy: {}", fancy_field.num);
+    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
+}
+```
+
+Here, we tried to move a field out of a struct of type `DropStruct` which
+implements the `Drop` trait. However, a struct cannot be dropped if one or
+more of its fields have been moved.
+
+Structs implementing the `Drop` trait have an implicit destructor that gets
+called when they go out of scope. This destructor may use the fields of the
+struct, so moving out of the struct could make it impossible to run the
+destructor. Therefore, we must think of all values whose type implements the
+`Drop` trait as single units whose fields cannot be moved.
+
+This error can be fixed by creating a reference to the fields of a struct,
+enum, or tuple using the `ref` keyword:
+
+```
+struct FancyNum {
+    num: usize
+}
+
+struct DropStruct {
+    fancy: FancyNum
+}
+
+impl Drop for DropStruct {
+    fn drop(&mut self) {
+        // Destruct DropStruct, possibly using FancyNum
+    }
+}
+
+fn main() {
+    let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
+    let ref fancy_field = drop_struct.fancy; // No more errors!
+    println!("Fancy: {}", fancy_field.num);
+    // implicit call to `drop_struct.drop()` as drop_struct goes out of scope
+}
+```
+
+Note that this technique can also be used in the arms of a match expression:
+
+```
+struct FancyNum {
+    num: usize
+}
+
+enum DropEnum {
+    Fancy(FancyNum)
+}
+
+impl Drop for DropEnum {
+    fn drop(&mut self) {
+        // Destruct DropEnum, possibly using FancyNum
+    }
+}
+
+fn main() {
+    // Creates and enum of type `DropEnum`, which implements `Drop`
+    let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
+    match drop_enum {
+        // Creates a reference to the inside of `DropEnum::Fancy`
+        DropEnum::Fancy(ref fancy_field) => // No error!
+            println!("It was fancy-- {}!", fancy_field.num),
+    }
+    // implicit call to `drop_enum.drop()` as drop_enum goes out of scope
+}
+```
+"##,
+
+E0595: r##"
+Closures cannot mutate immutable captured variables.
+
+Erroneous code example:
+
+```compile_fail,E0595
+let x = 3; // error: closure cannot assign to immutable local variable `x`
+let mut c = || { x += 1 };
+```
+
+Make the variable binding mutable:
+
+```
+let mut x = 3; // ok!
+let mut c = || { x += 1 };
+```
+"##,
+
+E0596: r##"
+This error occurs because you tried to mutably borrow a non-mutable variable.
+
+Example of erroneous code:
+
+```compile_fail,E0596
+let x = 1;
+let y = &mut x; // error: cannot borrow mutably
+```
+
+In here, `x` isn't mutable, so when we try to mutably borrow it in `y`, it
+fails. To fix this error, you need to make `x` mutable:
+
+```
+let mut x = 1;
+let y = &mut x; // ok!
+```
+"##,
+
+E0597: r##"
+This error occurs because a borrow was made inside a variable which has a
+greater lifetime than the borrowed one.
+
+Example of erroneous code:
+
+```compile_fail,E0597
+struct Foo<'a> {
+    x: Option<&'a u32>,
+}
+
+let mut x = Foo { x: None };
+let y = 0;
+x.x = Some(&y); // error: `y` does not live long enough
+```
+
+In here, `x` is created before `y` and therefore has a greater lifetime. Always
+keep in mind that values in a scope are dropped in the opposite order they are
+created. So to fix the previous example, just make the `y` lifetime greater than
+the `x`'s one:
+
+```
+struct Foo<'a> {
+    x: Option<&'a u32>,
+}
+
+let y = 0;
+let mut x = Foo { x: None };
+x.x = Some(&y);
+```
+"##,
+
+E0626: r##"
+This error occurs because a borrow in a generator persists across a
+yield point.
+
+```compile_fail,E0626
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+    let a = &String::new(); // <-- This borrow...
+    yield (); // ...is still in scope here, when the yield occurs.
+    println!("{}", a);
+};
+b.resume();
+```
+
+At present, it is not permitted to have a yield that occurs while a
+borrow is still in scope. To resolve this error, the borrow must
+either be "contained" to a smaller scope that does not overlap the
+yield or else eliminated in another way. So, for example, we might
+resolve the previous example by removing the borrow and just storing
+the integer by value:
+
+```
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+    let a = 3;
+    yield ();
+    println!("{}", a);
+};
+b.resume();
+```
+
+This is a very simple case, of course. In more complex cases, we may
+wish to have more than one reference to the value that was borrowed --
+in those cases, something like the `Rc` or `Arc` types may be useful.
+
+This error also frequently arises with iteration:
+
+```compile_fail,E0626
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+  let v = vec![1,2,3];
+  for &x in &v { // <-- borrow of `v` is still in scope...
+    yield x; // ...when this yield occurs.
+  }
+};
+b.resume();
+```
+
+Such cases can sometimes be resolved by iterating "by value" (or using
+`into_iter()`) to avoid borrowing:
+
+```
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+  let v = vec![1,2,3];
+  for x in v { // <-- Take ownership of the values instead!
+    yield x; // <-- Now yield is OK.
+  }
+};
+b.resume();
+```
+
+If taking ownership is not an option, using indices can work too:
+
+```
+# #![feature(generators, generator_trait)]
+# use std::ops::Generator;
+let mut b = || {
+  let v = vec![1,2,3];
+  let len = v.len(); // (*)
+  for i in 0..len {
+    let x = v[i]; // (*)
+    yield x; // <-- Now yield is OK.
+  }
+};
+b.resume();
+
+// (*) -- Unfortunately, these temporaries are currently required.
+// See <https://github.com/rust-lang/rust/issues/43122>.
+```
+"##,
+
 }
 
 register_diagnostics! {
+//    E0385, // {} in an aliasable location
     E0493, // destructors cannot be evaluated at compile-time
     E0524, // two closures require unique access to `..` at the same time
     E0526, // shuffle indices are not constant
     E0594, // cannot assign to {}
+    E0598, // lifetime of {} is too short to guarantee its contents can be...
     E0625, // thread-local statics cannot be accessed at compile-time
 }
diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs
index 67a3281dba4..cea66837d9a 100644
--- a/src/librustc_mir/transform/dump_mir.rs
+++ b/src/librustc_mir/transform/dump_mir.rs
@@ -65,7 +65,18 @@ impl PassHook for DumpMir {
                                pass_name,
                                &Disambiguator { is_after },
                                source,
-                               mir);
+                               mir,
+                               |_, _| Ok(()) );
+            for (index, promoted_mir) in mir.promoted.iter_enumerated() {
+                let promoted_source = MirSource::Promoted(source.item_id(), index);
+                mir_util::dump_mir(tcx,
+                                   Some((suite, pass_num)),
+                                   pass_name,
+                                   &Disambiguator { is_after },
+                                   promoted_source,
+                                   promoted_mir,
+                                   |_, _| Ok(()) );
+            }
         }
     }
 }
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index c833904adba..be1b794ecdf 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -45,7 +45,7 @@ impl MirPass for ElaborateDrops {
         }
         let id = src.item_id();
         let param_env = tcx.param_env(tcx.hir.local_def_id(id));
-        let move_data = MoveData::gather_moves(mir, tcx, param_env);
+        let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
         let elaborate_patch = {
             let mir = &*mir;
             let env = MoveDataParamEnv {
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 729fe46ef37..7d0814b67fb 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -587,7 +587,7 @@ fn create_generator_drop_shim<'a, 'tcx>(
     // unrelated code from the resume part of the function
     simplify::remove_dead_blocks(&mut mir);
 
-    dump_mir(tcx, None, "generator_drop", &0, source, &mut mir);
+    dump_mir(tcx, None, "generator_drop", &0, source, &mut mir, |_, _| Ok(()) );
 
     mir
 }
@@ -673,7 +673,7 @@ fn create_generator_resume_function<'a, 'tcx>(
     // unrelated code from the drop part of the function
     simplify::remove_dead_blocks(mir);
 
-    dump_mir(tcx, None, "generator_resume", &0, source, mir);
+    dump_mir(tcx, None, "generator_resume", &0, source, mir, |_, _| Ok(()) );
 }
 
 fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo {
@@ -816,14 +816,14 @@ impl MirPass for StateTransform {
         // This is expanded to a drop ladder in `elaborate_generator_drops`.
         let drop_clean = insert_clean_drop(mir);
 
-        dump_mir(tcx, None, "generator_pre-elab", &0, source, mir);
+        dump_mir(tcx, None, "generator_pre-elab", &0, source, mir, |_, _| Ok(()) );
 
         // Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
         // If any upvars are moved out of, drop elaboration will handle upvar destruction.
         // However we need to also elaborate the code generated by `insert_clean_drop`.
         elaborate_generator_drops(tcx, def_id, mir);
 
-        dump_mir(tcx, None, "generator_post-transform", &0, source, mir);
+        dump_mir(tcx, None, "generator_post-transform", &0, source, mir, |_, _| Ok(()) );
 
         // Create a copy of our MIR and use it to create the drop shim for the generator
         let drop_shim = create_generator_drop_shim(tcx,
diff --git a/src/librustc_mir/transform/nll/infer.rs b/src/librustc_mir/transform/nll/infer.rs
new file mode 100644
index 00000000000..e6e00f295ca
--- /dev/null
+++ b/src/librustc_mir/transform/nll/infer.rs
@@ -0,0 +1,222 @@
+// 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 super::{Region, RegionIndex};
+use std::mem;
+use rustc::infer::InferCtxt;
+use rustc::mir::{Location, Mir};
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_data_structures::fx::FxHashSet;
+
+pub struct InferenceContext {
+    definitions: IndexVec<RegionIndex, VarDefinition>,
+    constraints: IndexVec<ConstraintIndex, Constraint>,
+    errors: IndexVec<InferenceErrorIndex, InferenceError>,
+}
+
+pub struct InferenceError {
+    pub constraint_point: Location,
+    pub name: (), // FIXME(nashenas88) RegionName
+}
+
+newtype_index!(InferenceErrorIndex);
+
+struct VarDefinition {
+    name: (), // FIXME(nashenas88) RegionName
+    value: Region,
+    capped: bool,
+}
+
+impl VarDefinition {
+    pub fn new(value: Region) -> Self {
+        Self {
+            name: (),
+            value,
+            capped: false,
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Constraint {
+    sub: RegionIndex,
+    sup: RegionIndex,
+    point: Location,
+}
+
+newtype_index!(ConstraintIndex);
+
+impl InferenceContext {
+    pub fn new(values: IndexVec<RegionIndex, Region>) -> Self {
+        Self {
+            definitions: values.into_iter().map(VarDefinition::new).collect(),
+            constraints: IndexVec::new(),
+            errors: IndexVec::new(),
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn cap_var(&mut self, v: RegionIndex) {
+        self.definitions[v].capped = true;
+    }
+
+    #[allow(dead_code)]
+    pub fn add_live_point(&mut self, v: RegionIndex, point: Location) {
+        debug!("add_live_point({:?}, {:?})", v, point);
+        let definition = &mut self.definitions[v];
+        if definition.value.add_point(point) {
+            if definition.capped {
+                self.errors.push(InferenceError {
+                    constraint_point: point,
+                    name: definition.name,
+                });
+            }
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn add_outlives(&mut self, sup: RegionIndex, sub: RegionIndex, point: Location) {
+        debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
+        self.constraints.push(Constraint { sup, sub, point });
+    }
+
+    #[allow(dead_code)]
+    pub fn region(&self, v: RegionIndex) -> &Region {
+        &self.definitions[v].value
+    }
+
+    pub fn solve<'a, 'gcx, 'tcx>(
+        &mut self,
+        infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+        mir: &'a Mir<'tcx>,
+    ) -> IndexVec<InferenceErrorIndex, InferenceError>
+    where
+        'gcx: 'tcx + 'a,
+        'tcx: 'a,
+    {
+        let mut changed = true;
+        let mut dfs = Dfs::new(infcx, mir);
+        while changed {
+            changed = false;
+            for constraint in &self.constraints {
+                let sub = &self.definitions[constraint.sub].value.clone();
+                let sup_def = &mut self.definitions[constraint.sup];
+                debug!("constraint: {:?}", constraint);
+                debug!("    sub (before): {:?}", sub);
+                debug!("    sup (before): {:?}", sup_def.value);
+
+                if dfs.copy(sub, &mut sup_def.value, constraint.point) {
+                    changed = true;
+                    if sup_def.capped {
+                        // This is kind of a hack, but when we add a
+                        // constraint, the "point" is always the point
+                        // AFTER the action that induced the
+                        // constraint. So report the error on the
+                        // action BEFORE that.
+                        assert!(constraint.point.statement_index > 0);
+                        let p = Location {
+                            block: constraint.point.block,
+                            statement_index: constraint.point.statement_index - 1,
+                        };
+
+                        self.errors.push(InferenceError {
+                            constraint_point: p,
+                            name: sup_def.name,
+                        });
+                    }
+                }
+
+                debug!("    sup (after) : {:?}", sup_def.value);
+                debug!("    changed     : {:?}", changed);
+            }
+            debug!("\n");
+        }
+
+        mem::replace(&mut self.errors, IndexVec::new())
+    }
+}
+
+struct Dfs<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
+    #[allow(dead_code)]
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'gcx: 'tcx, 'tcx: 'a> Dfs<'a, 'gcx, 'tcx> {
+    fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
+        Self { infcx, mir }
+    }
+
+    fn copy(
+        &mut self,
+        from_region: &Region,
+        to_region: &mut Region,
+        start_point: Location,
+    ) -> bool {
+        let mut changed = false;
+
+        let mut stack = vec![];
+        let mut visited = FxHashSet();
+
+        stack.push(start_point);
+        while let Some(p) = stack.pop() {
+            debug!("        dfs: p={:?}", p);
+
+            if !from_region.may_contain(p) {
+                debug!("            not in from-region");
+                continue;
+            }
+
+            if !visited.insert(p) {
+                debug!("            already visited");
+                continue;
+            }
+
+            changed |= to_region.add_point(p);
+
+            let block_data = &self.mir[p.block];
+            let successor_points = if p.statement_index < block_data.statements.len() {
+                vec![Location {
+                    statement_index: p.statement_index + 1,
+                    ..p
+                }]
+            } else {
+                block_data.terminator()
+                    .successors()
+                    .iter()
+                    .map(|&basic_block| Location {
+                        statement_index: 0,
+                        block: basic_block,
+                    })
+                    .collect::<Vec<_>>()
+            };
+
+            if successor_points.is_empty() {
+                // FIXME handle free regions
+                // If we reach the END point in the graph, then copy
+                // over any skolemized end points in the `from_region`
+                // and make sure they are included in the `to_region`.
+                // for region_decl in self.infcx.tcx.tables.borrow().free_region_map() {
+                //     // FIXME(nashenas88) figure out skolemized_end points
+                //     let block = self.env.graph.skolemized_end(region_decl.name);
+                //     let skolemized_end_point = Location {
+                //         block,
+                //         statement_index: 0,
+                //     };
+                //     changed |= to_region.add_point(skolemized_end_point);
+                // }
+            } else {
+                stack.extend(successor_points);
+            }
+        }
+
+        changed
+    }
+}
diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs
index d4a5354c78f..805e9c976e4 100644
--- a/src/librustc_mir/transform/nll/mod.rs
+++ b/src/librustc_mir/transform/nll/mod.rs
@@ -8,27 +8,35 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use self::infer::InferenceContext;
 use rustc::ty::TypeFoldable;
 use rustc::ty::subst::{Kind, Substs};
 use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind};
 use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind};
 use rustc::mir::visit::{MutVisitor, Lookup};
 use rustc::mir::transform::{MirPass, MirSource};
-use rustc::infer::{self, InferCtxt};
+use rustc::infer::{self as rustc_infer, InferCtxt};
 use rustc::util::nodemap::FxHashSet;
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use syntax_pos::DUMMY_SP;
 use std::collections::HashMap;
+use std::fmt;
+
+use util as mir_util;
+use self::mir_util::PassWhere;
+
+mod infer;
 
 #[allow(dead_code)]
 struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     lookup_map: HashMap<RegionVid, Lookup>,
     regions: IndexVec<RegionIndex, Region>,
-    infcx: InferCtxt<'a, 'gcx, 'tcx>,
+    #[allow(dead_code)]
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
-    pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
         NLLVisitor {
             infcx,
             lookup_map: HashMap::new(),
@@ -36,14 +44,14 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn into_results(self) -> HashMap<RegionVid, Lookup> {
-        self.lookup_map
+    pub fn into_results(self) -> (HashMap<RegionVid, Lookup>, IndexVec<RegionIndex, Region>) {
+        (self.lookup_map, self.regions)
     }
 
     fn renumber_regions<T>(&mut self, value: &T) -> T where T: TypeFoldable<'tcx> {
         self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
             self.regions.push(Region::default());
-            self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP))
+            self.infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP))
         })
     }
 
@@ -134,7 +142,7 @@ pub struct NLL;
 impl MirPass for NLL {
     fn run_pass<'a, 'tcx>(&self,
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          _: MirSource,
+                          source: MirSource,
                           mir: &mut Mir<'tcx>) {
         if !tcx.sess.opts.debugging_opts.nll {
             return;
@@ -143,16 +151,42 @@ impl MirPass for NLL {
         tcx.infer_ctxt().enter(|infcx| {
             // Clone mir so we can mutate it without disturbing the rest of the compiler
             let mut renumbered_mir = mir.clone();
-            let mut visitor = NLLVisitor::new(infcx);
+            let mut visitor = NLLVisitor::new(&infcx);
             visitor.visit_mir(&mut renumbered_mir);
-            let _results = visitor.into_results();
+            mir_util::dump_mir(tcx, None, "nll", &0, source, mir, |pass_where, out| {
+                if let PassWhere::BeforeCFG = pass_where {
+                    for (index, value) in visitor.regions.iter_enumerated() {
+                        writeln!(out, "// R{:03}: {:?}", index.0, value)?;
+                    }
+                }
+                Ok(())
+            });
+            let (_lookup_map, regions) = visitor.into_results();
+            let mut inference_context = InferenceContext::new(regions);
+            inference_context.solve(&infcx, &renumbered_mir);
         })
     }
 }
 
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-struct Region {
+#[derive(Clone, Default, PartialEq, Eq)]
+pub struct Region {
     points: FxHashSet<Location>,
 }
 
+impl fmt::Debug for Region {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        write!(formatter, "{:?}", self.points)
+    }
+}
+
+impl Region {
+    pub fn add_point(&mut self, point: Location) -> bool {
+        self.points.insert(point)
+    }
+
+    pub fn may_contain(&self, point: Location) -> bool {
+        self.points.contains(&point)
+    }
+}
+
 newtype_index!(RegionIndex);
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index ceff52409b2..8d6458d7934 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -45,7 +45,7 @@ impl MirPass for SanityCheck {
 
         let attributes = tcx.get_attrs(def_id);
         let param_env = tcx.param_env(def_id);
-        let move_data = MoveData::gather_moves(mir, tcx, param_env);
+        let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
         let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
         let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
         let flow_inits =
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 81e3cd7f61f..216f6e44570 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -248,6 +248,185 @@ pub trait BorrowckErrors {
     {
         self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
     }
+
+    fn cannot_move_out_of(&self, move_from_span: Span, move_from_desc: &str, o: Origin)
+                          -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self, move_from_span, E0507,
+                                       "cannot move out of {}{OGN}",
+                                       move_from_desc, OGN=o);
+        err.span_label(
+            move_from_span,
+            format!("cannot move out of {}", move_from_desc));
+        err
+    }
+
+    fn cannot_move_out_of_interior_noncopy(&self,
+                                           move_from_span: Span,
+                                           ty: ty::Ty,
+                                           is_index: bool,
+                                           o: Origin)
+                                           -> DiagnosticBuilder
+    {
+        let type_name = match (&ty.sty, is_index) {
+            (&ty::TyArray(_, _), true) => "array",
+            (&ty::TySlice(_),    _) => "slice",
+            _ => span_bug!(move_from_span, "this path should not cause illegal move"),
+        };
+        let mut err = struct_span_err!(self, move_from_span, E0508,
+                                       "cannot move out of type `{}`, \
+                                        a non-copy {}{OGN}",
+                                       ty, type_name, OGN=o);
+        err.span_label(move_from_span, "cannot move out of here");
+        err
+    }
+
+    fn cannot_move_out_of_interior_of_drop(&self,
+                                           move_from_span: Span,
+                                           container_ty: ty::Ty,
+                                           o: Origin)
+                                           -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self, move_from_span, E0509,
+                                       "cannot move out of type `{}`, \
+                                        which implements the `Drop` trait{OGN}",
+                                       container_ty, OGN=o);
+        err.span_label(move_from_span, "cannot move out of here");
+        err
+    }
+
+    fn cannot_act_on_moved_value(&self,
+                                 use_span: Span,
+                                 verb: &str,
+                                 optional_adverb_for_moved: &str,
+                                 moved_path: &str,
+                                 o: Origin)
+                                 -> DiagnosticBuilder
+    {
+        let err = struct_span_err!(self, use_span, E0382,
+                                   "{} of {}moved value: `{}`{OGN}",
+                                   verb, optional_adverb_for_moved, moved_path, OGN=o);
+        err
+    }
+
+    fn cannot_partially_reinit_an_uninit_struct(&self,
+                                                span: Span,
+                                                uninit_path: &str,
+                                                o: Origin)
+                                                -> DiagnosticBuilder
+    {
+        let err = struct_span_err!(self,
+                                   span,
+                                   E0383,
+                                   "partial reinitialization of uninitialized structure `{}`{OGN}",
+                                   uninit_path, OGN=o);
+        err
+    }
+
+    fn closure_cannot_assign_to_borrowed(&self,
+                                         span: Span,
+                                         descr: &str,
+                                         o: Origin)
+                                         -> DiagnosticBuilder
+    {
+        let err = struct_span_err!(self, span, E0595, "closure cannot assign to {}{OGN}",
+                                   descr, OGN=o);
+        err
+    }
+
+    fn cannot_borrow_path_as_mutable(&self,
+                                     span: Span,
+                                     path: &str,
+                                     o: Origin)
+                                     -> DiagnosticBuilder
+    {
+        let err = struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{OGN}",
+                                   path, OGN=o);
+        err
+    }
+
+    fn cannot_borrow_across_generator_yield(&self,
+                                            span: Span,
+                                            yield_span: Span,
+                                            o: Origin)
+                                            -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self,
+                                       span,
+                                       E0626,
+                                       "borrow may still be in use when generator yields{OGN}",
+                                       OGN=o);
+        err.span_label(yield_span, "possible yield occurs here");
+        err
+    }
+
+    fn path_does_not_live_long_enough(&self,
+                                      span: Span,
+                                      path: &str,
+                                      o: Origin)
+                                      -> DiagnosticBuilder
+    {
+        let err = struct_span_err!(self, span, E0597, "{} does not live long enough{OGN}",
+                                   path, OGN=o);
+        err
+    }
+
+    fn lifetime_too_short_for_reborrow(&self,
+                                       span: Span,
+                                       path: &str,
+                                       o: Origin)
+                                       -> DiagnosticBuilder
+    {
+        let err = struct_span_err!(self, span, E0598,
+                                   "lifetime of {} is too short to guarantee \
+                                    its contents can be safely reborrowed{OGN}",
+                                   path, OGN=o);
+        err
+    }
+
+    fn cannot_act_on_capture_in_sharable_fn(&self,
+                                            span: Span,
+                                            bad_thing: &str,
+                                            help: (Span, &str),
+                                            o: Origin)
+                                            -> DiagnosticBuilder
+    {
+        let (help_span, help_msg) = help;
+        let mut err = struct_span_err!(self, span, E0387,
+                                       "{} in a captured outer variable in an `Fn` closure{OGN}",
+                                       bad_thing, OGN=o);
+        err.span_help(help_span, help_msg);
+        err
+    }
+
+    fn cannot_assign_into_immutable_reference(&self,
+                                              span: Span,
+                                              bad_thing: &str,
+                                              o: Origin)
+                                              -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self, span, E0389, "{} in a `&` reference{OGN}",
+                                       bad_thing, OGN=o);
+        err.span_label(span, "assignment into an immutable reference");
+        err
+    }
+
+    fn cannot_capture_in_long_lived_closure(&self,
+                                            closure_span: Span,
+                                            borrowed_path: &str,
+                                            capture_span: Span,
+                                            o: Origin)
+                                            -> DiagnosticBuilder
+    {
+        let mut err = struct_span_err!(self, closure_span, E0373,
+                                       "closure may outlive the current function, \
+                                        but it borrows {}, \
+                                        which is owned by the current function{OGN}",
+                                       borrowed_path, OGN=o);
+        err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
+            .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
+        err
+    }
 }
 
 impl<'b, 'tcx, 'gcx> BorrowckErrors for TyCtxt<'b, 'tcx, 'gcx> {
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index e6d3a82ff9b..1424c063d73 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -232,7 +232,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             writeln!(w, "{} {{{}}}", prefix, live.join(", "))
         };
         print(w, "   ", &result.ins)?;
-        write_basic_block(tcx, block, mir, w)?;
+        write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?;
         print(w, "   ", &result.outs)?;
         if block.index() + 1 != mir.basic_blocks().len() {
             writeln!(w, "")?;
diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs
index 4b6da96824d..13c14f8920f 100644
--- a/src/librustc_mir/util/mod.rs
+++ b/src/librustc_mir/util/mod.rs
@@ -17,6 +17,6 @@ mod graphviz;
 mod pretty;
 pub mod liveness;
 
-pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty};
+pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
 pub use self::graphviz::{write_mir_graphviz};
 pub use self::graphviz::write_node_label as write_graphviz_node_label;
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 9e1f05f6d2f..8a9047fb491 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -25,6 +25,22 @@ const INDENT: &'static str = "    ";
 /// Alignment for lining up comments following MIR statements
 const ALIGN: usize = 40;
 
+/// An indication of where we are in the control flow graph. Used for printing
+/// extra information in `dump_mir`
+pub enum PassWhere {
+    /// We have not started dumping the control flow graph, but we are about to.
+    BeforeCFG,
+
+    /// We just finished dumping the control flow graph. This is right before EOF
+    AfterCFG,
+
+    /// We are about to start dumping the given basic block.
+    BeforeBlock(BasicBlock),
+
+    /// We are just about to dumpt the given statement or terminator.
+    InCFG(Location),
+}
+
 /// If the session is properly configured, dumps a human-readable
 /// representation of the mir into:
 ///
@@ -39,12 +55,16 @@ const ALIGN: usize = 40;
 /// - `substring1&substring2,...` -- `&`-separated list of substrings
 ///   that can appear in the pass-name or the `item_path_str` for the given
 ///   node-id. If any one of the substrings match, the data is dumped out.
-pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          pass_num: Option<(MirSuite, MirPassIndex)>,
-                          pass_name: &str,
-                          disambiguator: &Display,
-                          source: MirSource,
-                          mir: &Mir<'tcx>) {
+pub fn dump_mir<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             pass_num: Option<(MirSuite, MirPassIndex)>,
+                             pass_name: &str,
+                             disambiguator: &Display,
+                             source: MirSource,
+                             mir: &Mir<'tcx>,
+                             extra_data: F)
+where
+    F: FnMut(PassWhere, &mut Write) -> io::Result<()>
+{
     if !dump_enabled(tcx, pass_name, source) {
         return;
     }
@@ -53,12 +73,7 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         tcx.item_path_str(tcx.hir.local_def_id(source.item_id()))
     });
     dump_matched_mir_node(tcx, pass_num, pass_name, &node_path,
-                          disambiguator, source, mir);
-    for (index, promoted_mir) in mir.promoted.iter_enumerated() {
-        let promoted_source = MirSource::Promoted(source.item_id(), index);
-        dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
-                              promoted_source, promoted_mir);
-    }
+                          disambiguator, source, mir, extra_data);
 }
 
 pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -85,13 +100,17 @@ pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 // `item_path_str()` would otherwise trigger `type_of`, and this can
 // run while we are already attempting to evaluate `type_of`.
 
-fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                   pass_num: Option<(MirSuite, MirPassIndex)>,
-                                   pass_name: &str,
-                                   node_path: &str,
-                                   disambiguator: &Display,
-                                   source: MirSource,
-                                   mir: &Mir<'tcx>) {
+fn dump_matched_mir_node<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                      pass_num: Option<(MirSuite, MirPassIndex)>,
+                                      pass_name: &str,
+                                      node_path: &str,
+                                      disambiguator: &Display,
+                                      source: MirSource,
+                                      mir: &Mir<'tcx>,
+                                      mut extra_data: F)
+where
+    F: FnMut(PassWhere, &mut Write) -> io::Result<()>
+{
     let promotion_id = match source {
         MirSource::Promoted(_, id) => format!("-{:?}", id),
         MirSource::GeneratorDrop(_) => format!("-drop"),
@@ -125,7 +144,9 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             writeln!(file, "// generator_layout = {:?}", layout)?;
         }
         writeln!(file, "")?;
-        write_mir_fn(tcx, source, mir, &mut file)?;
+        extra_data(PassWhere::BeforeCFG, &mut file)?;
+        write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
+        extra_data(PassWhere::AfterCFG, &mut file)?;
         Ok(())
     });
 }
@@ -152,24 +173,29 @@ pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         let id = tcx.hir.as_local_node_id(def_id).unwrap();
         let src = MirSource::from_node(tcx, id);
-        write_mir_fn(tcx, src, mir, w)?;
+        write_mir_fn(tcx, src, mir, &mut |_, _| Ok(()), w)?;
 
         for (i, mir) in mir.promoted.iter_enumerated() {
             writeln!(w, "")?;
-            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
+            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, &mut |_, _| Ok(()), w)?;
         }
     }
     Ok(())
 }
 
-pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              src: MirSource,
-                              mir: &Mir<'tcx>,
-                              w: &mut Write)
-                              -> io::Result<()> {
+pub fn write_mir_fn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 src: MirSource,
+                                 mir: &Mir<'tcx>,
+                                 extra_data: &mut F,
+                                 w: &mut Write)
+                                 -> io::Result<()>
+where
+    F: FnMut(PassWhere, &mut Write) -> io::Result<()>
+{
     write_mir_intro(tcx, src, mir, w)?;
     for block in mir.basic_blocks().indices() {
-        write_basic_block(tcx, block, mir, w)?;
+        extra_data(PassWhere::BeforeBlock(block), w)?;
+        write_basic_block(tcx, block, mir, extra_data, w)?;
         if block.index() + 1 != mir.basic_blocks().len() {
             writeln!(w, "")?;
         }
@@ -180,11 +206,15 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 /// Write out a human-readable textual representation for the given basic block.
-pub fn write_basic_block(tcx: TyCtxt,
-                     block: BasicBlock,
-                     mir: &Mir,
-                     w: &mut Write)
-                     -> io::Result<()> {
+pub fn write_basic_block<F>(tcx: TyCtxt,
+                            block: BasicBlock,
+                            mir: &Mir,
+                            extra_data: &mut F,
+                            w: &mut Write)
+                            -> io::Result<()>
+where
+    F: FnMut(PassWhere, &mut Write) -> io::Result<()>
+{
     let data = &mir[block];
 
     // Basic block label at the top.
@@ -195,6 +225,7 @@ pub fn write_basic_block(tcx: TyCtxt,
     // List of statements in the middle.
     let mut current_location = Location { block: block, statement_index: 0 };
     for statement in &data.statements {
+        extra_data(PassWhere::InCFG(current_location), w)?;
         let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
         writeln!(w, "{0:1$} // {2}",
                  indented_mir,
@@ -205,6 +236,7 @@ pub fn write_basic_block(tcx: TyCtxt,
     }
 
     // Terminator at the bottom.
+    extra_data(PassWhere::InCFG(current_location), w)?;
     let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
     writeln!(w, "{0:1$} // {2}",
              indented_terminator,
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index efb5b031809..14e33378969 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -152,7 +152,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     err.emit();
                 });
             }
-            TyKind::TraitObject(ref bounds) => {
+            TyKind::TraitObject(ref bounds, ..) => {
                 let mut any_lifetime_bounds = false;
                 for bound in bounds {
                     if let RegionTyParamBound(ref lifetime) = *bound {
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 547d63fc3d4..d3202ba4ab5 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -39,20 +39,79 @@ use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::mir::transform::MirSource;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::{queries, Providers};
 use rustc::ty::subst::Substs;
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::NodeSet;
+use rustc::util::nodemap::{ItemLocalMap, NodeSet};
 use rustc::lint::builtin::CONST_ERR;
-
 use rustc::hir::{self, PatKind, RangeEnd};
+use std::rc::Rc;
 use syntax::ast;
 use syntax_pos::{Span, DUMMY_SP};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 
-use std::collections::hash_map::Entry;
 use std::cmp::Ordering;
 
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        rvalue_promotable_map,
+        const_is_rvalue_promotable_to_static,
+        ..*providers
+    };
+}
+
+pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    for &body_id in &tcx.hir.krate().body_ids {
+        let def_id = tcx.hir.body_owner_def_id(body_id);
+        tcx.const_is_rvalue_promotable_to_static(def_id);
+    }
+    tcx.sess.abort_if_errors();
+}
+
+fn const_is_rvalue_promotable_to_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                                  def_id: DefId)
+                                                  -> bool
+{
+    assert!(def_id.is_local());
+
+    let node_id = tcx.hir.as_local_node_id(def_id)
+                     .expect("rvalue_promotable_map invoked with non-local def-id");
+    let body_id = tcx.hir.body_owned_by(node_id);
+    let body_hir_id = tcx.hir.node_to_hir_id(body_id.node_id);
+    tcx.rvalue_promotable_map(def_id).contains_key(&body_hir_id.local_id)
+}
+
+fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   def_id: DefId)
+                                   -> Rc<ItemLocalMap<bool>>
+{
+    let outer_def_id = tcx.closure_base_def_id(def_id);
+    if outer_def_id != def_id {
+        return tcx.rvalue_promotable_map(outer_def_id);
+    }
+
+    let mut visitor = CheckCrateVisitor {
+        tcx,
+        tables: &ty::TypeckTables::empty(None),
+        in_fn: false,
+        in_static: false,
+        promotable: false,
+        mut_rvalue_borrows: NodeSet(),
+        param_env: ty::ParamEnv::empty(Reveal::UserFacing),
+        identity_substs: Substs::empty(),
+        result_map: ItemLocalMap(),
+    };
+
+    // `def_id` should be a `Body` owner
+    let node_id = tcx.hir.as_local_node_id(def_id)
+                     .expect("rvalue_promotable_map invoked with non-local def-id");
+    let body_id = tcx.hir.body_owned_by(node_id);
+    visitor.visit_nested_body(body_id);
+
+    Rc::new(visitor.result_map)
+}
+
 struct CheckCrateVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     in_fn: bool,
@@ -62,6 +121,7 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> {
     param_env: ty::ParamEnv<'tcx>,
     identity_substs: &'tcx Substs<'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
+    result_map: ItemLocalMap<bool>,
 }
 
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
@@ -109,18 +169,11 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        // note that we *do* visit nested bodies, because we override `visit_nested_body` below
         NestedVisitorMap::None
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
-        match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body_id.node_id) {
-            Entry::Occupied(_) => return,
-            Entry::Vacant(entry) => {
-                // Prevent infinite recursion on re-entry.
-                entry.insert(false);
-            }
-        }
-
         let item_id = self.tcx.hir.body_owner(body_id);
         let item_def_id = self.tcx.hir.local_def_id(item_id);
 
@@ -151,7 +204,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
         let tcx = self.tcx;
         let param_env = self.param_env;
         let region_scope_tree = self.tcx.region_scope_tree(item_def_id);
-        euv::ExprUseVisitor::new(self, tcx, param_env, &region_scope_tree, self.tables)
+        euv::ExprUseVisitor::new(self, tcx, param_env, &region_scope_tree, self.tables, None)
             .consume_body(body);
 
         self.visit_body(body);
@@ -270,7 +323,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             }
         }
 
-        self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
+        self.result_map.insert(ex.hir_id.local_id, self.promotable);
         self.promotable &= outer;
     }
 }
@@ -371,16 +424,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                     let promotable = if v.tcx.trait_of_item(did).is_some() {
                         // Don't peek inside trait associated constants.
                         false
-                    } else if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
-                        match v.tcx.hir.maybe_body_owned_by(node_id) {
-                            Some(body) => {
-                                v.visit_nested_body(body);
-                                v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
-                            }
-                            None => false
-                        }
                     } else {
-                        v.tcx.const_is_rvalue_promotable_to_static(did)
+                        queries::const_is_rvalue_promotable_to_static::try_get(v.tcx, e.span, did)
+                            .unwrap_or_else(|mut err| {
+                                // A cycle between constants ought to be reported elsewhere.
+                                err.cancel();
+                                v.tcx.sess.delay_span_bug(
+                                    e.span,
+                                    &format!("cycle encountered during const qualification: {:?}",
+                                             did));
+                                false
+                            })
                     };
 
                     // Just in case the type is more specific than the definition,
@@ -513,20 +567,6 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
     }
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.hir.krate().visit_all_item_likes(&mut CheckCrateVisitor {
-        tcx,
-        tables: &ty::TypeckTables::empty(None),
-        in_fn: false,
-        in_static: false,
-        promotable: false,
-        mut_rvalue_borrows: NodeSet(),
-        param_env: ty::ParamEnv::empty(Reveal::UserFacing),
-        identity_substs: Substs::empty(),
-    }.as_deep_visitor());
-    tcx.sess.abort_if_errors();
-}
-
 impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
     fn consume(&mut self,
                _consume_id: ast::NodeId,
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 28b99e1185b..9a150abea66 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -33,6 +33,8 @@ extern crate syntax;
 extern crate syntax_pos;
 extern crate rustc_errors as errors;
 
+use rustc::ty::maps::Providers;
+
 mod diagnostics;
 
 pub mod ast_validation;
@@ -44,3 +46,7 @@ pub mod no_asm;
 pub mod static_recursion;
 
 __build_diagnostic_array! { librustc_passes, DIAGNOSTICS }
+
+pub fn provide(providers: &mut Providers) {
+    consts::provide(providers);
+}
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 9193ac0fcd6..564626ac398 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -43,7 +43,7 @@ parameter if so.
 "##,
 
 E0154: r##"
-## Note: this error code is no longer emitted by the compiler.
+#### Note: this error code is no longer emitted by the compiler.
 
 Imports (`use` statements) are not allowed after non-item statements, such as
 variable declarations and expression statements.
@@ -79,7 +79,7 @@ https://doc.rust-lang.org/reference.html#statements
 "##,
 
 E0251: r##"
-## Note: this error code is no longer emitted by the compiler.
+#### Note: this error code is no longer emitted by the compiler.
 
 Two items of the same name cannot be imported without rebinding one of the
 items under a new local name.
@@ -268,7 +268,7 @@ fn main() {
 "##,
 
 E0256: r##"
-## Note: this error code is no longer emitted by the compiler.
+#### Note: this error code is no longer emitted by the compiler.
 
 You can't import a type or module when the name of the item being imported is
 the same as another type or submodule defined in the module.
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 36cd69f91b9..0799c4f7190 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -137,7 +137,7 @@ enum ResolutionError<'a> {
     /// error E0416: identifier is bound more than once in the same pattern
     IdentifierBoundMoreThanOnceInSamePattern(&'a str),
     /// error E0426: use of undeclared label
-    UndeclaredLabel(&'a str),
+    UndeclaredLabel(&'a str, Option<Name>),
     /// error E0429: `self` imports are only allowed within a { } list
     SelfImportsOnlyAllowedWithin,
     /// error E0430: `self` import can only appear once in the list
@@ -263,13 +263,17 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             err.span_label(span, "used in a pattern more than once");
             err
         }
-        ResolutionError::UndeclaredLabel(name) => {
+        ResolutionError::UndeclaredLabel(name, lev_candidate) => {
             let mut err = struct_span_err!(resolver.session,
                                            span,
                                            E0426,
                                            "use of undeclared label `{}`",
                                            name);
-            err.span_label(span, format!("undeclared label `{}`", name));
+            if let Some(lev_candidate) = lev_candidate {
+                err.span_label(span, format!("did you mean `{}`?", lev_candidate));
+            } else {
+                err.span_label(span, format!("undeclared label `{}`", name));
+            }
             err
         }
         ResolutionError::SelfImportsOnlyAllowedWithin => {
@@ -714,12 +718,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
                 _: Span,
                 node_id: NodeId) {
         let rib_kind = match function_kind {
-            FnKind::ItemFn(_, generics, ..) => {
-                self.visit_generics(generics);
+            FnKind::ItemFn(..) => {
                 ItemRibKind
             }
             FnKind::Method(_, sig, _, _) => {
-                self.visit_generics(&sig.generics);
                 MethodRibKind(!sig.decl.has_self())
             }
             FnKind::Closure(_) => ClosureRibKind(node_id),
@@ -1790,9 +1792,13 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    /// Searches the current set of local scopes for labels.
+    /// Searches the current set of local scopes for labels. Returns the first non-None label that
+    /// is returned by the given predicate function
+    ///
     /// Stops after meeting a closure.
-    fn search_label(&self, mut ident: Ident) -> Option<Def> {
+    fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
+        where P: Fn(&Rib, Ident) -> Option<R>
+    {
         for rib in self.label_ribs.iter().rev() {
             match rib.kind {
                 NormalRibKind => {}
@@ -1808,9 +1814,9 @@ impl<'a> Resolver<'a> {
                     return None;
                 }
             }
-            let result = rib.bindings.get(&ident).cloned();
-            if result.is_some() {
-                return result;
+            let r = pred(rib, ident);
+            if r.is_some() {
+                return r;
             }
         }
         None
@@ -1872,7 +1878,7 @@ impl<'a> Resolver<'a> {
                                 }
                                 TraitItemKind::Method(ref sig, _) => {
                                     let type_parameters =
-                                        HasTypeParameters(&sig.generics,
+                                        HasTypeParameters(&trait_item.generics,
                                                           MethodRibKind(!sig.decl.has_self()));
                                     this.with_type_parameter_rib(type_parameters, |this| {
                                         visit::walk_trait_item(this, trait_item)
@@ -2076,7 +2082,9 @@ impl<'a> Resolver<'a> {
                                                             ValueNS,
                                                             impl_item.span,
                                             |n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
-                                        visit::walk_impl_item(this, impl_item);
+                                        this.with_constant_rib(|this|
+                                            visit::walk_impl_item(this, impl_item)
+                                        );
                                     }
                                     ImplItemKind::Method(ref sig, _) => {
                                         // If this is a trait impl, ensure the method
@@ -2089,7 +2097,7 @@ impl<'a> Resolver<'a> {
                                         // We also need a new scope for the method-
                                         // specific type parameters.
                                         let type_parameters =
-                                            HasTypeParameters(&sig.generics,
+                                            HasTypeParameters(&impl_item.generics,
                                                             MethodRibKind(!sig.decl.has_self()));
                                         this.with_type_parameter_rib(type_parameters, |this| {
                                             visit::walk_impl_item(this, impl_item);
@@ -3202,12 +3210,20 @@ impl<'a> Resolver<'a> {
             }
 
             ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
-                match self.search_label(label.node) {
+                match self.search_label(label.node, |rib, id| rib.bindings.get(&id).cloned()) {
                     None => {
+                        // Search again for close matches...
+                        // Picks the first label that is "close enough", which is not necessarily
+                        // the closest match
+                        let close_match = self.search_label(label.node, |rib, ident| {
+                            let names = rib.bindings.iter().map(|(id, _)| &id.name);
+                            find_best_match_for_name(names, &*ident.name.as_str(), None)
+                        });
                         self.record_def(expr.id, err_path_resolution());
                         resolve_error(self,
                                       label.span,
-                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str()));
+                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str(),
+                                                                       close_match));
                     }
                     Some(def @ Def::Label(_)) => {
                         // Since this def is a label, it is never read.
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index bd0774d9c42..ca44a088e23 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -354,23 +354,24 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                       body: Option<&'l ast::Block>,
                       id: ast::NodeId,
                       name: ast::Ident,
+                      generics: &'l ast::Generics,
                       vis: ast::Visibility,
                       span: Span) {
         debug!("process_method: {}:{}", id, name);
 
         if let Some(mut method_data) = self.save_ctxt.get_method_data(id, name.name, span) {
 
-            let sig_str = ::make_signature(&sig.decl, &sig.generics);
+            let sig_str = ::make_signature(&sig.decl, &generics);
             if body.is_some() {
                 self.nest_tables(id, |v| {
                     v.process_formals(&sig.decl.inputs, &method_data.qualname)
                 });
             }
 
-            self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
+            self.process_generic_params(&generics, span, &method_data.qualname, id);
 
             method_data.value = sig_str;
-            method_data.sig = sig::method_signature(id, name, sig, &self.save_ctxt);
+            method_data.sig = sig::method_signature(id, name, generics, sig, &self.save_ctxt);
             self.dumper.dump_def(vis == ast::Visibility::Public, method_data);
         }
 
@@ -1007,6 +1008,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                                     body.as_ref().map(|x| &**x),
                                     trait_item.id,
                                     trait_item.ident,
+                                    &trait_item.generics,
                                     ast::Visibility::Public,
                                     trait_item.span);
             }
@@ -1066,6 +1068,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                                     Some(body),
                                     impl_item.id,
                                     impl_item.ident,
+                                    &impl_item.generics,
                                     impl_item.vis.clone(),
                                     impl_item.span);
             }
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index c7e00245d63..88f574d513b 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -77,13 +77,14 @@ pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext) -> Option<Si
 
 pub fn method_signature(id: NodeId,
                         ident: ast::Ident,
+                        generics: &ast::Generics,
                         m: &ast::MethodSig,
                         scx: &SaveContext)
                         -> Option<Signature> {
     if !scx.config.signatures {
         return None;
     }
-    make_method_signature(id, ident, m, scx).ok()
+    make_method_signature(id, ident, generics, m, scx).ok()
 }
 
 pub fn assoc_const_signature(id: NodeId,
@@ -288,7 +289,7 @@ impl Sig for ast::Ty {
                     })
                 }
             }
-            ast::TyKind::TraitObject(ref bounds) => {
+            ast::TyKind::TraitObject(ref bounds, ..) => {
                 // FIXME recurse into bounds
                 let nested = pprust::bounds_to_string(bounds);
                 Ok(text_sig(nested))
@@ -895,6 +896,7 @@ fn make_assoc_const_signature(id: NodeId,
 
 fn make_method_signature(id: NodeId,
                          ident: ast::Ident,
+                         generics: &ast::Generics,
                          m: &ast::MethodSig,
                          scx: &SaveContext)
                          -> Result {
@@ -915,7 +917,7 @@ fn make_method_signature(id: NodeId,
 
     let mut sig = name_and_generics(text,
                                     0,
-                                    &m.generics,
+                                    generics,
                                     id,
                                     ident,
                                     scx)?;
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index 482350d04b5..5b7879ea58e 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -32,4 +32,4 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 
 [target."cfg(windows)".dependencies]
-cc = "1.0"
+cc = "1.0.1"
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 2aecc016a5c..6df40c34ec5 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -37,6 +37,7 @@ use type_of;
 use rustc::hir;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, Layout, LayoutTyper, TyLayout, Size};
+use rustc_back::PanicStrategy;
 
 use libc::c_uint;
 use std::cmp;
@@ -112,6 +113,10 @@ impl ArgAttributes {
         self
     }
 
+    pub fn contains(&self, attr: ArgAttribute) -> bool {
+        self.regular.contains(attr)
+    }
+
     pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
         unsafe {
             self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
@@ -750,9 +755,7 @@ impl<'a, 'tcx> FnType<'tcx> {
                 Some(ty.boxed_ty())
             }
 
-            ty::TyRef(b, mt) => {
-                use rustc::ty::{BrAnon, ReLateBound};
-
+            ty::TyRef(_, mt) => {
                 // `&mut` pointer parameters never alias other parameters, or mutable global data
                 //
                 // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
@@ -760,7 +763,17 @@ impl<'a, 'tcx> FnType<'tcx> {
                 // on memory dependencies rather than pointer equality
                 let is_freeze = ccx.shared().type_is_freeze(mt.ty);
 
-                if mt.mutbl != hir::MutMutable && is_freeze {
+                let no_alias_is_safe =
+                    if ccx.shared().tcx().sess.opts.debugging_opts.mutable_noalias ||
+                       ccx.shared().tcx().sess.panic_strategy() == PanicStrategy::Abort {
+                        // Mutable refrences or immutable shared references
+                        mt.mutbl == hir::MutMutable || is_freeze
+                    } else {
+                        // Only immutable shared references
+                        mt.mutbl != hir::MutMutable && is_freeze
+                    };
+
+                if no_alias_is_safe {
                     arg.attrs.set(ArgAttribute::NoAlias);
                 }
 
@@ -768,13 +781,6 @@ impl<'a, 'tcx> FnType<'tcx> {
                     arg.attrs.set(ArgAttribute::ReadOnly);
                 }
 
-                // When a reference in an argument has no named lifetime, it's
-                // impossible for that reference to escape this function
-                // (returned or stored beyond the call by a closure).
-                if let ReLateBound(_, BrAnon(_)) = *b {
-                    arg.attrs.set(ArgAttribute::NoCapture);
-                }
-
                 Some(mt.ty)
             }
             _ => None
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 23a45a7962a..b06f8e4e671 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -80,7 +80,7 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>,
         ty::TyGenerator(def_id, substs, _) => {
             if variant_index > 0 { bug!("{} is a generator, which only has one variant", t);}
             substs.field_tys(def_id, cx.tcx()).map(|t| {
-                cx.tcx().normalize_associated_type(&t)
+                cx.tcx().fully_normalize_associated_types_in(&t)
             }).collect()
         },
         _ => bug!("{} is not a type that can have fields.", t)
diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs
index 179ef20b19f..775cf3ac4c9 100644
--- a/src/librustc_trans/back/archive.rs
+++ b/src/librustc_trans/back/archive.rs
@@ -31,8 +31,7 @@ pub struct ArchiveConfig<'a> {
     pub lib_search_paths: Vec<PathBuf>,
 }
 
-/// Helper for adding many files to an archive with a single invocation of
-/// `ar`.
+/// Helper for adding many files to an archive.
 #[must_use = "must call build() to finish building the archive"]
 pub struct ArchiveBuilder<'a> {
     config: ArchiveConfig<'a>,
@@ -201,8 +200,8 @@ impl<'a> ArchiveBuilder<'a> {
         });
     }
 
-    /// Indicate that the next call to `build` should updates all symbols in
-    /// the archive (run 'ar s' over it).
+    /// Indicate that the next call to `build` should update all symbols in
+    /// the archive (equivalent to running 'ar s' over it).
     pub fn update_symbols(&mut self) {
         self.should_update_symbols = true;
     }
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 3badc1b9a69..b203bd640cf 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -9,13 +9,14 @@
 // except according to those terms.
 
 use super::archive::{ArchiveBuilder, ArchiveConfig};
-use super::bytecode::{self, RLIB_BYTECODE_EXTENSION};
+use super::bytecode::RLIB_BYTECODE_EXTENSION;
 use super::linker::Linker;
 use super::command::Command;
 use super::rpath::RPathConfig;
 use super::rpath;
 use metadata::METADATA_FILENAME;
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
+use rustc::session::config::RUST_CGU_EXT;
 use rustc::session::filesearch;
 use rustc::session::search_paths::PathKind;
 use rustc::session::Session;
@@ -36,7 +37,7 @@ use std::env;
 use std::ffi::OsString;
 use std::fmt;
 use std::fs::{self, File};
-use std::io::{self, Read, Write, BufWriter};
+use std::io::{self, Write, BufWriter};
 use std::path::{Path, PathBuf};
 use std::process::{Output, Stdio};
 use std::str;
@@ -45,13 +46,9 @@ use syntax::attr;
 /// The LLVM module name containing crate-metadata. This includes a `.` on
 /// purpose, so it cannot clash with the name of a user-defined module.
 pub const METADATA_MODULE_NAME: &'static str = "crate.metadata";
-/// The name of the crate-metadata object file the compiler generates. Must
-/// match up with `METADATA_MODULE_NAME`.
-pub const METADATA_OBJ_NAME: &'static str = "crate.metadata.o";
 
 // same as for metadata above, but for allocator shim
 pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator";
-pub const ALLOCATOR_OBJ_NAME: &'static str = "crate.allocator.o";
 
 pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_output_for_target,
                                   invalid_output_for_target, build_link_meta, out_filename,
@@ -170,13 +167,23 @@ pub fn link_binary(sess: &Session,
     // Remove the temporary object file and metadata if we aren't saving temps
     if !sess.opts.cg.save_temps {
         if sess.opts.output_types.should_trans() {
-            for obj in trans.modules.iter() {
-                remove(sess, &obj.object);
+            for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
+                remove(sess, obj);
             }
         }
-        remove(sess, &outputs.with_extension(METADATA_OBJ_NAME));
-        if trans.allocator_module.is_some() {
-            remove(sess, &outputs.with_extension(ALLOCATOR_OBJ_NAME));
+        for obj in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
+            remove(sess, obj);
+        }
+        if let Some(ref obj) = trans.metadata_module.object {
+            remove(sess, obj);
+        }
+        if let Some(ref allocator) = trans.allocator_module {
+            if let Some(ref obj) = allocator.object {
+                remove(sess, obj);
+            }
+            if let Some(ref bc) = allocator.bytecode_compressed {
+                remove(sess, bc);
+            }
         }
     }
 
@@ -251,8 +258,8 @@ fn link_binary_output(sess: &Session,
                       crate_type: config::CrateType,
                       outputs: &OutputFilenames,
                       crate_name: &str) -> Vec<PathBuf> {
-    for module in trans.modules.iter() {
-        check_file_is_writeable(&module.object, sess);
+    for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
+        check_file_is_writeable(obj, sess);
     }
 
     let tmpdir = match TempDir::new("rustc") {
@@ -275,20 +282,14 @@ fn link_binary_output(sess: &Session,
                 link_rlib(sess,
                           trans,
                           RlibFlavor::Normal,
-                          outputs,
                           &out_filename,
                           tmpdir.path()).build();
             }
             config::CrateTypeStaticlib => {
-                link_staticlib(sess,
-                               trans,
-                               outputs,
-                               &out_filename,
-                               tmpdir.path());
+                link_staticlib(sess, trans, &out_filename, tmpdir.path());
             }
             _ => {
-                link_natively(sess, crate_type, &out_filename,
-                              trans, outputs, tmpdir.path());
+                link_natively(sess, crate_type, &out_filename, trans, tmpdir.path());
             }
         }
         out_filenames.push(out_filename);
@@ -344,14 +345,13 @@ enum RlibFlavor {
 fn link_rlib<'a>(sess: &'a Session,
                  trans: &CrateTranslation,
                  flavor: RlibFlavor,
-                 outputs: &OutputFilenames,
                  out_filename: &Path,
                  tmpdir: &Path) -> ArchiveBuilder<'a> {
     info!("preparing rlib to {:?}", out_filename);
     let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None));
 
-    for module in trans.modules.iter() {
-        ab.add_file(&module.object);
+    for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
+        ab.add_file(obj);
     }
 
     // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
@@ -416,56 +416,9 @@ fn link_rlib<'a>(sess: &'a Session,
             ab.add_file(&metadata);
 
             // For LTO purposes, the bytecode of this library is also inserted
-            // into the archive.  If codegen_units > 1, we insert each of the
-            // bitcode files.
-            for module in trans.modules.iter() {
-                // Note that we make sure that the bytecode filename in the
-                // archive is never exactly 16 bytes long by adding a 16 byte
-                // extension to it. This is to work around a bug in LLDB that
-                // would cause it to crash if the name of a file in an archive
-                // was exactly 16 bytes.
-                let bc_filename = module.object.with_extension("bc");
-                let bc_encoded_filename = tmpdir.join({
-                    module.object.with_extension(RLIB_BYTECODE_EXTENSION).file_name().unwrap()
-                });
-
-                let mut bc_data = Vec::new();
-                match fs::File::open(&bc_filename).and_then(|mut f| {
-                    f.read_to_end(&mut bc_data)
-                }) {
-                    Ok(..) => {}
-                    Err(e) => sess.fatal(&format!("failed to read bytecode: {}",
-                                                 e))
-                }
-
-                let encoded = bytecode::encode(&module.llmod_id, &bc_data);
-
-                let mut bc_file_deflated = match fs::File::create(&bc_encoded_filename) {
-                    Ok(file) => file,
-                    Err(e) => {
-                        sess.fatal(&format!("failed to create compressed \
-                                             bytecode file: {}", e))
-                    }
-                };
-
-                match bc_file_deflated.write_all(&encoded) {
-                    Ok(()) => {}
-                    Err(e) => {
-                        sess.fatal(&format!("failed to write compressed \
-                                             bytecode: {}", e));
-                    }
-                };
-
-                ab.add_file(&bc_encoded_filename);
-
-                // See the bottom of back::write::run_passes for an explanation
-                // of when we do and don't keep .#module-name#.bc files around.
-                let user_wants_numbered_bitcode =
-                        sess.opts.output_types.contains_key(&OutputType::Bitcode) &&
-                        sess.opts.codegen_units > 1;
-                if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
-                    remove(sess, &bc_filename);
-                }
+            // into the archive.
+            for bytecode in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) {
+                ab.add_file(bytecode);
             }
 
             // After adding all files to the archive, we need to update the
@@ -477,8 +430,11 @@ fn link_rlib<'a>(sess: &'a Session,
         }
 
         RlibFlavor::StaticlibBase => {
-            if trans.allocator_module.is_some() {
-                ab.add_file(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+            let obj = trans.allocator_module
+                .as_ref()
+                .and_then(|m| m.object.as_ref());
+            if let Some(obj) = obj {
+                ab.add_file(obj);
             }
         }
     }
@@ -500,13 +456,11 @@ fn link_rlib<'a>(sess: &'a Session,
 // metadata file).
 fn link_staticlib(sess: &Session,
                   trans: &CrateTranslation,
-                  outputs: &OutputFilenames,
                   out_filename: &Path,
                   tempdir: &Path) {
     let mut ab = link_rlib(sess,
                            trans,
                            RlibFlavor::StaticlibBase,
-                           outputs,
                            out_filename,
                            tempdir);
     let mut all_native_libs = vec![];
@@ -611,7 +565,6 @@ fn link_natively(sess: &Session,
                  crate_type: config::CrateType,
                  out_filename: &Path,
                  trans: &CrateTranslation,
-                 outputs: &OutputFilenames,
                  tmpdir: &Path) {
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let flavor = sess.linker_flavor();
@@ -651,7 +604,7 @@ fn link_natively(sess: &Session,
     {
         let mut linker = trans.linker_info.to_linker(cmd, &sess);
         link_args(&mut *linker, sess, crate_type, tmpdir,
-                  out_filename, outputs, trans);
+                  out_filename, trans);
         cmd = linker.finalize();
     }
     if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
@@ -873,7 +826,6 @@ fn link_args(cmd: &mut Linker,
              crate_type: config::CrateType,
              tmpdir: &Path,
              out_filename: &Path,
-             outputs: &OutputFilenames,
              trans: &CrateTranslation) {
 
     // The default library location, we need this to find the runtime.
@@ -884,8 +836,8 @@ fn link_args(cmd: &mut Linker,
     let t = &sess.target.target;
 
     cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
-    for module in trans.modules.iter() {
-        cmd.add_object(&module.object);
+    for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) {
+        cmd.add_object(obj);
     }
     cmd.output_filename(out_filename);
 
@@ -908,11 +860,16 @@ fn link_args(cmd: &mut Linker,
     // object file, so we link that in here.
     if crate_type == config::CrateTypeDylib ||
        crate_type == config::CrateTypeProcMacro {
-        cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME));
+        if let Some(obj) = trans.metadata_module.object.as_ref() {
+            cmd.add_object(obj);
+        }
     }
 
-    if trans.allocator_module.is_some() {
-        cmd.add_object(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+    let obj = trans.allocator_module
+        .as_ref()
+        .and_then(|m| m.object.as_ref());
+    if let Some(obj) = obj {
+        cmd.add_object(obj);
     }
 
     // Try to strip as much out of the generated object by removing unused
@@ -1180,9 +1137,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
 
         for f in archive.src_files() {
             if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
-                    archive.remove_file(&f);
-                    continue
-                }
+                archive.remove_file(&f);
+                continue
+            }
         }
 
         archive.build();
@@ -1265,11 +1222,23 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
                 let canonical = f.replace("-", "_");
                 let canonical_name = name.replace("-", "_");
 
+                // Look for `.rust-cgu.o` at the end of the filename to conclude
+                // that this is a Rust-related object file.
+                fn looks_like_rust(s: &str) -> bool {
+                    let path = Path::new(s);
+                    let ext = path.extension().and_then(|s| s.to_str());
+                    if ext != Some(OutputType::Object.extension()) {
+                        return false
+                    }
+                    let ext2 = path.file_stem()
+                        .and_then(|s| Path::new(s).extension())
+                        .and_then(|s| s.to_str());
+                    ext2 == Some(RUST_CGU_EXT)
+                }
+
                 let is_rust_object =
-                    canonical.starts_with(&canonical_name) && {
-                        let num = &f[name.len()..f.len() - 2];
-                        num.len() > 0 && num[1..].parse::<u32>().is_ok()
-                    };
+                    canonical.starts_with(&canonical_name) &&
+                    looks_like_rust(&f);
 
                 // If we've been requested to skip all native object files
                 // (those not generated by the rust compiler) then we can skip
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 8651b95b12a..48c3fd638c3 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -9,23 +9,25 @@
 // except according to those terms.
 
 use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
-use back::write;
 use back::symbol_export;
-use rustc::session::config;
+use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
+use back::write;
 use errors::{FatalError, Handler};
-use llvm;
 use llvm::archive_ro::ArchiveRO;
 use llvm::{ModuleRef, TargetMachineRef, True, False};
+use llvm;
+use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::middle::exported_symbols::SymbolExportLevel;
+use rustc::session::config;
 use rustc::util::common::time;
-use rustc::hir::def_id::LOCAL_CRATE;
-use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
-use {ModuleTranslation, ModuleKind};
+use time_graph::Timeline;
+use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource};
 
 use libc;
 
 use std::ffi::CString;
 use std::slice;
+use std::sync::Arc;
 
 pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
     match crate_type {
@@ -45,14 +47,14 @@ pub enum LtoModuleTranslation {
         _serialized_bitcode: Vec<SerializedModule>,
     },
 
-    // Note the lack of other entries in this enum! Ideally one day this gap is
-    // intended to be filled with a "Thin" LTO variant.
+    Thin(ThinModule),
 }
 
 impl LtoModuleTranslation {
     pub fn name(&self) -> &str {
         match *self {
             LtoModuleTranslation::Fat { .. } => "everything",
+            LtoModuleTranslation::Thin(ref m) => m.name(),
         }
     }
 
@@ -62,7 +64,9 @@ impl LtoModuleTranslation {
     /// points to LLVM data structures owned by this `LtoModuleTranslation`.
     /// It's intended that the module returned is immediately code generated and
     /// dropped, and then this LTO module is dropped.
-    pub unsafe fn optimize(&mut self, cgcx: &CodegenContext)
+    pub unsafe fn optimize(&mut self,
+                           cgcx: &CodegenContext,
+                           timeline: &mut Timeline)
         -> Result<ModuleTranslation, FatalError>
     {
         match *self {
@@ -71,9 +75,11 @@ impl LtoModuleTranslation {
                 let config = cgcx.config(trans.kind);
                 let llmod = trans.llvm().unwrap().llmod;
                 let tm = trans.llvm().unwrap().tm;
-                run_pass_manager(cgcx, tm, llmod, config);
+                run_pass_manager(cgcx, tm, llmod, config, false);
+                timeline.record("fat-done");
                 Ok(trans)
             }
+            LtoModuleTranslation::Thin(ref mut thin) => thin.optimize(cgcx, timeline),
         }
     }
 
@@ -83,33 +89,31 @@ impl LtoModuleTranslation {
         match *self {
             // Only one module with fat LTO, so the cost doesn't matter.
             LtoModuleTranslation::Fat { .. } => 0,
+            LtoModuleTranslation::Thin(ref m) => m.cost(),
         }
     }
 }
 
-pub fn run(cgcx: &CodegenContext, modules: Vec<ModuleTranslation>)
+pub enum LTOMode {
+    WholeCrateGraph,
+    JustThisCrate,
+}
+
+pub fn run(cgcx: &CodegenContext,
+           modules: Vec<ModuleTranslation>,
+           mode: LTOMode,
+           timeline: &mut Timeline)
     -> Result<Vec<LtoModuleTranslation>, FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
-    if cgcx.opts.cg.prefer_dynamic {
-        diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
-                    .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
-                           supported with LTO")
-                    .emit();
-        return Err(FatalError)
-    }
-
-    // Make sure we actually can run LTO
-    for crate_type in cgcx.crate_types.iter() {
-        if !crate_type_allows_lto(*crate_type) {
-            let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \
-                                        static library outputs");
-            return Err(e)
+    let export_threshold = match mode {
+        LTOMode::WholeCrateGraph => {
+            symbol_export::crates_export_threshold(&cgcx.crate_types)
         }
-    }
-
-    let export_threshold =
-        symbol_export::crates_export_threshold(&cgcx.crate_types);
+        LTOMode::JustThisCrate => {
+            SymbolExportLevel::Rust
+        }
+    };
 
     let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
         if level.is_below_threshold(export_threshold) {
@@ -121,55 +125,82 @@ pub fn run(cgcx: &CodegenContext, modules: Vec<ModuleTranslation>)
         }
     };
 
-    let mut symbol_white_list: Vec<CString> = cgcx.exported_symbols[&LOCAL_CRATE]
+    let mut symbol_white_list = cgcx.exported_symbols[&LOCAL_CRATE]
         .iter()
         .filter_map(symbol_filter)
-        .collect();
-    info!("{} symbols in whitelist", symbol_white_list.len());
+        .collect::<Vec<CString>>();
+    timeline.record("whitelist");
+    info!("{} symbols to preserve in this crate", symbol_white_list.len());
 
-    // For each of our upstream dependencies, find the corresponding rlib and
-    // load the bitcode from the archive. Then merge it into the current LLVM
-    // module that we've got.
+    // If we're performing LTO for the entire crate graph, then for each of our
+    // upstream dependencies, find the corresponding rlib and load the bitcode
+    // from the archive.
+    //
+    // We save off all the bytecode and LLVM module ids for later processing
+    // with either fat or thin LTO
     let mut upstream_modules = Vec::new();
-    for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
-        symbol_white_list.extend(
-            cgcx.exported_symbols[&cnum]
-                .iter()
-                .filter_map(symbol_filter));
-        info!("{} symbols in whitelist after {}", symbol_white_list.len(), cnum);
-
-        let archive = ArchiveRO::open(&path).expect("wanted an rlib");
-        let bytecodes = archive.iter().filter_map(|child| {
-            child.ok().and_then(|c| c.name().map(|name| (name, c)))
-        }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION));
-        for (name, data) in bytecodes {
-            info!("adding bytecode {}", name);
-            let bc_encoded = data.data();
-
-            let (bc, id) = time(cgcx.time_passes, &format!("decode {}", name), || {
-                match DecodedBytecode::new(bc_encoded) {
-                    Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
-                    Err(e) => Err(diag_handler.fatal(&e)),
-                }
-            })?;
-            let bc = SerializedModule::FromRlib(bc);
-            upstream_modules.push((bc, CString::new(id).unwrap()));
+    if let LTOMode::WholeCrateGraph = mode {
+        if cgcx.opts.cg.prefer_dynamic {
+            diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
+                        .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
+                               supported with LTO")
+                        .emit();
+            return Err(FatalError)
+        }
+
+        // Make sure we actually can run LTO
+        for crate_type in cgcx.crate_types.iter() {
+            if !crate_type_allows_lto(*crate_type) {
+                let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \
+                                            static library outputs");
+                return Err(e)
+            }
         }
-    }
 
-    // Internalize everything but the exported symbols of the current module
-    let arr: Vec<*const libc::c_char> = symbol_white_list.iter()
-                                                         .map(|c| c.as_ptr())
-                                                         .collect();
+        for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
+            symbol_white_list.extend(
+                cgcx.exported_symbols[&cnum]
+                    .iter()
+                    .filter_map(symbol_filter));
+
+            let archive = ArchiveRO::open(&path).expect("wanted an rlib");
+            let bytecodes = archive.iter().filter_map(|child| {
+                child.ok().and_then(|c| c.name().map(|name| (name, c)))
+            }).filter(|&(name, _)| name.ends_with(RLIB_BYTECODE_EXTENSION));
+            for (name, data) in bytecodes {
+                info!("adding bytecode {}", name);
+                let bc_encoded = data.data();
+
+                let (bc, id) = time(cgcx.time_passes, &format!("decode {}", name), || {
+                    match DecodedBytecode::new(bc_encoded) {
+                        Ok(b) => Ok((b.bytecode(), b.identifier().to_string())),
+                        Err(e) => Err(diag_handler.fatal(&e)),
+                    }
+                })?;
+                let bc = SerializedModule::FromRlib(bc);
+                upstream_modules.push((bc, CString::new(id).unwrap()));
+            }
+            timeline.record(&format!("load: {}", path.display()));
+        }
+    }
 
-    fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr)
+    let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
+    match mode {
+        LTOMode::WholeCrateGraph if !cgcx.thinlto => {
+            fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
+        }
+        _ => {
+            thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
+        }
+    }
 }
 
 fn fat_lto(cgcx: &CodegenContext,
            diag_handler: &Handler,
            mut modules: Vec<ModuleTranslation>,
            mut serialized_modules: Vec<(SerializedModule, CString)>,
-           symbol_white_list: &[*const libc::c_char])
+           symbol_white_list: &[*const libc::c_char],
+           timeline: &mut Timeline)
     -> Result<Vec<LtoModuleTranslation>, FatalError>
 {
     info!("going for a fat lto");
@@ -228,6 +259,7 @@ fn fat_lto(cgcx: &CodegenContext,
                 Err(write::llvm_err(&diag_handler, msg))
             }
         })?;
+        timeline.record(&format!("link {:?}", name));
         serialized_bitcode.push(bc_decoded);
     }
     cgcx.save_temp_bitcode(&module, "lto.input");
@@ -248,6 +280,7 @@ fn fat_lto(cgcx: &CodegenContext,
         }
         cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
     }
+    timeline.record("passes");
 
     Ok(vec![LtoModuleTranslation::Fat {
         module: Some(module),
@@ -255,11 +288,142 @@ fn fat_lto(cgcx: &CodegenContext,
     }])
 }
 
+/// Prepare "thin" LTO to get run on these modules.
+///
+/// The general structure of ThinLTO is quite different from the structure of
+/// "fat" LTO above. With "fat" LTO all LLVM modules in question are merged into
+/// one giant LLVM module, and then we run more optimization passes over this
+/// big module after internalizing most symbols. Thin LTO, on the other hand,
+/// avoid this large bottleneck through more targeted optimization.
+///
+/// At a high level Thin LTO looks like:
+///
+///     1. Prepare a "summary" of each LLVM module in question which describes
+///        the values inside, cost of the values, etc.
+///     2. Merge the summaries of all modules in question into one "index"
+///     3. Perform some global analysis on this index
+///     4. For each module, use the index and analysis calculated previously to
+///        perform local transformations on the module, for example inlining
+///        small functions from other modules.
+///     5. Run thin-specific optimization passes over each module, and then code
+///        generate everything at the end.
+///
+/// The summary for each module is intended to be quite cheap, and the global
+/// index is relatively quite cheap to create as well. As a result, the goal of
+/// ThinLTO is to reduce the bottleneck on LTO and enable LTO to be used in more
+/// situations. For example one cheap optimization is that we can parallelize
+/// all codegen modules, easily making use of all the cores on a machine.
+///
+/// With all that in mind, the function here is designed at specifically just
+/// calculating the *index* for ThinLTO. This index will then be shared amongst
+/// all of the `LtoModuleTranslation` units returned below and destroyed once
+/// they all go out of scope.
+fn thin_lto(diag_handler: &Handler,
+            modules: Vec<ModuleTranslation>,
+            serialized_modules: Vec<(SerializedModule, CString)>,
+            symbol_white_list: &[*const libc::c_char],
+            timeline: &mut Timeline)
+    -> Result<Vec<LtoModuleTranslation>, FatalError>
+{
+    unsafe {
+        info!("going for that thin, thin LTO");
+
+        let mut thin_buffers = Vec::new();
+        let mut module_names = Vec::new();
+        let mut thin_modules = Vec::new();
+
+        // FIXME: right now, like with fat LTO, we serialize all in-memory
+        //        modules before working with them and ThinLTO. We really
+        //        shouldn't do this, however, and instead figure out how to
+        //        extract a summary from an in-memory module and then merge that
+        //        into the global index. It turns out that this loop is by far
+        //        the most expensive portion of this small bit of global
+        //        analysis!
+        for (i, module) in modules.iter().enumerate() {
+            info!("local module: {} - {}", i, module.llmod_id);
+            let llvm = module.llvm().expect("can't lto pretranslated module");
+            let name = CString::new(module.llmod_id.clone()).unwrap();
+            let buffer = ThinBuffer::new(llvm.llmod);
+            thin_modules.push(llvm::ThinLTOModule {
+                identifier: name.as_ptr(),
+                data: buffer.data().as_ptr(),
+                len: buffer.data().len(),
+            });
+            thin_buffers.push(buffer);
+            module_names.push(name);
+            timeline.record(&module.llmod_id);
+        }
+
+        // FIXME: All upstream crates are deserialized internally in the
+        //        function below to extract their summary and modules. Note that
+        //        unlike the loop above we *must* decode and/or read something
+        //        here as these are all just serialized files on disk. An
+        //        improvement, however, to make here would be to store the
+        //        module summary separately from the actual module itself. Right
+        //        now this is store in one large bitcode file, and the entire
+        //        file is deflate-compressed. We could try to bypass some of the
+        //        decompression by storing the index uncompressed and only
+        //        lazily decompressing the bytecode if necessary.
+        //
+        //        Note that truly taking advantage of this optimization will
+        //        likely be further down the road. We'd have to implement
+        //        incremental ThinLTO first where we could actually avoid
+        //        looking at upstream modules entirely sometimes (the contents,
+        //        we must always unconditionally look at the index).
+        let mut serialized = Vec::new();
+        for (module, name) in serialized_modules {
+            info!("foreign module {:?}", name);
+            thin_modules.push(llvm::ThinLTOModule {
+                identifier: name.as_ptr(),
+                data: module.data().as_ptr(),
+                len: module.data().len(),
+            });
+            serialized.push(module);
+            module_names.push(name);
+        }
+
+        // Delegate to the C++ bindings to create some data here. Once this is a
+        // tried-and-true interface we may wish to try to upstream some of this
+        // to LLVM itself, right now we reimplement a lot of what they do
+        // upstream...
+        let data = llvm::LLVMRustCreateThinLTOData(
+            thin_modules.as_ptr(),
+            thin_modules.len() as u32,
+            symbol_white_list.as_ptr(),
+            symbol_white_list.len() as u32,
+        );
+        if data.is_null() {
+            let msg = format!("failed to prepare thin LTO context");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        let data = ThinData(data);
+        info!("thin LTO data created");
+        timeline.record("data");
+
+        // Throw our data in an `Arc` as we'll be sharing it across threads. We
+        // also put all memory referenced by the C++ data (buffers, ids, etc)
+        // into the arc as well. After this we'll create a thin module
+        // translation per module in this data.
+        let shared = Arc::new(ThinShared {
+            data,
+            thin_buffers,
+            serialized_modules: serialized,
+            module_names,
+        });
+        Ok((0..shared.module_names.len()).map(|i| {
+            LtoModuleTranslation::Thin(ThinModule {
+                shared: shared.clone(),
+                idx: i,
+            })
+        }).collect())
+    }
+}
+
 fn run_pass_manager(cgcx: &CodegenContext,
                     tm: TargetMachineRef,
                     llmod: ModuleRef,
-                    config: &ModuleConfig) {
-
+                    config: &ModuleConfig,
+                    thin: bool) {
     // Now we have one massive module inside of llmod. Time to run the
     // LTO-specific optimization passes that LLVM provides.
     //
@@ -273,10 +437,33 @@ fn run_pass_manager(cgcx: &CodegenContext,
         assert!(!pass.is_null());
         llvm::LLVMRustAddPass(pm, pass);
 
-        with_llvm_pmb(llmod, config, &mut |b| {
-            llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
-                /* Internalize = */ False,
-                /* RunInliner = */ True);
+        // When optimizing for LTO we don't actually pass in `-O0`, but we force
+        // it to always happen at least with `-O1`.
+        //
+        // With ThinLTO we mess around a lot with symbol visibility in a way
+        // that will actually cause linking failures if we optimize at O0 which
+        // notable is lacking in dead code elimination. To ensure we at least
+        // get some optimizations and correctly link we forcibly switch to `-O1`
+        // to get dead code elimination.
+        //
+        // Note that in general this shouldn't matter too much as you typically
+        // only turn on ThinLTO when you're compiling with optimizations
+        // otherwise.
+        let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+        let opt_level = match opt_level {
+            llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
+            level => level,
+        };
+        with_llvm_pmb(llmod, config, opt_level, &mut |b| {
+            if thin {
+                if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
+                    panic!("this version of LLVM does not support ThinLTO");
+                }
+            } else {
+                llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
+                    /* Internalize = */ False,
+                    /* RunInliner = */ True);
+            }
         });
 
         let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
@@ -311,13 +498,13 @@ unsafe impl Send for ModuleBuffer {}
 unsafe impl Sync for ModuleBuffer {}
 
 impl ModuleBuffer {
-    fn new(m: ModuleRef) -> ModuleBuffer {
+    pub fn new(m: ModuleRef) -> ModuleBuffer {
         ModuleBuffer(unsafe {
             llvm::LLVMRustModuleBufferCreate(m)
         })
     }
 
-    fn data(&self) -> &[u8] {
+    pub fn data(&self) -> &[u8] {
         unsafe {
             let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
             let len = llvm::LLVMRustModuleBufferLen(self.0);
@@ -331,3 +518,165 @@ impl Drop for ModuleBuffer {
         unsafe { llvm::LLVMRustModuleBufferFree(self.0); }
     }
 }
+
+pub struct ThinModule {
+    shared: Arc<ThinShared>,
+    idx: usize,
+}
+
+struct ThinShared {
+    data: ThinData,
+    thin_buffers: Vec<ThinBuffer>,
+    serialized_modules: Vec<SerializedModule>,
+    module_names: Vec<CString>,
+}
+
+struct ThinData(*mut llvm::ThinLTOData);
+
+unsafe impl Send for ThinData {}
+unsafe impl Sync for ThinData {}
+
+impl Drop for ThinData {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustFreeThinLTOData(self.0);
+        }
+    }
+}
+
+pub struct ThinBuffer(*mut llvm::ThinLTOBuffer);
+
+unsafe impl Send for ThinBuffer {}
+unsafe impl Sync for ThinBuffer {}
+
+impl ThinBuffer {
+    pub fn new(m: ModuleRef) -> ThinBuffer {
+        unsafe {
+            let buffer = llvm::LLVMRustThinLTOBufferCreate(m);
+            ThinBuffer(buffer)
+        }
+    }
+
+    pub fn data(&self) -> &[u8] {
+        unsafe {
+            let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
+            let len = llvm::LLVMRustThinLTOBufferLen(self.0);
+            slice::from_raw_parts(ptr, len)
+        }
+    }
+}
+
+impl Drop for ThinBuffer {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustThinLTOBufferFree(self.0);
+        }
+    }
+}
+
+impl ThinModule {
+    fn name(&self) -> &str {
+        self.shared.module_names[self.idx].to_str().unwrap()
+    }
+
+    fn cost(&self) -> u64 {
+        // Yes, that's correct, we're using the size of the bytecode as an
+        // indicator for how costly this codegen unit is.
+        self.data().len() as u64
+    }
+
+    fn data(&self) -> &[u8] {
+        let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
+        a.unwrap_or_else(|| {
+            let len = self.shared.thin_buffers.len();
+            self.shared.serialized_modules[self.idx - len].data()
+        })
+    }
+
+    unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline)
+        -> Result<ModuleTranslation, FatalError>
+    {
+        let diag_handler = cgcx.create_diag_handler();
+        let tm = (cgcx.tm_factory)().map_err(|e| {
+            write::llvm_err(&diag_handler, e)
+        })?;
+
+        // Right now the implementation we've got only works over serialized
+        // modules, so we create a fresh new LLVM context and parse the module
+        // into that context. One day, however, we may do this for upstream
+        // crates but for locally translated modules we may be able to reuse
+        // that LLVM Context and Module.
+        let llcx = llvm::LLVMContextCreate();
+        let llmod = llvm::LLVMRustParseBitcodeForThinLTO(
+            llcx,
+            self.data().as_ptr(),
+            self.data().len(),
+            self.shared.module_names[self.idx].as_ptr(),
+        );
+        assert!(!llmod.is_null());
+        let mtrans = ModuleTranslation {
+            source: ModuleSource::Translated(ModuleLlvm {
+                llmod,
+                llcx,
+                tm,
+            }),
+            llmod_id: self.name().to_string(),
+            name: self.name().to_string(),
+            kind: ModuleKind::Regular,
+        };
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-input");
+
+        // Like with "fat" LTO, get some better optimizations if landing pads
+        // are disabled by removing all landing pads.
+        if cgcx.no_landing_pads {
+            llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
+            cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-nounwind");
+            timeline.record("nounwind");
+        }
+
+        // Up next comes the per-module local analyses that we do for Thin LTO.
+        // Each of these functions is basically copied from the LLVM
+        // implementation and then tailored to suit this implementation. Ideally
+        // each of these would be supported by upstream LLVM but that's perhaps
+        // a patch for another day!
+        //
+        // You can find some more comments about these functions in the LLVM
+        // bindings we've got (currently `PassWrapper.cpp`)
+        if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rename");
+        timeline.record("rename");
+        if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-resolve");
+        timeline.record("resolve");
+        if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-internalize");
+        timeline.record("internalize");
+        if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
+            let msg = format!("failed to prepare thin LTO module");
+            return Err(write::llvm_err(&diag_handler, msg))
+        }
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-import");
+        timeline.record("import");
+
+        // Alright now that we've done everything related to the ThinLTO
+        // analysis it's time to run some optimizations! Here we use the same
+        // `run_pass_manager` as the "fat" LTO above except that we tell it to
+        // populate a thin-specific pass manager, which presumably LLVM treats a
+        // little differently.
+        info!("running thin lto passes over {}", mtrans.name);
+        let config = cgcx.config(mtrans.kind);
+        run_pass_manager(cgcx, tm, llmod, config, true);
+        cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-pm");
+        timeline.record("thin-done");
+        Ok(mtrans)
+    }
+}
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index 306071223fc..0ebfe4daad1 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -98,8 +98,10 @@
 //! DefPaths which are much more robust in the face of changes to the code base.
 
 use monomorphize::Instance;
+use trans_item::{BaseTransItemExt, InstantiationMode};
 
 use rustc::middle::weak_lang_items;
+use rustc::middle::trans::TransItem;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -150,7 +152,10 @@ pub fn provide(providers: &mut Providers) {
 fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                              // the DefId of the item this name is for
-                             def_id: Option<DefId>,
+                             def_id: DefId,
+
+                             // instance this name will be for
+                             instance: Instance<'tcx>,
 
                              // type of the item, without any generic
                              // parameters substituted; this is
@@ -160,7 +165,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                              // values for generic type parameters,
                              // if any.
-                             substs: Option<&'tcx Substs<'tcx>>)
+                             substs: &'tcx Substs<'tcx>)
                              -> u64 {
     debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
 
@@ -170,7 +175,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // the main symbol name is not necessarily unique; hash in the
         // compiler's internal def-path, guaranteeing each symbol has a
         // truly unique path
-        hasher.hash(def_id.map(|def_id| tcx.def_path_hash(def_id)));
+        hasher.hash(tcx.def_path_hash(def_id));
 
         // Include the main item-type. Note that, in this case, the
         // assertions about `needs_subst` may not hold, but this item-type
@@ -186,19 +191,36 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         // also include any type parameters (for generic items)
-        if let Some(substs) = substs {
-            assert!(!substs.has_erasable_regions());
-            assert!(!substs.needs_subst());
-            substs.visit_with(&mut hasher);
-
-            // If this is an instance of a generic function, we also hash in
-            // the ID of the instantiating crate. This avoids symbol conflicts
-            // in case the same instances is emitted in two crates of the same
-            // project.
-            if substs.types().next().is_some() {
-                hasher.hash(tcx.crate_name.as_str());
-                hasher.hash(tcx.sess.local_crate_disambiguator().as_str());
+        assert!(!substs.has_erasable_regions());
+        assert!(!substs.needs_subst());
+        substs.visit_with(&mut hasher);
+
+        let mut avoid_cross_crate_conflicts = false;
+
+        // If this is an instance of a generic function, we also hash in
+        // the ID of the instantiating crate. This avoids symbol conflicts
+        // in case the same instances is emitted in two crates of the same
+        // project.
+        if substs.types().next().is_some() {
+            avoid_cross_crate_conflicts = true;
+        }
+
+        // If we're dealing with an instance of a function that's inlined from
+        // another crate but we're marking it as globally shared to our
+        // compliation (aka we're not making an internal copy in each of our
+        // codegen units) then this symbol may become an exported (but hidden
+        // visibility) symbol. This means that multiple crates may do the same
+        // and we want to be sure to avoid any symbol conflicts here.
+        match TransItem::Fn(instance).instantiation_mode(tcx) {
+            InstantiationMode::GloballyShared { may_conflict: true } => {
+                avoid_cross_crate_conflicts = true;
             }
+            _ => {}
+        }
+
+        if avoid_cross_crate_conflicts {
+            hasher.hash(tcx.crate_name.as_str());
+            hasher.hash(tcx.sess.local_crate_disambiguator().as_str());
         }
     });
 
@@ -309,7 +331,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
     // and should not matter anyhow.
     let instance_ty = tcx.erase_regions(&instance_ty);
 
-    let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs));
+    let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
 
     SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
 }
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 1988b9f76e4..5550ab9fa55 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -8,18 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use back::lto;
+use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
+use back::lto::{self, ModuleBuffer, ThinBuffer};
 use back::link::{self, get_linker, remove};
 use back::linker::LinkerInfo;
 use back::symbol_export::ExportedSymbols;
+use base;
+use consts;
 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
-use rustc::dep_graph::DepGraph;
+use rustc::dep_graph::{DepGraph, WorkProductFileKind};
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
                              AllPasses, Sanitizer};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
-use time_graph::{self, TimeGraph};
+use time_graph::{self, TimeGraph, Timeline};
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
 use llvm::{SMDiagnosticRef, ContextRef};
@@ -35,13 +38,14 @@ use syntax::attr;
 use syntax::ext::hygiene::Mark;
 use syntax_pos::MultiSpan;
 use syntax_pos::symbol::Symbol;
+use type_::Type;
 use context::{is_pie_binary, get_reloc_model};
 use jobserver::{Client, Acquired};
 use rustc_demangle;
 
 use std::any::Any;
-use std::ffi::CString;
-use std::fs;
+use std::ffi::{CString, CStr};
+use std::fs::{self, File};
 use std::io;
 use std::io::Write;
 use std::mem;
@@ -217,7 +221,7 @@ pub struct ModuleConfig {
     passes: Vec<String>,
     /// Some(level) to optimize at a certain level, or None to run
     /// absolutely no optimizations (used for the metadata module).
-    opt_level: Option<llvm::CodeGenOptLevel>,
+    pub opt_level: Option<llvm::CodeGenOptLevel>,
 
     /// Some(level) to optimize binary size, or None to not affect program size.
     opt_size: Option<llvm::CodeGenOptSize>,
@@ -225,6 +229,7 @@ pub struct ModuleConfig {
     // Flags indicating which outputs to produce.
     emit_no_opt_bc: bool,
     emit_bc: bool,
+    emit_bc_compressed: bool,
     emit_lto_bc: bool,
     emit_ir: bool,
     emit_asm: bool,
@@ -254,6 +259,7 @@ impl ModuleConfig {
 
             emit_no_opt_bc: false,
             emit_bc: false,
+            emit_bc_compressed: false,
             emit_lto_bc: false,
             emit_ir: false,
             emit_asm: false,
@@ -303,6 +309,7 @@ pub struct CodegenContext {
     // Resouces needed when running LTO
     pub time_passes: bool,
     pub lto: bool,
+    pub thinlto: bool,
     pub no_landing_pads: bool,
     pub save_temps: bool,
     pub exported_symbols: Arc<ExportedSymbols>,
@@ -314,7 +321,11 @@ pub struct CodegenContext {
     metadata_module_config: Arc<ModuleConfig>,
     allocator_module_config: Arc<ModuleConfig>,
     pub tm_factory: Arc<Fn() -> Result<TargetMachineRef, String> + Send + Sync>,
+    pub msvc_imps_needed: bool,
+    pub target_pointer_width: String,
 
+    // Number of cgus excluding the allocator/metadata modules
+    pub total_cgus: usize,
     // Handler to use for diagnostics produced during codegen.
     pub diag_emitter: SharedEmitter,
     // LLVM passes added by plugins.
@@ -450,7 +461,8 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
 unsafe fn optimize(cgcx: &CodegenContext,
                    diag_handler: &Handler,
                    mtrans: &ModuleTranslation,
-                   config: &ModuleConfig)
+                   config: &ModuleConfig,
+                   timeline: &mut Timeline)
     -> Result<(), FatalError>
 {
     let (llmod, llcx, tm) = match mtrans.source {
@@ -503,7 +515,8 @@ unsafe fn optimize(cgcx: &CodegenContext,
         if !config.no_prepopulate_passes {
             llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
             llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
-            with_llvm_pmb(llmod, &config, &mut |b| {
+            let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+            with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
                 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
                 llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
             })
@@ -529,6 +542,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
         // Finally, run the actual optimization passes
         time(config.time_passes, &format!("llvm function passes [{}]", module_name.unwrap()), ||
              llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
+        timeline.record("fpm");
         time(config.time_passes, &format!("llvm module passes [{}]", module_name.unwrap()), ||
              llvm::LLVMRunPassManager(mpm, llmod));
 
@@ -543,7 +557,18 @@ fn generate_lto_work(cgcx: &CodegenContext,
                      modules: Vec<ModuleTranslation>)
     -> Vec<(WorkItem, u64)>
 {
-    let lto_modules = lto::run(cgcx, modules).unwrap_or_else(|e| panic!(e));
+    let mut timeline = cgcx.time_graph.as_ref().map(|tg| {
+        tg.start(TRANS_WORKER_TIMELINE,
+                 TRANS_WORK_PACKAGE_KIND,
+                 "generate lto")
+    }).unwrap_or(Timeline::noop());
+    let mode = if cgcx.lto {
+        lto::LTOMode::WholeCrateGraph
+    } else {
+        lto::LTOMode::JustThisCrate
+    };
+    let lto_modules = lto::run(cgcx, modules, mode, &mut timeline)
+        .unwrap_or_else(|e| panic!(e));
 
     lto_modules.into_iter().map(|module| {
         let cost = module.cost();
@@ -554,9 +579,11 @@ fn generate_lto_work(cgcx: &CodegenContext,
 unsafe fn codegen(cgcx: &CodegenContext,
                   diag_handler: &Handler,
                   mtrans: ModuleTranslation,
-                  config: &ModuleConfig)
+                  config: &ModuleConfig,
+                  timeline: &mut Timeline)
     -> Result<CompiledModule, FatalError>
 {
+    timeline.record("codegen");
     let (llmod, llcx, tm) = match mtrans.source {
         ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm),
         ModuleSource::Preexisting(_) => {
@@ -567,6 +594,10 @@ unsafe fn codegen(cgcx: &CodegenContext,
     let module_name = Some(&module_name[..]);
     let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
 
+    if cgcx.msvc_imps_needed {
+        create_msvc_imps(cgcx, llcx, llmod);
+    }
+
     // A codegen-specific pass manager is used to generate object
     // files for an LLVM module.
     //
@@ -599,9 +630,34 @@ unsafe fn codegen(cgcx: &CodegenContext,
     let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
     let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
 
-    if write_bc {
-        let bc_out_c = path2cstr(&bc_out);
-        llvm::LLVMWriteBitcodeToFile(llmod, bc_out_c.as_ptr());
+
+    if write_bc || config.emit_bc_compressed {
+        let thin;
+        let old;
+        let data = if llvm::LLVMRustThinLTOAvailable() {
+            thin = ThinBuffer::new(llmod);
+            thin.data()
+        } else {
+            old = ModuleBuffer::new(llmod);
+            old.data()
+        };
+        timeline.record("make-bc");
+
+        if write_bc {
+            if let Err(e) = File::create(&bc_out).and_then(|mut f| f.write_all(data)) {
+                diag_handler.err(&format!("failed to write bytecode: {}", e));
+            }
+            timeline.record("write-bc");
+        }
+
+        if config.emit_bc_compressed {
+            let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
+            let data = bytecode::encode(&mtrans.llmod_id, data);
+            if let Err(e) = File::create(&dst).and_then(|mut f| f.write_all(&data)) {
+                diag_handler.err(&format!("failed to write bytecode: {}", e));
+            }
+            timeline.record("compress-bc");
+        }
     }
 
     time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
@@ -644,7 +700,8 @@ unsafe fn codegen(cgcx: &CodegenContext,
             with_codegen(tm, llmod, config.no_builtins, |cpm| {
                 llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
                 llvm::LLVMDisposePassManager(cpm);
-            })
+            });
+            timeline.record("ir");
         }
 
         if config.emit_asm {
@@ -665,6 +722,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
             if config.emit_obj {
                 llvm::LLVMDisposeModule(llmod);
             }
+            timeline.record("asm");
         }
 
         if write_obj {
@@ -672,6 +730,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
                 write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
                                   llvm::FileType::ObjectFile)
             })?;
+            timeline.record("obj");
         }
 
         Ok(())
@@ -694,6 +753,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
     drop(handlers);
     Ok(mtrans.into_compiled_module(config.emit_obj,
                                    config.emit_bc,
+                                   config.emit_bc_compressed,
                                    &cgcx.output_filenames))
 }
 
@@ -712,7 +772,8 @@ pub fn start_async_translation(tcx: TyCtxt,
                                time_graph: Option<TimeGraph>,
                                link: LinkMeta,
                                metadata: EncodedMetadata,
-                               coordinator_receive: Receiver<Box<Any + Send>>)
+                               coordinator_receive: Receiver<Box<Any + Send>>,
+                               total_cgus: usize)
                                -> OngoingCrateTranslation {
     let sess = tcx.sess;
     let crate_output = tcx.output_filenames(LOCAL_CRATE);
@@ -779,11 +840,12 @@ pub fn start_async_translation(tcx: TyCtxt,
         allocator_config.emit_bc = true;
     }
 
-    // Emit bitcode files for the crate if we're emitting an rlib.
-    // Whenever an rlib is created, the bitcode is inserted into the
-    // archive in order to allow LTO against it.
+    // Emit compressed bitcode files for the crate if we're emitting an rlib.
+    // Whenever an rlib is created, the bitcode is inserted into the archive in
+    // order to allow LTO against it.
     if need_crate_bitcode_for_rlib(sess) {
-        modules_config.emit_bc = true;
+        modules_config.emit_bc_compressed = true;
+        allocator_config.emit_bc_compressed = true;
     }
 
     for output_type in output_types_override.keys() {
@@ -836,6 +898,7 @@ pub fn start_async_translation(tcx: TyCtxt,
                                                   shared_emitter,
                                                   trans_worker_send,
                                                   coordinator_receive,
+                                                  total_cgus,
                                                   client,
                                                   time_graph.clone(),
                                                   Arc::new(modules_config),
@@ -862,8 +925,7 @@ pub fn start_async_translation(tcx: TyCtxt,
 
 fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
                                               dep_graph: &DepGraph,
-                                              compiled_modules: &CompiledModules,
-                                              crate_output: &OutputFilenames) {
+                                              compiled_modules: &CompiledModules) {
     if sess.opts.incremental.is_none() {
         return;
     }
@@ -871,20 +933,17 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
     for module in compiled_modules.modules.iter() {
         let mut files = vec![];
 
-        if module.emit_obj {
-            let path = crate_output.temp_path(OutputType::Object, Some(&module.name));
-            files.push((OutputType::Object, path));
+        if let Some(ref path) = module.object {
+            files.push((WorkProductFileKind::Object, path.clone()));
         }
-
-        if module.emit_bc {
-            let path = crate_output.temp_path(OutputType::Bitcode, Some(&module.name));
-            files.push((OutputType::Bitcode, path));
+        if let Some(ref path) = module.bytecode {
+            files.push((WorkProductFileKind::Bytecode, path.clone()));
+        }
+        if let Some(ref path) = module.bytecode_compressed {
+            files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
         }
 
-        save_trans_partition(sess,
-                             dep_graph,
-                             &module.name,
-                             &files);
+        save_trans_partition(sess, dep_graph, &module.name, &files);
     }
 }
 
@@ -988,8 +1047,6 @@ fn produce_final_output_artifacts(sess: &Session,
         // well.
 
         // Specific rules for keeping .#module-name#.bc:
-        //  - If we're building an rlib (`needs_crate_bitcode`), then keep
-        //    it.
         //  - If the user requested bitcode (`user_wants_bitcode`), and
         //    codegen_units > 1, then keep it.
         //  - If the user requested bitcode but codegen_units == 1, then we
@@ -999,41 +1056,37 @@ fn produce_final_output_artifacts(sess: &Session,
         // If you change how this works, also update back::link::link_rlib,
         // where .#module-name#.bc files are (maybe) deleted after making an
         // rlib.
-        let needs_crate_bitcode = need_crate_bitcode_for_rlib(sess);
         let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe);
 
-        let keep_numbered_bitcode = needs_crate_bitcode ||
-                (user_wants_bitcode && sess.opts.codegen_units > 1);
+        let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units() > 1;
 
         let keep_numbered_objects = needs_crate_object ||
-                (user_wants_objects && sess.opts.codegen_units > 1);
+                (user_wants_objects && sess.codegen_units() > 1);
 
         for module in compiled_modules.modules.iter() {
-            let module_name = Some(&module.name[..]);
-
-            if module.emit_obj && !keep_numbered_objects {
-                let path = crate_output.temp_path(OutputType::Object, module_name);
-                remove(sess, &path);
+            if let Some(ref path) = module.object {
+                if !keep_numbered_objects {
+                    remove(sess, path);
+                }
             }
 
-            if module.emit_bc && !keep_numbered_bitcode {
-                let path = crate_output.temp_path(OutputType::Bitcode, module_name);
-                remove(sess, &path);
+            if let Some(ref path) = module.bytecode {
+                if !keep_numbered_bitcode {
+                    remove(sess, path);
+                }
             }
         }
 
-        if compiled_modules.metadata_module.emit_bc && !user_wants_bitcode {
-            let path = crate_output.temp_path(OutputType::Bitcode,
-                                              Some(&compiled_modules.metadata_module.name));
-            remove(sess, &path);
-        }
-
-        if let Some(ref allocator_module) = compiled_modules.allocator_module {
-            if allocator_module.emit_bc && !user_wants_bitcode {
-                let path = crate_output.temp_path(OutputType::Bitcode,
-                                                  Some(&allocator_module.name));
+        if !user_wants_bitcode {
+            if let Some(ref path) = compiled_modules.metadata_module.bytecode {
                 remove(sess, &path);
             }
+
+            if let Some(ref allocator_module) = compiled_modules.allocator_module {
+                if let Some(ref path) = allocator_module.bytecode {
+                    remove(sess, path);
+                }
+            }
         }
     }
 
@@ -1045,13 +1098,9 @@ fn produce_final_output_artifacts(sess: &Session,
 }
 
 pub fn dump_incremental_data(trans: &CrateTranslation) {
-    let mut reuse = 0;
-    for mtrans in trans.modules.iter() {
-        if mtrans.pre_existing {
-            reuse += 1;
-        }
-    }
-    eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len());
+    println!("[incremental] Re-using {} out of {} modules",
+              trans.modules.iter().filter(|m| m.pre_existing).count(),
+              trans.modules.len());
 }
 
 enum WorkItem {
@@ -1080,7 +1129,9 @@ enum WorkItemResult {
     NeedsLTO(ModuleTranslation),
 }
 
-fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
+fn execute_work_item(cgcx: &CodegenContext,
+                     work_item: WorkItem,
+                     timeline: &mut Timeline)
     -> Result<WorkItemResult, FatalError>
 {
     let diag_handler = cgcx.create_diag_handler();
@@ -1089,8 +1140,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
         WorkItem::Optimize(mtrans) => mtrans,
         WorkItem::LTO(mut lto) => {
             unsafe {
-                let module = lto.optimize(cgcx)?;
-                let module = codegen(cgcx, &diag_handler, module, config)?;
+                let module = lto.optimize(cgcx, timeline)?;
+                let module = codegen(cgcx, &diag_handler, module, config, timeline)?;
                 return Ok(WorkItemResult::Compiled(module))
             }
         }
@@ -1107,8 +1158,28 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
                                         .as_ref()
                                         .unwrap();
         let name = &mtrans.name;
+        let mut object = None;
+        let mut bytecode = None;
+        let mut bytecode_compressed = None;
         for (kind, saved_file) in wp.saved_files {
-            let obj_out = cgcx.output_filenames.temp_path(kind, Some(name));
+            let obj_out = match kind {
+                WorkProductFileKind::Object => {
+                    let path = cgcx.output_filenames.temp_path(OutputType::Object, Some(name));
+                    object = Some(path.clone());
+                    path
+                }
+                WorkProductFileKind::Bytecode => {
+                    let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name));
+                    bytecode = Some(path.clone());
+                    path
+                }
+                WorkProductFileKind::BytecodeCompressed => {
+                    let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(name))
+                        .with_extension(RLIB_BYTECODE_EXTENSION);
+                    bytecode_compressed = Some(path.clone());
+                    path
+                }
+            };
             let source_file = in_incr_comp_dir(&incr_comp_session_dir,
                                                &saved_file);
             debug!("copying pre-existing module `{}` from {:?} to {}",
@@ -1125,24 +1196,44 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
                 }
             }
         }
-        let object = cgcx.output_filenames.temp_path(OutputType::Object, Some(name));
+        assert_eq!(object.is_some(), config.emit_obj);
+        assert_eq!(bytecode.is_some(), config.emit_bc);
+        assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed);
 
         Ok(WorkItemResult::Compiled(CompiledModule {
-            object,
             llmod_id: mtrans.llmod_id.clone(),
             name: module_name,
             kind: ModuleKind::Regular,
             pre_existing: true,
-            emit_bc: config.emit_bc,
-            emit_obj: config.emit_obj,
+            object,
+            bytecode,
+            bytecode_compressed,
         }))
     } else {
         debug!("llvm-optimizing {:?}", module_name);
 
         unsafe {
-            optimize(cgcx, &diag_handler, &mtrans, config)?;
-            if !cgcx.lto || mtrans.kind == ModuleKind::Metadata {
-                let module = codegen(cgcx, &diag_handler, mtrans, config)?;
+            optimize(cgcx, &diag_handler, &mtrans, config, timeline)?;
+
+            let lto = cgcx.lto;
+
+            let auto_thin_lto =
+                cgcx.thinlto &&
+                cgcx.total_cgus > 1 &&
+                mtrans.kind != ModuleKind::Allocator;
+
+            // If we're a metadata module we never participate in LTO.
+            //
+            // If LTO was explicitly requested on the command line, we always
+            // LTO everything else.
+            //
+            // If LTO *wasn't* explicitly requested and we're not a metdata
+            // module, then we may automatically do ThinLTO if we've got
+            // multiple codegen units. Note, however, that the allocator module
+            // doesn't participate here automatically because of linker
+            // shenanigans later on.
+            if mtrans.kind == ModuleKind::Metadata || (!lto && !auto_thin_lto) {
+                let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?;
                 Ok(WorkItemResult::Compiled(module))
             } else {
                 Ok(WorkItemResult::NeedsLTO(mtrans))
@@ -1187,12 +1278,13 @@ fn start_executing_work(tcx: TyCtxt,
                         shared_emitter: SharedEmitter,
                         trans_worker_send: Sender<Message>,
                         coordinator_receive: Receiver<Box<Any + Send>>,
+                        total_cgus: usize,
                         jobserver: Client,
                         time_graph: Option<TimeGraph>,
                         modules_config: Arc<ModuleConfig>,
                         metadata_config: Arc<ModuleConfig>,
                         allocator_config: Arc<ModuleConfig>)
-                        -> thread::JoinHandle<CompiledModules> {
+                        -> thread::JoinHandle<Result<CompiledModules, ()>> {
     let coordinator_send = tcx.tx_to_llvm_workers.clone();
     let mut exported_symbols = FxHashMap();
     exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
@@ -1229,6 +1321,7 @@ fn start_executing_work(tcx: TyCtxt,
         crate_types: sess.crate_types.borrow().clone(),
         each_linked_rlib_for_lto,
         lto: sess.lto(),
+        thinlto: sess.opts.debugging_opts.thinlto,
         no_landing_pads: sess.no_landing_pads(),
         save_temps: sess.opts.cg.save_temps,
         opts: Arc::new(sess.opts.clone()),
@@ -1246,6 +1339,9 @@ fn start_executing_work(tcx: TyCtxt,
         metadata_module_config: metadata_config,
         allocator_module_config: allocator_config,
         tm_factory: target_machine_factory(tcx.sess),
+        total_cgus,
+        msvc_imps_needed: msvc_imps_needed(tcx),
+        target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
@@ -1638,7 +1734,7 @@ fn start_executing_work(tcx: TyCtxt,
                 Message::Done { result: Err(()), worker_id: _ } => {
                     shared_emitter.fatal("aborting due to worker thread failure");
                     // Exit the coordinator thread
-                    panic!("aborting due to worker thread failure")
+                    return Err(())
                 }
                 Message::TranslateItem => {
                     bug!("the coordinator should not receive translation requests")
@@ -1664,11 +1760,11 @@ fn start_executing_work(tcx: TyCtxt,
         let compiled_metadata_module = compiled_metadata_module
             .expect("Metadata module not compiled?");
 
-        CompiledModules {
+        Ok(CompiledModules {
             modules: compiled_modules,
             metadata_module: compiled_metadata_module,
             allocator_module: compiled_allocator_module,
-        }
+        })
     });
 
     // A heuristic that determines if we have enough LLVM WorkItems in the
@@ -1743,12 +1839,13 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
         // as a diagnostic was already sent off to the main thread - just
         // surface that there was an error in this worker.
         bomb.result = {
-            let _timing_guard = cgcx.time_graph.as_ref().map(|tg| {
+            let timeline = cgcx.time_graph.as_ref().map(|tg| {
                 tg.start(time_graph::TimelineId(cgcx.worker),
                          LLVM_WORK_PACKAGE_KIND,
                          &work.name())
             });
-            execute_work_item(&cgcx, work).ok()
+            let mut timeline = timeline.unwrap_or(Timeline::noop());
+            execute_work_item(&cgcx, work, &mut timeline).ok()
         };
     });
 }
@@ -1788,16 +1885,17 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
 
 pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
                             config: &ModuleConfig,
+                            opt_level: llvm::CodeGenOptLevel,
                             f: &mut FnMut(llvm::PassManagerBuilderRef)) {
     // Create the PassManagerBuilder for LLVM. We configure it with
     // reasonable defaults and prepare it to actually populate the pass
     // manager.
     let builder = llvm::LLVMPassManagerBuilderCreate();
-    let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
     let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
     let inline_threshold = config.inline_threshold;
 
-    llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level,
+    llvm::LLVMRustConfigurePassManagerBuilder(builder,
+                                              opt_level,
                                               config.merge_functions,
                                               config.vectorize_slp,
                                               config.vectorize_loop);
@@ -1960,7 +2058,7 @@ pub struct OngoingCrateTranslation {
     coordinator_send: Sender<Box<Any + Send>>,
     trans_worker_receive: Receiver<Message>,
     shared_emitter_main: SharedEmitterMain,
-    future: thread::JoinHandle<CompiledModules>,
+    future: thread::JoinHandle<Result<CompiledModules, ()>>,
     output_filenames: Arc<OutputFilenames>,
 }
 
@@ -1968,7 +2066,11 @@ impl OngoingCrateTranslation {
     pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = match self.future.join() {
-            Ok(compiled_modules) => compiled_modules,
+            Ok(Ok(compiled_modules)) => compiled_modules,
+            Ok(Err(())) => {
+                sess.abort_if_errors();
+                panic!("expected abort due to worker thread errors")
+            },
             Err(_) => {
                 sess.fatal("Error during translation/LLVM phase.");
             }
@@ -1982,15 +2084,14 @@ impl OngoingCrateTranslation {
 
         copy_module_artifacts_into_incr_comp_cache(sess,
                                                    dep_graph,
-                                                   &compiled_modules,
-                                                   &self.output_filenames);
+                                                   &compiled_modules);
         produce_final_output_artifacts(sess,
                                        &compiled_modules,
                                        &self.output_filenames);
 
         // FIXME: time_llvm_passes support - does this use a global context or
         // something?
-        if sess.opts.codegen_units == 1 && sess.time_llvm_passes() {
+        if sess.codegen_units() == 1 && sess.time_llvm_passes() {
             unsafe { llvm::LLVMRustPrintPassTimings(); }
         }
 
@@ -2004,6 +2105,7 @@ impl OngoingCrateTranslation {
 
             modules: compiled_modules.modules,
             allocator_module: compiled_modules.allocator_module,
+            metadata_module: compiled_modules.metadata_module,
         };
 
         if self.no_integrated_as {
@@ -2073,3 +2175,51 @@ pub fn submit_translated_module_to_llvm(tcx: TyCtxt,
         cost,
     })));
 }
+
+fn msvc_imps_needed(tcx: TyCtxt) -> bool {
+    tcx.sess.target.target.options.is_like_msvc &&
+        tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib)
+}
+
+// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
+// This is required to satisfy `dllimport` references to static data in .rlibs
+// when using MSVC linker.  We do this only for data, as linker can fix up
+// code references on its own.
+// See #26591, #27438
+fn create_msvc_imps(cgcx: &CodegenContext, llcx: ContextRef, llmod: ModuleRef) {
+    if !cgcx.msvc_imps_needed {
+        return
+    }
+    // The x86 ABI seems to require that leading underscores are added to symbol
+    // names, so we need an extra underscore on 32-bit. There's also a leading
+    // '\x01' here which disables LLVM's symbol mangling (e.g. no extra
+    // underscores added in front).
+    let prefix = if cgcx.target_pointer_width == "32" {
+        "\x01__imp__"
+    } else {
+        "\x01__imp_"
+    };
+    unsafe {
+        let i8p_ty = Type::i8p_llcx(llcx);
+        let globals = base::iter_globals(llmod)
+            .filter(|&val| {
+                llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage &&
+                    llvm::LLVMIsDeclaration(val) == 0
+            })
+            .map(move |val| {
+                let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
+                let mut imp_name = prefix.as_bytes().to_vec();
+                imp_name.extend(name.to_bytes());
+                let imp_name = CString::new(imp_name).unwrap();
+                (imp_name, val)
+            })
+            .collect::<Vec<_>>();
+        for (imp_name, val) in globals {
+            let imp = llvm::LLVMAddGlobal(llmod,
+                                          i8p_ty.to_ref(),
+                                          imp_name.as_ptr() as *const _);
+            llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
+            llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
+        }
+    }
+}
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 8c39f579b3e..547b1f7b2bf 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -70,7 +70,7 @@ use monomorphize::{self, Instance};
 use partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
 use symbol_names_test;
 use time_graph;
-use trans_item::{TransItem, TransItemExt, DefPathBasedNames};
+use trans_item::{TransItem, BaseTransItemExt, TransItemExt, DefPathBasedNames};
 use type_::Type;
 use type_of;
 use value::Value;
@@ -78,7 +78,7 @@ use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet};
 use CrateInfo;
 
 use std::any::Any;
-use std::ffi::{CStr, CString};
+use std::ffi::CString;
 use std::str;
 use std::sync::Arc;
 use std::time::{Instant, Duration};
@@ -93,6 +93,7 @@ use syntax::ast;
 use mir::lvalue::Alignment;
 
 pub use rustc_trans_utils::{find_exported_symbols, check_for_rustc_errors_attr};
+pub use rustc_trans_utils::trans_item::linkage_by_name;
 
 pub struct StatRecorder<'a, 'tcx: 'a> {
     ccx: &'a CrateContext<'a, 'tcx>,
@@ -618,33 +619,6 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     mir::trans_mir(ccx, lldecl, &mir, instance, sig);
 }
 
-pub fn linkage_by_name(name: &str) -> Option<Linkage> {
-    use rustc::middle::trans::Linkage::*;
-
-    // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
-    // applicable to variable declarations and may not really make sense for
-    // Rust code in the first place but whitelist them anyway and trust that
-    // the user knows what s/he's doing. Who knows, unanticipated use cases
-    // may pop up in the future.
-    //
-    // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
-    // and don't have to be, LLVM treats them as no-ops.
-    match name {
-        "appending" => Some(Appending),
-        "available_externally" => Some(AvailableExternally),
-        "common" => Some(Common),
-        "extern_weak" => Some(ExternalWeak),
-        "external" => Some(External),
-        "internal" => Some(Internal),
-        "linkonce" => Some(LinkOnceAny),
-        "linkonce_odr" => Some(LinkOnceODR),
-        "private" => Some(Private),
-        "weak" => Some(WeakAny),
-        "weak_odr" => Some(WeakODR),
-        _ => None,
-    }
-}
-
 pub fn set_link_section(ccx: &CrateContext,
                         llval: ValueRef,
                         attrs: &[ast::Attribute]) {
@@ -812,47 +786,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
     return (metadata_llcx, metadata_llmod, metadata, hashes);
 }
 
-// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
-// This is required to satisfy `dllimport` references to static data in .rlibs
-// when using MSVC linker.  We do this only for data, as linker can fix up
-// code references on its own.
-// See #26591, #27438
-fn create_imps(sess: &Session,
-               llvm_module: &ModuleLlvm) {
-    // The x86 ABI seems to require that leading underscores are added to symbol
-    // names, so we need an extra underscore on 32-bit. There's also a leading
-    // '\x01' here which disables LLVM's symbol mangling (e.g. no extra
-    // underscores added in front).
-    let prefix = if sess.target.target.target_pointer_width == "32" {
-        "\x01__imp__"
-    } else {
-        "\x01__imp_"
-    };
-    unsafe {
-        let exported: Vec<_> = iter_globals(llvm_module.llmod)
-                                   .filter(|&val| {
-                                       llvm::LLVMRustGetLinkage(val) ==
-                                       llvm::Linkage::ExternalLinkage &&
-                                       llvm::LLVMIsDeclaration(val) == 0
-                                   })
-                                   .collect();
-
-        let i8p_ty = Type::i8p_llcx(llvm_module.llcx);
-        for val in exported {
-            let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
-            let mut imp_name = prefix.as_bytes().to_vec();
-            imp_name.extend(name.to_bytes());
-            let imp_name = CString::new(imp_name).unwrap();
-            let imp = llvm::LLVMAddGlobal(llvm_module.llmod,
-                                          i8p_ty.to_ref(),
-                                          imp_name.as_ptr() as *const _);
-            llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
-            llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
-        }
-    }
-}
-
-struct ValueIter {
+pub struct ValueIter {
     cur: ValueRef,
     step: unsafe extern "C" fn(ValueRef) -> ValueRef,
 }
@@ -871,7 +805,7 @@ impl Iterator for ValueIter {
     }
 }
 
-fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
+pub fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
     unsafe {
         ValueIter {
             cur: llvm::LLVMGetFirstGlobal(llmod),
@@ -886,6 +820,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     check_for_rustc_errors_attr(tcx);
 
+    if tcx.sess.opts.debugging_opts.thinlto {
+        if unsafe { !llvm::LLVMRustThinLTOAvailable() } {
+            tcx.sess.fatal("this compiler's LLVM does not support ThinLTO");
+        }
+    }
 
     let crate_hash = tcx.dep_graph
                         .fingerprint_of(&DepNode::new_no_params(DepKind::Krate));
@@ -925,7 +864,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             time_graph.clone(),
             link_meta,
             metadata,
-            rx);
+            rx,
+            1);
 
         ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
         ongoing_translation.translation_finished(tcx);
@@ -961,7 +901,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         time_graph.clone(),
         link_meta,
         metadata,
-        rx);
+        rx,
+        codegen_units.len());
 
     // Translate an allocator shim, if any
     let allocator_module = if let Some(kind) = tcx.sess.allocator_kind.get() {
@@ -1211,7 +1152,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(
     let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() {
         PartitioningStrategy::PerModule
     } else {
-        PartitioningStrategy::FixedUnitCount(tcx.sess.opts.codegen_units)
+        PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
     };
 
     let codegen_units = time(time_passes, "codegen unit partitioning", || {
@@ -1224,9 +1165,6 @@ fn collect_and_partition_translation_items<'a, 'tcx>(
             .collect::<Vec<_>>()
     });
 
-    assert!(tcx.sess.opts.codegen_units == codegen_units.len() ||
-            tcx.sess.opts.debugging_opts.incremental.is_some());
-
     let translation_items: DefIdSet = items.iter().filter_map(|trans_item| {
         match *trans_item {
             TransItem::Fn(ref instance) => Some(instance.def_id()),
@@ -1372,7 +1310,9 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // crashes if the module identifier is same as other symbols
         // such as a function name in the module.
         // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
-        let llmod_id = format!("{}.rs", cgu.name());
+        let llmod_id = format!("{}-{}.rs",
+                               cgu.name(),
+                               tcx.crate_disambiguator(LOCAL_CRATE));
 
         // Instantiate translation items without filling out definitions yet...
         let scx = SharedCrateContext::new(tcx);
@@ -1431,12 +1371,6 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 tm: create_target_machine(ccx.sess()),
             };
 
-            // Adjust exported symbols for MSVC dllimport
-            if ccx.sess().target.target.options.is_like_msvc &&
-               ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
-                create_imps(ccx.sess(), &llvm_module);
-            }
-
             ModuleTranslation {
                 name: cgu_name,
                 source: ModuleSource::Translated(llvm_module),
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 18b91b18d8e..b515c9420bf 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -24,6 +24,7 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::{self, TypeFoldable};
 use rustc::traits;
 use rustc::ty::subst::Substs;
+use rustc_back::PanicStrategy;
 use type_of;
 
 /// Translates a reference to a fn/method item, monomorphizing and
@@ -105,8 +106,10 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // *in Rust code* may unwind. Foreign items like `extern "C" {
         // fn foo(); }` are assumed not to unwind **unless** they have
         // a `#[unwind]` attribute.
-        if !tcx.is_foreign_item(instance_def_id) {
-            attributes::unwind(llfn, true);
+        if tcx.sess.panic_strategy() == PanicStrategy::Unwind {
+            if !tcx.is_foreign_item(instance_def_id) {
+                attributes::unwind(llfn, true);
+            }
         }
 
         // Apply an appropriate linkage/visibility value to our item that we
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 52607904f73..e3856cabcf9 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -36,7 +36,6 @@ use libc::{c_uint, c_char};
 use std::iter;
 
 use syntax::abi::Abi;
-use syntax::attr;
 use syntax::symbol::InternedString;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -552,22 +551,6 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-pub fn requests_inline<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    instance: &ty::Instance<'tcx>
-) -> bool {
-    if is_inline_instance(tcx, instance) {
-        return true
-    }
-    if let ty::InstanceDef::DropGlue(..) = instance.def {
-        // Drop glue wants to be instantiated at every translation
-        // unit, but without an #[inline] hint. We should make this
-        // available to normal end-users.
-        return true
-    }
-    attr::requests_inline(&instance.def.attrs(tcx)[..])
-}
-
 pub fn is_inline_instance<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: &ty::Instance<'tcx>
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 1722d008a54..6fd24c1786c 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -642,7 +642,7 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
     }
 
     fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.tcx().normalize_associated_type(&ty)
+        self.tcx().fully_normalize_associated_types_in(&ty)
     }
 }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 8a89bfee4ac..3bde78e2c6a 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -30,7 +30,7 @@ use rustc::ty::fold::TypeVisitor;
 use rustc::ty::subst::Substs;
 use rustc::ty::util::TypeIdHasher;
 use rustc::hir;
-use rustc_data_structures::ToHex;
+use rustc::ich::Fingerprint;
 use {type_of, machine, monomorphize};
 use common::{self, CrateContext};
 use type_::Type;
@@ -146,11 +146,10 @@ impl<'tcx> TypeMap<'tcx> {
 
         // The hasher we are using to generate the UniqueTypeId. We want
         // something that provides more than the 64 bits of the DefaultHasher.
-
-        let mut type_id_hasher = TypeIdHasher::<[u8; 20]>::new(cx.tcx());
+        let mut type_id_hasher = TypeIdHasher::<Fingerprint>::new(cx.tcx());
         type_id_hasher.visit_ty(type_);
-
         let unique_type_id = type_id_hasher.finish().to_hex();
+
         let key = self.unique_id_interner.intern(&unique_type_id);
         self.type_to_unique_id.insert(type_, UniqueTypeId(key));
 
@@ -583,7 +582,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         }
         ty::TyGenerator(def_id, substs, _) => {
             let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx()).map(|t| {
-                cx.tcx().normalize_associated_type(&t)
+                cx.tcx().fully_normalize_associated_types_in(&t)
             }).collect();
             prepare_tuple_metadata(cx,
                                    t,
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 7e2ac95cd84..1a284292016 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -376,7 +376,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 name_to_append_suffix_to.push_str(",");
             }
 
-            let actual_type = cx.tcx().normalize_associated_type(&actual_type);
+            let actual_type = cx.tcx().fully_normalize_associated_types_in(&actual_type);
             // Add actual type name to <...> clause of function name
             let actual_type_name = compute_debuginfo_type_name(cx,
                                                                actual_type,
@@ -389,7 +389,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
             let names = get_type_parameter_names(cx, generics);
             substs.types().zip(names).map(|(ty, name)| {
-                let actual_type = cx.tcx().normalize_associated_type(&ty);
+                let actual_type = cx.tcx().fully_normalize_associated_types_in(&ty);
                 let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
                 let name = CString::new(name.as_str().as_bytes()).unwrap();
                 unsafe {
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 3c8ff454997..f894bdf16e4 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -24,6 +24,7 @@ use llvm::{self, ValueRef};
 use llvm::AttributePlace::Function;
 use rustc::ty::Ty;
 use rustc::session::config::Sanitizer;
+use rustc_back::PanicStrategy;
 use abi::{Abi, FnType};
 use attributes;
 use context::CrateContext;
@@ -98,6 +99,10 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty:
         _ => {},
     }
 
+    if ccx.tcx().sess.panic_strategy() != PanicStrategy::Unwind {
+        attributes::unwind(llfn, false);
+    }
+
     llfn
 }
 
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 2b1c62c7f1c..93f2eef76d1 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -64,6 +64,7 @@ extern crate serialize;
 extern crate cc; // Used to locate MSVC
 
 pub use base::trans_crate;
+use back::bytecode::RLIB_BYTECODE_EXTENSION;
 
 pub use metadata::LlvmMetadataLoader;
 pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug};
@@ -83,11 +84,14 @@ use rustc::ty::maps::Providers;
 use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 
+use rustc_trans_utils::collector;
+use rustc_trans_utils::monomorphize;
+
 mod diagnostics;
 
 pub mod back {
     mod archive;
-    mod bytecode;
+    pub mod bytecode;
     mod command;
     pub(crate) mod linker;
     pub mod link;
@@ -124,7 +128,6 @@ mod cabi_x86;
 mod cabi_x86_64;
 mod cabi_x86_win64;
 mod callee;
-mod collector;
 mod common;
 mod consts;
 mod context;
@@ -137,7 +140,6 @@ mod machine;
 mod metadata;
 mod meth;
 mod mir;
-mod monomorphize;
 mod partitioning;
 mod symbol_names_test;
 mod time_graph;
@@ -226,21 +228,37 @@ impl ModuleTranslation {
     pub fn into_compiled_module(self,
                                 emit_obj: bool,
                                 emit_bc: bool,
+                                emit_bc_compressed: bool,
                                 outputs: &OutputFilenames) -> CompiledModule {
         let pre_existing = match self.source {
             ModuleSource::Preexisting(_) => true,
             ModuleSource::Translated(_) => false,
         };
-        let object = outputs.temp_path(OutputType::Object, Some(&self.name));
+        let object = if emit_obj {
+            Some(outputs.temp_path(OutputType::Object, Some(&self.name)))
+        } else {
+            None
+        };
+        let bytecode = if emit_bc {
+            Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)))
+        } else {
+            None
+        };
+        let bytecode_compressed = if emit_bc_compressed {
+            Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
+                    .with_extension(RLIB_BYTECODE_EXTENSION))
+        } else {
+            None
+        };
 
         CompiledModule {
             llmod_id: self.llmod_id,
             name: self.name.clone(),
             kind: self.kind,
             pre_existing,
-            emit_obj,
-            emit_bc,
             object,
+            bytecode,
+            bytecode_compressed,
         }
     }
 }
@@ -249,11 +267,11 @@ impl ModuleTranslation {
 pub struct CompiledModule {
     pub name: String,
     pub llmod_id: String,
-    pub object: PathBuf,
     pub kind: ModuleKind,
     pub pre_existing: bool,
-    pub emit_obj: bool,
-    pub emit_bc: bool,
+    pub object: Option<PathBuf>,
+    pub bytecode: Option<PathBuf>,
+    pub bytecode_compressed: Option<PathBuf>,
 }
 
 pub enum ModuleSource {
@@ -288,6 +306,7 @@ pub struct CrateTranslation {
     pub crate_name: Symbol,
     pub modules: Vec<CompiledModule>,
     allocator_module: Option<CompiledModule>,
+    metadata_module: CompiledModule,
     pub link: rustc::middle::cstore::LinkMeta,
     pub metadata: rustc::middle::cstore::EncodedMetadata,
     windows_subsystem: Option<String>,
diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs
index 448feb5259d..4fe726364f2 100644
--- a/src/librustc_trans/llvm_util.rs
+++ b/src/librustc_trans/llvm_util.rs
@@ -73,6 +73,8 @@ unsafe fn configure_llvm(sess: &Session) {
 
 const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];
 
+const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0"];
+
 const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                  "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                  "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
@@ -90,6 +92,7 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
 
     let whitelist = match &*sess.target.target.arch {
         "arm" => ARM_WHITELIST,
+        "aarch64" => AARCH64_WHITELIST,
         "x86" | "x86_64" => X86_WHITELIST,
         "hexagon" => HEXAGON_WHITELIST,
         "powerpc" | "powerpc64" => POWERPC_WHITELIST,
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 88407947f0e..3253a0339a8 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 use llvm::ValueRef;
-use rustc::traits;
 use callee;
 use common::*;
 use builder::Builder;
@@ -87,7 +86,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     if let Some(trait_ref) = trait_ref {
         let trait_ref = trait_ref.with_self_ty(tcx, ty);
-        let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
+        let methods = tcx.vtable_methods(trait_ref);
+        let methods = methods.iter().cloned().map(|opt_mth| {
             opt_mth.map_or(nullptr, |(def_id, substs)| {
                 callee::resolve_and_get_fn(ccx, def_id, substs)
             })
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 5206ad74e20..d5d44bfa7ba 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -23,7 +23,7 @@ use builder::Builder;
 use common::{self, CrateContext, Funclet};
 use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
 use monomorphize::Instance;
-use abi::FnType;
+use abi::{ArgAttribute, FnType};
 use type_of;
 
 use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
@@ -378,6 +378,10 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         None
     };
 
+    let deref_op = unsafe {
+        [llvm::LLVMRustDIBuilderCreateOpDeref()]
+    };
+
     mir.args_iter().enumerate().map(|(arg_index, local)| {
         let arg_decl = &mir.local_decls[local];
         let arg_ty = mircx.monomorphize(&arg_decl.ty);
@@ -432,10 +436,9 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
 
         let arg = &mircx.fn_ty.args[idx];
         idx += 1;
-        let llval = if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
+        let llval = if arg.is_indirect() {
             // Don't copy an indirect argument to an alloca, the caller
-            // already put it in a temporary alloca and gave it up, unless
-            // we emit extra-debug-info, which requires local allocas :(.
+            // already put it in a temporary alloca and gave it up
             // FIXME: lifetimes
             if arg.pad.is_some() {
                 llarg_idx += 1;
@@ -444,8 +447,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             llarg_idx += 1;
             llarg
         } else if !lvalue_locals.contains(local.index()) &&
-                  !arg.is_indirect() && arg.cast.is_none() &&
-                  arg_scope.is_none() {
+                  arg.cast.is_none() && arg_scope.is_none() {
             if arg.is_ignore() {
                 return LocalRef::new_operand(bcx.ccx, arg_ty);
             }
@@ -510,13 +512,26 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         arg_scope.map(|scope| {
             // Is this a regular argument?
             if arg_index > 0 || mir.upvar_decls.is_empty() {
+                // The Rust ABI passes indirect variables using a pointer and a manual copy, so we
+                // need to insert a deref here, but the C ABI uses a pointer and a copy using the
+                // byval attribute, for which LLVM does the deref itself, so we must not add it.
+                let variable_access = if arg.is_indirect() &&
+                    !arg.attrs.contains(ArgAttribute::ByVal) {
+                    VariableAccess::IndirectVariable {
+                        alloca: llval,
+                        address_operations: &deref_op,
+                    }
+                } else {
+                    VariableAccess::DirectVariable { alloca: llval }
+                };
+
                 declare_local(
                     bcx,
                     &mircx.debug_context,
                     arg_decl.name.unwrap_or(keywords::Invalid.name()),
                     arg_ty,
                     scope,
-                    VariableAccess::DirectVariable { alloca: llval },
+                    variable_access,
                     VariableKind::ArgumentVariable(arg_index + 1),
                     DUMMY_SP
                 );
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 7b6daa7d133..6980ba8a525 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -108,14 +108,13 @@ use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::middle::trans::{Linkage, Visibility};
-use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use std::collections::hash_map::Entry;
 use syntax::ast::NodeId;
 use syntax::symbol::{Symbol, InternedString};
-use trans_item::{TransItem, TransItemExt, InstantiationMode};
+use trans_item::{TransItem, BaseTransItemExt, TransItemExt, InstantiationMode};
 
 pub use rustc::middle::trans::CodegenUnit;
 
@@ -164,10 +163,27 @@ pub trait CodegenUnitExt<'tcx> {
         fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                    item: TransItem<'tcx>) -> ItemSortKey {
             ItemSortKey(match item {
-                TransItem::Fn(instance) => {
-                    tcx.hir.as_local_node_id(instance.def_id())
+                TransItem::Fn(ref instance) => {
+                    match instance.def {
+                        // We only want to take NodeIds of user-defined
+                        // instances into account. The others don't matter for
+                        // the codegen tests and can even make item order
+                        // unstable.
+                        InstanceDef::Item(def_id) => {
+                            tcx.hir.as_local_node_id(def_id)
+                        }
+                        InstanceDef::Intrinsic(..) |
+                        InstanceDef::FnPtrShim(..) |
+                        InstanceDef::Virtual(..) |
+                        InstanceDef::ClosureOnceShim { .. } |
+                        InstanceDef::DropGlue(..) |
+                        InstanceDef::CloneShim(..) => {
+                            None
+                        }
+                    }
                 }
-                TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => {
+                TransItem::Static(node_id) |
+                TransItem::GlobalAsm(node_id) => {
                     Some(node_id)
                 }
             }, item.symbol_name(tcx))
@@ -280,75 +296,74 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut internalization_candidates = FxHashSet();
 
     for trans_item in trans_items {
-        let is_root = trans_item.instantiation_mode(tcx) == InstantiationMode::GloballyShared;
+        match trans_item.instantiation_mode(tcx) {
+            InstantiationMode::GloballyShared { .. } => {}
+            InstantiationMode::LocalCopy => continue,
+        }
 
-        if is_root {
-            let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item);
-            let is_volatile = is_incremental_build &&
-                              trans_item.is_generic_fn();
+        let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item);
+        let is_volatile = is_incremental_build &&
+                          trans_item.is_generic_fn();
 
-            let codegen_unit_name = match characteristic_def_id {
-                Some(def_id) => compute_codegen_unit_name(tcx, def_id, is_volatile),
-                None => Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str(),
-            };
+        let codegen_unit_name = match characteristic_def_id {
+            Some(def_id) => compute_codegen_unit_name(tcx, def_id, is_volatile),
+            None => Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str(),
+        };
 
-            let make_codegen_unit = || {
-                CodegenUnit::new(codegen_unit_name.clone())
-            };
+        let make_codegen_unit = || {
+            CodegenUnit::new(codegen_unit_name.clone())
+        };
 
-            let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
-                                                .or_insert_with(make_codegen_unit);
-
-            let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
-                Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
-                None => {
-                    match trans_item {
-                        TransItem::Fn(ref instance) => {
-                            let visibility = match instance.def {
-                                InstanceDef::Item(def_id) => {
-                                    if def_id.is_local() {
-                                        if tcx.is_exported_symbol(def_id) {
-                                            Visibility::Default
-                                        } else {
-                                            internalization_candidates.insert(trans_item);
-                                            Visibility::Hidden
-                                        }
+        let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
+                                            .or_insert_with(make_codegen_unit);
+
+        let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
+            Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
+            None => {
+                match trans_item {
+                    TransItem::Fn(ref instance) => {
+                        let visibility = match instance.def {
+                            InstanceDef::Item(def_id) => {
+                                if def_id.is_local() {
+                                    if tcx.is_exported_symbol(def_id) {
+                                        Visibility::Default
                                     } else {
-                                        internalization_candidates.insert(trans_item);
                                         Visibility::Hidden
                                     }
+                                } else {
+                                    Visibility::Hidden
                                 }
-                                InstanceDef::FnPtrShim(..) |
-                                InstanceDef::Virtual(..) |
-                                InstanceDef::Intrinsic(..) |
-                                InstanceDef::ClosureOnceShim { .. } |
-                                InstanceDef::DropGlue(..) |
-                                InstanceDef::CloneShim(..) => {
-                                    bug!("partitioning: Encountered unexpected
-                                          root translation item: {:?}",
-                                          trans_item)
-                                }
-                            };
-                            (Linkage::External, visibility)
-                        }
-                        TransItem::Static(node_id) |
-                        TransItem::GlobalAsm(node_id) => {
-                            let def_id = tcx.hir.local_def_id(node_id);
-                            let visibility = if tcx.is_exported_symbol(def_id) {
-                                Visibility::Default
-                            } else {
-                                internalization_candidates.insert(trans_item);
+                            }
+                            InstanceDef::FnPtrShim(..) |
+                            InstanceDef::Virtual(..) |
+                            InstanceDef::Intrinsic(..) |
+                            InstanceDef::ClosureOnceShim { .. } |
+                            InstanceDef::DropGlue(..) |
+                            InstanceDef::CloneShim(..) => {
                                 Visibility::Hidden
-                            };
-                            (Linkage::External, visibility)
-                        }
+                            }
+                        };
+                        (Linkage::External, visibility)
+                    }
+                    TransItem::Static(node_id) |
+                    TransItem::GlobalAsm(node_id) => {
+                        let def_id = tcx.hir.local_def_id(node_id);
+                        let visibility = if tcx.is_exported_symbol(def_id) {
+                            Visibility::Default
+                        } else {
+                            Visibility::Hidden
+                        };
+                        (Linkage::External, visibility)
                     }
                 }
-            };
-
-            codegen_unit.items_mut().insert(trans_item, (linkage, visibility));
-            roots.insert(trans_item);
+            }
+        };
+        if visibility == Visibility::Hidden {
+            internalization_candidates.insert(trans_item);
         }
+
+        codegen_unit.items_mut().insert(trans_item, (linkage, visibility));
+        roots.insert(trans_item);
     }
 
     // always ensure we have at least one CGU; otherwise, if we have a
@@ -391,15 +406,6 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
     for (index, cgu) in codegen_units.iter_mut().enumerate() {
         cgu.set_name(numbered_codegen_unit_name(crate_name, index));
     }
-
-    // If the initial partitioning contained less than target_cgu_count to begin
-    // with, we won't have enough codegen units here, so add a empty units until
-    // we reach the target count
-    while codegen_units.len() < target_cgu_count {
-        let index = codegen_units.len();
-        let name = numbered_codegen_unit_name(crate_name, index);
-        codegen_units.push(CodegenUnit::new(name));
-    }
 }
 
 fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
@@ -627,7 +633,7 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
-    Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str()
+    Symbol::intern(&format!("{}{}", crate_name, index)).as_str()
 }
 
 fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_trans/time_graph.rs b/src/librustc_trans/time_graph.rs
index ec57af888e5..a8502682a80 100644
--- a/src/librustc_trans/time_graph.rs
+++ b/src/librustc_trans/time_graph.rs
@@ -9,11 +9,12 @@
 // except according to those terms.
 
 use std::collections::HashMap;
+use std::fs::File;
+use std::io::prelude::*;
 use std::marker::PhantomData;
+use std::mem;
 use std::sync::{Arc, Mutex};
 use std::time::Instant;
-use std::io::prelude::*;
-use std::fs::File;
 
 const OUTPUT_WIDTH_IN_PX: u64 = 1000;
 const TIME_LINE_HEIGHT_IN_PX: u64 = 20;
@@ -25,6 +26,7 @@ struct Timing {
     end: Instant,
     work_package_kind: WorkPackageKind,
     name: String,
+    events: Vec<(String, Instant)>,
 }
 
 #[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
@@ -44,9 +46,14 @@ pub struct TimeGraph {
 #[derive(Clone, Copy)]
 pub struct WorkPackageKind(pub &'static [&'static str]);
 
-pub struct RaiiToken {
+pub struct Timeline {
+    token: Option<RaiiToken>,
+}
+
+struct RaiiToken {
     graph: TimeGraph,
     timeline: TimelineId,
+    events: Vec<(String, Instant)>,
     // The token must not be Send:
     _marker: PhantomData<*const ()>
 }
@@ -54,7 +61,7 @@ pub struct RaiiToken {
 
 impl Drop for RaiiToken {
     fn drop(&mut self) {
-        self.graph.end(self.timeline);
+        self.graph.end(self.timeline, mem::replace(&mut self.events, Vec::new()));
     }
 }
 
@@ -68,7 +75,7 @@ impl TimeGraph {
     pub fn start(&self,
                  timeline: TimelineId,
                  work_package_kind: WorkPackageKind,
-                 name: &str) -> RaiiToken {
+                 name: &str) -> Timeline {
         {
             let mut table = self.data.lock().unwrap();
 
@@ -81,14 +88,17 @@ impl TimeGraph {
             data.open_work_package = Some((Instant::now(), work_package_kind, name.to_string()));
         }
 
-        RaiiToken {
-            graph: self.clone(),
-            timeline,
-            _marker: PhantomData,
+        Timeline {
+            token: Some(RaiiToken {
+                graph: self.clone(),
+                timeline,
+                events: Vec::new(),
+                _marker: PhantomData,
+            }),
         }
     }
 
-    fn end(&self, timeline: TimelineId) {
+    fn end(&self, timeline: TimelineId, events: Vec<(String, Instant)>) {
         let end = Instant::now();
 
         let mut table = self.data.lock().unwrap();
@@ -100,6 +110,7 @@ impl TimeGraph {
                 end,
                 work_package_kind,
                 name,
+                events,
             });
         } else {
             bug!("end timing without start?")
@@ -113,13 +124,13 @@ impl TimeGraph {
             assert!(data.open_work_package.is_none());
         }
 
-        let mut timelines: Vec<PerThread> =
+        let mut threads: Vec<PerThread> =
             table.values().map(|data| data.clone()).collect();
 
-        timelines.sort_by_key(|timeline| timeline.timings[0].start);
+        threads.sort_by_key(|timeline| timeline.timings[0].start);
 
-        let earliest_instant = timelines[0].timings[0].start;
-        let latest_instant = timelines.iter()
+        let earliest_instant = threads[0].timings[0].start;
+        let latest_instant = threads.iter()
                                        .map(|timeline| timeline.timings
                                                                .last()
                                                                .unwrap()
@@ -130,16 +141,46 @@ impl TimeGraph {
 
         let mut file = File::create(format!("{}.html", output_filename)).unwrap();
 
-        writeln!(file, "<html>").unwrap();
-        writeln!(file, "<head></head>").unwrap();
-        writeln!(file, "<body>").unwrap();
+        writeln!(file, "
+            <html>
+            <head>
+                <style>
+                    #threads a {{
+                        position: absolute;
+                        overflow: hidden;
+                    }}
+                    #threads {{
+                        height: {total_height}px;
+                        width: {width}px;
+                    }}
+
+                    .timeline {{
+                        display: none;
+                        width: {width}px;
+                        position: relative;
+                    }}
+
+                    .timeline:target {{
+                        display: block;
+                    }}
+
+                    .event {{
+                        position: absolute;
+                    }}
+                </style>
+            </head>
+            <body>
+                <div id='threads'>
+        ",
+            total_height = threads.len() * TIME_LINE_HEIGHT_STRIDE_IN_PX,
+            width = OUTPUT_WIDTH_IN_PX,
+        ).unwrap();
 
         let mut color = 0;
-
-        for (line_index, timeline) in timelines.iter().enumerate() {
+        for (line_index, thread) in threads.iter().enumerate() {
             let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX;
 
-            for span in &timeline.timings {
+            for span in &thread.timings {
                 let start = distance(earliest_instant, span.start);
                 let end = distance(earliest_instant, span.end);
 
@@ -148,13 +189,13 @@ impl TimeGraph {
 
                 let colors = span.work_package_kind.0;
 
-                writeln!(file, "<div style='position:absolute; \
-                                            overflow:hidden; \
-                                            top:{}px; \
-                                            left:{}px; \
-                                            width:{}px; \
-                                            height:{}px; \
-                                            background:{};'>{}</div>",
+                writeln!(file, "<a href='#timing{}'
+                                   style='top:{}px; \
+                                          left:{}px; \
+                                          width:{}px; \
+                                          height:{}px; \
+                                          background:{};'>{}</a>",
+                    color,
                     line_top,
                     start,
                     end - start,
@@ -167,8 +208,61 @@ impl TimeGraph {
             }
         }
 
-        writeln!(file, "</body>").unwrap();
-        writeln!(file, "</html>").unwrap();
+        writeln!(file, "
+            </div>
+        ").unwrap();
+
+        let mut idx = 0;
+        for thread in threads.iter() {
+            for timing in &thread.timings {
+                let colors = timing.work_package_kind.0;
+                let height = TIME_LINE_HEIGHT_STRIDE_IN_PX * timing.events.len();
+                writeln!(file, "<div class='timeline'
+                                     id='timing{}'
+                                     style='background:{};height:{}px;'>",
+                         idx,
+                         colors[idx % colors.len()],
+                         height).unwrap();
+                idx += 1;
+                let max = distance(timing.start, timing.end);
+                for (i, &(ref event, time)) in timing.events.iter().enumerate() {
+                    let i = i as u64;
+                    let time = distance(timing.start, time);
+                    let at = normalize(time, max, OUTPUT_WIDTH_IN_PX);
+                    writeln!(file, "<span class='event'
+                                          style='left:{}px;\
+                                                 top:{}px;'>{}</span>",
+                             at,
+                             TIME_LINE_HEIGHT_IN_PX * i,
+                             event).unwrap();
+                }
+                writeln!(file, "</div>").unwrap();
+            }
+        }
+
+        writeln!(file, "
+            </body>
+            </html>
+        ").unwrap();
+    }
+}
+
+impl Timeline {
+    pub fn noop() -> Timeline {
+        Timeline { token: None }
+    }
+
+    /// Record an event which happened at this moment on this timeline.
+    ///
+    /// Events are displayed in the eventual HTML output where you can click on
+    /// a particular timeline and it'll expand to all of the events that
+    /// happened on that timeline. This can then be used to drill into a
+    /// particular timeline and see what events are happening and taking the
+    /// most time.
+    pub fn record(&mut self, name: &str) {
+        if let Some(ref mut token) = self.token {
+            token.events.push((name.to_string(), Instant::now()));
+        }
     }
 }
 
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 526b61303e1..db1af8cdefb 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -24,36 +24,21 @@ use declare;
 use llvm;
 use monomorphize::Instance;
 use rustc::hir;
-use rustc::hir::def_id::DefId;
 use rustc::middle::trans::{Linkage, Visibility};
-use rustc::traits;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
 use syntax::ast;
 use syntax::attr;
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 use type_of;
-use std::fmt::{self, Write};
-use std::iter;
+use std::fmt;
 
 pub use rustc::middle::trans::TransItem;
 
-/// Describes how a translation item will be instantiated in object files.
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
-pub enum InstantiationMode {
-    /// There will be exactly one instance of the given TransItem. It will have
-    /// external linkage so that it can be linked to from other codegen units.
-    GloballyShared,
-
-    /// Each codegen unit containing a reference to the given TransItem will
-    /// have its own private copy of the function (with internal linkage).
-    LocalCopy,
-}
-
-pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
-    fn as_trans_item(&self) -> &TransItem<'tcx>;
+pub use rustc_trans_utils::trans_item::*;
+pub use rustc_trans_utils::trans_item::TransItemExt as BaseTransItemExt;
 
+pub trait TransItemExt<'a, 'tcx>: fmt::Debug + BaseTransItemExt<'a, 'tcx> {
     fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
         debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
                self.to_string(ccx.tcx()),
@@ -151,24 +136,6 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
         }.map(|node_id| tcx.hir.span(node_id))
     }
 
-    fn instantiation_mode(&self,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                          -> InstantiationMode {
-        match *self.as_trans_item() {
-            TransItem::Fn(ref instance) => {
-                if self.explicit_linkage(tcx).is_none() &&
-                    common::requests_inline(tcx, instance)
-                {
-                    InstantiationMode::LocalCopy
-                } else {
-                    InstantiationMode::GloballyShared
-                }
-            }
-            TransItem::Static(..) => InstantiationMode::GloballyShared,
-            TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared,
-        }
-    }
-
     fn is_generic_fn(&self) -> bool {
         match *self.as_trans_item() {
             TransItem::Fn(ref instance) => {
@@ -179,97 +146,6 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
         }
     }
 
-    fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
-        let def_id = match *self.as_trans_item() {
-            TransItem::Fn(ref instance) => instance.def_id(),
-            TransItem::Static(node_id) => tcx.hir.local_def_id(node_id),
-            TransItem::GlobalAsm(..) => return None,
-        };
-
-        let attributes = tcx.get_attrs(def_id);
-        if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") {
-            if let Some(linkage) = base::linkage_by_name(&name.as_str()) {
-                Some(linkage)
-            } else {
-                let span = tcx.hir.span_if_local(def_id);
-                if let Some(span) = span {
-                    tcx.sess.span_fatal(span, "invalid linkage specified")
-                } else {
-                    tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
-                }
-            }
-        } else {
-            None
-        }
-    }
-
-    /// Returns whether this instance is instantiable - whether it has no unsatisfied
-    /// predicates.
-    ///
-    /// In order to translate an item, all of its predicates must hold, because
-    /// otherwise the item does not make sense. Type-checking ensures that
-    /// the predicates of every item that is *used by* a valid item *do*
-    /// hold, so we can rely on that.
-    ///
-    /// However, we translate collector roots (reachable items) and functions
-    /// in vtables when they are seen, even if they are not used, and so they
-    /// might not be instantiable. For example, a programmer can define this
-    /// public function:
-    ///
-    ///     pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
-    ///         <&mut () as Clone>::clone(&s);
-    ///     }
-    ///
-    /// That function can't be translated, because the method `<&mut () as Clone>::clone`
-    /// does not exist. Luckily for us, that function can't ever be used,
-    /// because that would require for `&'a mut (): Clone` to hold, so we
-    /// can just not emit any code, or even a linker reference for it.
-    ///
-    /// Similarly, if a vtable method has such a signature, and therefore can't
-    /// be used, we can just not emit it and have a placeholder (a null pointer,
-    /// which will never be accessed) in its place.
-    fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
-        debug!("is_instantiable({:?})", self);
-        let (def_id, substs) = match *self.as_trans_item() {
-            TransItem::Fn(ref instance) => (instance.def_id(), instance.substs),
-            TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()),
-            // global asm never has predicates
-            TransItem::GlobalAsm(..) => return true
-        };
-
-        let predicates = tcx.predicates_of(def_id).predicates.subst(tcx, substs);
-        traits::normalize_and_test_predicates(tcx, predicates)
-    }
-
-    fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
-        let hir_map = &tcx.hir;
-
-        return match *self.as_trans_item() {
-            TransItem::Fn(instance) => {
-                to_string_internal(tcx, "fn ", instance)
-            },
-            TransItem::Static(node_id) => {
-                let def_id = hir_map.local_def_id(node_id);
-                let instance = Instance::new(def_id, tcx.intern_substs(&[]));
-                to_string_internal(tcx, "static ", instance)
-            },
-            TransItem::GlobalAsm(..) => {
-                "global_asm".to_string()
-            }
-        };
-
-        fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        prefix: &str,
-                                        instance: Instance<'tcx>)
-                                        -> String {
-            let mut result = String::with_capacity(32);
-            result.push_str(prefix);
-            let printer = DefPathBasedNames::new(tcx, false, false);
-            printer.push_instance_as_string(instance, &mut result);
-            result
-        }
-    }
-
     fn to_raw_string(&self) -> String {
         match *self.as_trans_item() {
             TransItem::Fn(instance) => {
@@ -287,11 +163,7 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
     }
 }
 
-impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {
-    fn as_trans_item(&self) -> &TransItem<'tcx> {
-        self
-    }
-}
+impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {}
 
 fn predefine_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               node_id: ast::NodeId,
@@ -359,235 +231,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     ccx.instances().borrow_mut().insert(instance, lldecl);
 }
 
-//=-----------------------------------------------------------------------------
-// TransItem String Keys
-//=-----------------------------------------------------------------------------
-
-// The code below allows for producing a unique string key for a trans item.
-// These keys are used by the handwritten auto-tests, so they need to be
-// predictable and human-readable.
-//
-// Note: A lot of this could looks very similar to what's already in the
-//       ppaux module. It would be good to refactor things so we only have one
-//       parameterizable implementation for printing types.
-
-/// Same as `unique_type_name()` but with the result pushed onto the given
-/// `output` parameter.
-pub struct DefPathBasedNames<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    omit_disambiguators: bool,
-    omit_local_crate_name: bool,
-}
-
-impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               omit_disambiguators: bool,
-               omit_local_crate_name: bool)
-               -> Self {
-        DefPathBasedNames {
-            tcx,
-            omit_disambiguators,
-            omit_local_crate_name,
-        }
-    }
-
-    pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
-        match t.sty {
-            ty::TyBool              => output.push_str("bool"),
-            ty::TyChar              => output.push_str("char"),
-            ty::TyStr               => output.push_str("str"),
-            ty::TyNever             => output.push_str("!"),
-            ty::TyInt(ast::IntTy::Is)    => output.push_str("isize"),
-            ty::TyInt(ast::IntTy::I8)    => output.push_str("i8"),
-            ty::TyInt(ast::IntTy::I16)   => output.push_str("i16"),
-            ty::TyInt(ast::IntTy::I32)   => output.push_str("i32"),
-            ty::TyInt(ast::IntTy::I64)   => output.push_str("i64"),
-            ty::TyInt(ast::IntTy::I128)   => output.push_str("i128"),
-            ty::TyUint(ast::UintTy::Us)   => output.push_str("usize"),
-            ty::TyUint(ast::UintTy::U8)   => output.push_str("u8"),
-            ty::TyUint(ast::UintTy::U16)  => output.push_str("u16"),
-            ty::TyUint(ast::UintTy::U32)  => output.push_str("u32"),
-            ty::TyUint(ast::UintTy::U64)  => output.push_str("u64"),
-            ty::TyUint(ast::UintTy::U128)  => output.push_str("u128"),
-            ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
-            ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
-            ty::TyAdt(adt_def, substs) => {
-                self.push_def_path(adt_def.did, output);
-                self.push_type_params(substs, iter::empty(), output);
-            },
-            ty::TyTuple(component_types, _) => {
-                output.push('(');
-                for &component_type in component_types {
-                    self.push_type_name(component_type, output);
-                    output.push_str(", ");
-                }
-                if !component_types.is_empty() {
-                    output.pop();
-                    output.pop();
-                }
-                output.push(')');
-            },
-            ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
-                output.push('*');
-                match mutbl {
-                    hir::MutImmutable => output.push_str("const "),
-                    hir::MutMutable => output.push_str("mut "),
-                }
-
-                self.push_type_name(inner_type, output);
-            },
-            ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
-                output.push('&');
-                if mutbl == hir::MutMutable {
-                    output.push_str("mut ");
-                }
-
-                self.push_type_name(inner_type, output);
-            },
-            ty::TyArray(inner_type, len) => {
-                output.push('[');
-                self.push_type_name(inner_type, output);
-                write!(output, "; {}",
-                    len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
-                output.push(']');
-            },
-            ty::TySlice(inner_type) => {
-                output.push('[');
-                self.push_type_name(inner_type, output);
-                output.push(']');
-            },
-            ty::TyDynamic(ref trait_data, ..) => {
-                if let Some(principal) = trait_data.principal() {
-                    self.push_def_path(principal.def_id(), output);
-                    self.push_type_params(principal.skip_binder().substs,
-                        trait_data.projection_bounds(),
-                        output);
-                }
-            },
-            ty::TyFnDef(..) |
-            ty::TyFnPtr(_) => {
-                let sig = t.fn_sig(self.tcx);
-                if sig.unsafety() == hir::Unsafety::Unsafe {
-                    output.push_str("unsafe ");
-                }
-
-                let abi = sig.abi();
-                if abi != ::abi::Abi::Rust {
-                    output.push_str("extern \"");
-                    output.push_str(abi.name());
-                    output.push_str("\" ");
-                }
-
-                output.push_str("fn(");
-
-                let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
-
-                if !sig.inputs().is_empty() {
-                    for &parameter_type in sig.inputs() {
-                        self.push_type_name(parameter_type, output);
-                        output.push_str(", ");
-                    }
-                    output.pop();
-                    output.pop();
-                }
-
-                if sig.variadic {
-                    if !sig.inputs().is_empty() {
-                        output.push_str(", ...");
-                    } else {
-                        output.push_str("...");
-                    }
-                }
-
-                output.push(')');
-
-                if !sig.output().is_nil() {
-                    output.push_str(" -> ");
-                    self.push_type_name(sig.output(), output);
-                }
-            },
-            ty::TyGenerator(def_id, ref closure_substs, _) |
-            ty::TyClosure(def_id, ref closure_substs) => {
-                self.push_def_path(def_id, output);
-                let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
-                let substs = closure_substs.substs.truncate_to(self.tcx, generics);
-                self.push_type_params(substs, iter::empty(), output);
-            }
-            ty::TyError |
-            ty::TyInfer(_) |
-            ty::TyProjection(..) |
-            ty::TyParam(_) |
-            ty::TyAnon(..) => {
-                bug!("DefPathBasedNames: Trying to create type name for \
-                                         unexpected type: {:?}", t);
-            }
-        }
-    }
-
-    pub fn push_def_path(&self,
-                         def_id: DefId,
-                         output: &mut String) {
-        let def_path = self.tcx.def_path(def_id);
-
-        // some_crate::
-        if !(self.omit_local_crate_name && def_id.is_local()) {
-            output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
-            output.push_str("::");
-        }
-
-        // foo::bar::ItemName::
-        for part in self.tcx.def_path(def_id).data {
-            if self.omit_disambiguators {
-                write!(output, "{}::", part.data.as_interned_str()).unwrap();
-            } else {
-                write!(output, "{}[{}]::",
-                       part.data.as_interned_str(),
-                       part.disambiguator).unwrap();
-            }
-        }
-
-        // remove final "::"
-        output.pop();
-        output.pop();
-    }
-
-    fn push_type_params<I>(&self,
-                            substs: &Substs<'tcx>,
-                            projections: I,
-                            output: &mut String)
-        where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
-    {
-        let mut projections = projections.peekable();
-        if substs.types().next().is_none() && projections.peek().is_none() {
-            return;
-        }
-
-        output.push('<');
-
-        for type_parameter in substs.types() {
-            self.push_type_name(type_parameter, output);
-            output.push_str(", ");
-        }
-
-        for projection in projections {
-            let projection = projection.skip_binder();
-            let name = &self.tcx.associated_item(projection.item_def_id).name.as_str();
-            output.push_str(name);
-            output.push_str("=");
-            self.push_type_name(projection.ty, output);
-            output.push_str(", ");
-        }
-
-        output.pop();
-        output.pop();
-
-        output.push('>');
-    }
-
-    pub fn push_instance_as_string(&self,
-                                   instance: Instance<'tcx>,
-                                   output: &mut String) {
-        self.push_def_path(instance.def_id(), output);
-        self.push_type_params(instance.substs, iter::empty(), output);
-    }
-}
diff --git a/src/librustc_trans_utils/Cargo.toml b/src/librustc_trans_utils/Cargo.toml
index bedbea00688..7d9d7cea933 100644
--- a/src/librustc_trans_utils/Cargo.toml
+++ b/src/librustc_trans_utils/Cargo.toml
@@ -19,3 +19,4 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans_utils/collector.rs
index 73df1b45c59..c87d86262ef 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans_utils/collector.rs
@@ -195,6 +195,7 @@ use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
+use rustc::middle::trans::TransItem;
 use rustc::traits;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
@@ -206,7 +207,7 @@ use common::{def_ty, instance_ty, type_is_sized};
 use monomorphize::{self, Instance};
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
 
-use trans_item::{TransItem, TransItemExt, DefPathBasedNames, InstantiationMode};
+use trans_item::{TransItemExt, DefPathBasedNames, InstantiationMode};
 
 use rustc_data_structures::bitvec::BitVector;
 
@@ -401,9 +402,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        caller: TransItem<'tcx>,
-                                        callees: &[TransItem<'tcx>],
-                                        inlining_map: &mut InliningMap<'tcx>) {
+                             caller: TransItem<'tcx>,
+                             callees: &[TransItem<'tcx>],
+                             inlining_map: &mut InliningMap<'tcx>) {
     let is_inlining_candidate = |trans_item: &TransItem<'tcx>| {
         trans_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy
     };
@@ -849,8 +850,8 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             assert!(!poly_trait_ref.has_escaping_regions());
 
             // Walk all methods of the trait, including those of its supertraits
-            let methods = traits::get_vtable_methods(tcx, poly_trait_ref);
-            let methods = methods.filter_map(|method| method)
+            let methods = tcx.vtable_methods(poly_trait_ref);
+            let methods = methods.iter().cloned().filter_map(|method| method)
                 .map(|(def_id, substs)| ty::Instance::resolve(
                         tcx,
                         ty::ParamEnv::empty(traits::Reveal::All),
diff --git a/src/librustc_trans_utils/common.rs b/src/librustc_trans_utils/common.rs
new file mode 100644
index 00000000000..634e37220e2
--- /dev/null
+++ b/src/librustc_trans_utils/common.rs
@@ -0,0 +1,78 @@
+// 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.
+
+#![allow(non_camel_case_types, non_snake_case)]
+
+//! Code that is useful in various trans modules.
+
+use rustc::hir::def_id::DefId;
+use rustc::hir::map::DefPathData;
+use rustc::traits;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
+
+use syntax::attr;
+use syntax_pos::DUMMY_SP;
+
+pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
+}
+
+pub fn requests_inline<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: &ty::Instance<'tcx>
+) -> bool {
+    if is_inline_instance(tcx, instance) {
+        return true
+    }
+    if let ty::InstanceDef::DropGlue(..) = instance.def {
+        // Drop glue wants to be instantiated at every translation
+        // unit, but without an #[inline] hint. We should make this
+        // available to normal end-users.
+        return true
+    }
+    attr::requests_inline(&instance.def.attrs(tcx)[..])
+}
+
+pub fn is_inline_instance<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: &ty::Instance<'tcx>
+) -> bool {
+    let def_id = match instance.def {
+        ty::InstanceDef::Item(def_id) => def_id,
+        ty::InstanceDef::DropGlue(_, Some(_)) => return false,
+        _ => return true
+    };
+    match tcx.def_key(def_id).disambiguated_data.data {
+        DefPathData::StructCtor |
+        DefPathData::EnumVariant(..) |
+        DefPathData::ClosureExpr => true,
+        _ => false
+    }
+}
+
+/// Given a DefId and some Substs, produces the monomorphic item type.
+pub fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        def_id: DefId,
+                        substs: &'tcx Substs<'tcx>)
+                        -> Ty<'tcx>
+{
+    let ty = tcx.type_of(def_id);
+    tcx.trans_apply_param_substs(substs, &ty)
+}
+
+/// Return the substituted type of an instance.
+pub fn instance_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             instance: &ty::Instance<'tcx>)
+                             -> Ty<'tcx>
+{
+    let ty = instance.def.def_ty(tcx);
+    tcx.trans_apply_param_substs(instance.substs, &ty)
+}
diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs
index 6873befd2bf..bc8f8d5a6da 100644
--- a/src/librustc_trans_utils/lib.rs
+++ b/src/librustc_trans_utils/lib.rs
@@ -38,6 +38,7 @@ extern crate log;
 #[macro_use]
 extern crate rustc;
 extern crate rustc_back;
+extern crate rustc_data_structures;
 extern crate syntax;
 extern crate syntax_pos;
 
@@ -49,7 +50,11 @@ use rustc::util::nodemap::NodeSet;
 
 use syntax::attr;
 
+mod common;
 pub mod link;
+pub mod collector;
+pub mod trans_item;
+pub mod monomorphize;
 pub mod trans_crate;
 
 /// check for the #[rustc_error] annotation, which forces an
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans_utils/monomorphize.rs
index cd2a881451c..ab61dacf010 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans_utils/monomorphize.rs
@@ -15,8 +15,6 @@ use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
 
-use syntax::codemap::DUMMY_SP;
-
 pub use rustc::ty::Instance;
 
 fn fn_once_adapter_instance<'a, 'tcx>(
@@ -110,13 +108,14 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            source_ty: Ty<'tcx>,
                                            target_ty: Ty<'tcx>)
                                            -> CustomCoerceUnsized {
+    let def_id = tcx.lang_items().coerce_unsized_trait().unwrap();
+
     let trait_ref = ty::Binder(ty::TraitRef {
-        def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
+        def_id: def_id,
         substs: tcx.mk_substs_trait(source_ty, &[target_ty])
     });
 
-    match tcx.trans_fulfill_obligation(
-        DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), trait_ref) {
+    match tcx.trans_fulfill_obligation( (ty::ParamEnv::empty(traits::Reveal::All), trait_ref)) {
         traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
             tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
         }
@@ -132,6 +131,6 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           f: &'tcx ty::FieldDef)
                           -> Ty<'tcx>
 {
-    tcx.normalize_associated_type(&f.ty(tcx, param_substs))
+    tcx.fully_normalize_associated_types_in(&f.ty(tcx, param_substs))
 }
 
diff --git a/src/librustc_trans_utils/trans_item.rs b/src/librustc_trans_utils/trans_item.rs
new file mode 100644
index 00000000000..0ada39d7d27
--- /dev/null
+++ b/src/librustc_trans_utils/trans_item.rs
@@ -0,0 +1,464 @@
+// 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.
+
+//! Walks the crate looking for items/impl-items/trait-items that have
+//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
+//! generates an error giving, respectively, the symbol name or
+//! item-path. This is used for unit testing the code that generates
+//! paths etc in all kinds of annoying scenarios.
+
+use common;
+use monomorphize::Instance;
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::middle::trans::Linkage;
+use rustc::session::config::OptLevel;
+use rustc::traits;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::{Subst, Substs};
+use syntax::ast;
+use syntax::attr::{self, InlineAttr};
+use std::fmt::{self, Write};
+use std::iter;
+
+pub use rustc::middle::trans::TransItem;
+
+pub fn linkage_by_name(name: &str) -> Option<Linkage> {
+    use rustc::middle::trans::Linkage::*;
+
+    // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
+    // applicable to variable declarations and may not really make sense for
+    // Rust code in the first place but whitelist them anyway and trust that
+    // the user knows what s/he's doing. Who knows, unanticipated use cases
+    // may pop up in the future.
+    //
+    // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
+    // and don't have to be, LLVM treats them as no-ops.
+    match name {
+        "appending" => Some(Appending),
+        "available_externally" => Some(AvailableExternally),
+        "common" => Some(Common),
+        "extern_weak" => Some(ExternalWeak),
+        "external" => Some(External),
+        "internal" => Some(Internal),
+        "linkonce" => Some(LinkOnceAny),
+        "linkonce_odr" => Some(LinkOnceODR),
+        "private" => Some(Private),
+        "weak" => Some(WeakAny),
+        "weak_odr" => Some(WeakODR),
+        _ => None,
+    }
+}
+
+/// Describes how a translation item will be instantiated in object files.
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
+pub enum InstantiationMode {
+    /// There will be exactly one instance of the given TransItem. It will have
+    /// external linkage so that it can be linked to from other codegen units.
+    GloballyShared {
+        /// In some compilation scenarios we may decide to take functions that
+        /// are typically `LocalCopy` and instead move them to `GloballyShared`
+        /// to avoid translating them a bunch of times. In this situation,
+        /// however, our local copy may conflict with other crates also
+        /// inlining the same function.
+        ///
+        /// This flag indicates that this situation is occuring, and informs
+        /// symbol name calculation that some extra mangling is needed to
+        /// avoid conflicts. Note that this may eventually go away entirely if
+        /// ThinLTO enables us to *always* have a globally shared instance of a
+        /// function within one crate's compilation.
+        may_conflict: bool,
+    },
+
+    /// Each codegen unit containing a reference to the given TransItem will
+    /// have its own private copy of the function (with internal linkage).
+    LocalCopy,
+}
+
+pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
+    fn as_trans_item(&self) -> &TransItem<'tcx>;
+
+    fn instantiation_mode(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> InstantiationMode {
+        let inline_in_all_cgus =
+            tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
+                tcx.sess.opts.optimize != OptLevel::No
+            });
+
+        match *self.as_trans_item() {
+            TransItem::Fn(ref instance) => {
+                // If this function isn't inlined or otherwise has explicit
+                // linkage, then we'll be creating a globally shared version.
+                if self.explicit_linkage(tcx).is_some() ||
+                    !common::requests_inline(tcx, instance)
+                {
+                    return InstantiationMode::GloballyShared  { may_conflict: false }
+                }
+
+                // At this point we don't have explicit linkage and we're an
+                // inlined function. If we're inlining into all CGUs then we'll
+                // be creating a local copy per CGU
+                if inline_in_all_cgus {
+                    return InstantiationMode::LocalCopy
+                }
+
+                // Finally, if this is `#[inline(always)]` we're sure to respect
+                // that with an inline copy per CGU, but otherwise we'll be
+                // creating one copy of this `#[inline]` function which may
+                // conflict with upstream crates as it could be an exported
+                // symbol.
+                let attrs = instance.def.attrs(tcx);
+                match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
+                    InlineAttr::Always => InstantiationMode::LocalCopy,
+                    _ => {
+                        InstantiationMode::GloballyShared  { may_conflict: true }
+                    }
+                }
+            }
+            TransItem::Static(..) => {
+                InstantiationMode::GloballyShared { may_conflict: false }
+            }
+            TransItem::GlobalAsm(..) => {
+                InstantiationMode::GloballyShared { may_conflict: false }
+            }
+        }
+    }
+
+    fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
+        let def_id = match *self.as_trans_item() {
+            TransItem::Fn(ref instance) => instance.def_id(),
+            TransItem::Static(node_id) => tcx.hir.local_def_id(node_id),
+            TransItem::GlobalAsm(..) => return None,
+        };
+
+        let attributes = tcx.get_attrs(def_id);
+        if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") {
+            if let Some(linkage) = linkage_by_name(&name.as_str()) {
+                Some(linkage)
+            } else {
+                let span = tcx.hir.span_if_local(def_id);
+                if let Some(span) = span {
+                    tcx.sess.span_fatal(span, "invalid linkage specified")
+                } else {
+                    tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
+                }
+            }
+        } else {
+            None
+        }
+    }
+
+    /// Returns whether this instance is instantiable - whether it has no unsatisfied
+    /// predicates.
+    ///
+    /// In order to translate an item, all of its predicates must hold, because
+    /// otherwise the item does not make sense. Type-checking ensures that
+    /// the predicates of every item that is *used by* a valid item *do*
+    /// hold, so we can rely on that.
+    ///
+    /// However, we translate collector roots (reachable items) and functions
+    /// in vtables when they are seen, even if they are not used, and so they
+    /// might not be instantiable. For example, a programmer can define this
+    /// public function:
+    ///
+    ///     pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+    ///         <&mut () as Clone>::clone(&s);
+    ///     }
+    ///
+    /// That function can't be translated, because the method `<&mut () as Clone>::clone`
+    /// does not exist. Luckily for us, that function can't ever be used,
+    /// because that would require for `&'a mut (): Clone` to hold, so we
+    /// can just not emit any code, or even a linker reference for it.
+    ///
+    /// Similarly, if a vtable method has such a signature, and therefore can't
+    /// be used, we can just not emit it and have a placeholder (a null pointer,
+    /// which will never be accessed) in its place.
+    fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+        debug!("is_instantiable({:?})", self);
+        let (def_id, substs) = match *self.as_trans_item() {
+            TransItem::Fn(ref instance) => (instance.def_id(), instance.substs),
+            TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()),
+            // global asm never has predicates
+            TransItem::GlobalAsm(..) => return true
+        };
+
+        let predicates = tcx.predicates_of(def_id).predicates.subst(tcx, substs);
+        traits::normalize_and_test_predicates(tcx, predicates)
+    }
+
+    fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
+        let hir_map = &tcx.hir;
+
+        return match *self.as_trans_item() {
+            TransItem::Fn(instance) => {
+                to_string_internal(tcx, "fn ", instance)
+            },
+            TransItem::Static(node_id) => {
+                let def_id = hir_map.local_def_id(node_id);
+                let instance = Instance::new(def_id, tcx.intern_substs(&[]));
+                to_string_internal(tcx, "static ", instance)
+            },
+            TransItem::GlobalAsm(..) => {
+                "global_asm".to_string()
+            }
+        };
+
+        fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                        prefix: &str,
+                                        instance: Instance<'tcx>)
+                                        -> String {
+            let mut result = String::with_capacity(32);
+            result.push_str(prefix);
+            let printer = DefPathBasedNames::new(tcx, false, false);
+            printer.push_instance_as_string(instance, &mut result);
+            result
+        }
+    }
+}
+
+impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {
+    fn as_trans_item(&self) -> &TransItem<'tcx> {
+        self
+    }
+}
+
+//=-----------------------------------------------------------------------------
+// TransItem String Keys
+//=-----------------------------------------------------------------------------
+
+// The code below allows for producing a unique string key for a trans item.
+// These keys are used by the handwritten auto-tests, so they need to be
+// predictable and human-readable.
+//
+// Note: A lot of this could looks very similar to what's already in the
+//       ppaux module. It would be good to refactor things so we only have one
+//       parameterizable implementation for printing types.
+
+/// Same as `unique_type_name()` but with the result pushed onto the given
+/// `output` parameter.
+pub struct DefPathBasedNames<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    omit_disambiguators: bool,
+    omit_local_crate_name: bool,
+}
+
+impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               omit_disambiguators: bool,
+               omit_local_crate_name: bool)
+               -> Self {
+        DefPathBasedNames {
+            tcx,
+            omit_disambiguators,
+            omit_local_crate_name,
+        }
+    }
+
+    pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
+        match t.sty {
+            ty::TyBool              => output.push_str("bool"),
+            ty::TyChar              => output.push_str("char"),
+            ty::TyStr               => output.push_str("str"),
+            ty::TyNever             => output.push_str("!"),
+            ty::TyInt(ast::IntTy::Is)    => output.push_str("isize"),
+            ty::TyInt(ast::IntTy::I8)    => output.push_str("i8"),
+            ty::TyInt(ast::IntTy::I16)   => output.push_str("i16"),
+            ty::TyInt(ast::IntTy::I32)   => output.push_str("i32"),
+            ty::TyInt(ast::IntTy::I64)   => output.push_str("i64"),
+            ty::TyInt(ast::IntTy::I128)   => output.push_str("i128"),
+            ty::TyUint(ast::UintTy::Us)   => output.push_str("usize"),
+            ty::TyUint(ast::UintTy::U8)   => output.push_str("u8"),
+            ty::TyUint(ast::UintTy::U16)  => output.push_str("u16"),
+            ty::TyUint(ast::UintTy::U32)  => output.push_str("u32"),
+            ty::TyUint(ast::UintTy::U64)  => output.push_str("u64"),
+            ty::TyUint(ast::UintTy::U128)  => output.push_str("u128"),
+            ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
+            ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
+            ty::TyAdt(adt_def, substs) => {
+                self.push_def_path(adt_def.did, output);
+                self.push_type_params(substs, iter::empty(), output);
+            },
+            ty::TyTuple(component_types, _) => {
+                output.push('(');
+                for &component_type in component_types {
+                    self.push_type_name(component_type, output);
+                    output.push_str(", ");
+                }
+                if !component_types.is_empty() {
+                    output.pop();
+                    output.pop();
+                }
+                output.push(')');
+            },
+            ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
+                output.push('*');
+                match mutbl {
+                    hir::MutImmutable => output.push_str("const "),
+                    hir::MutMutable => output.push_str("mut "),
+                }
+
+                self.push_type_name(inner_type, output);
+            },
+            ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
+                output.push('&');
+                if mutbl == hir::MutMutable {
+                    output.push_str("mut ");
+                }
+
+                self.push_type_name(inner_type, output);
+            },
+            ty::TyArray(inner_type, len) => {
+                output.push('[');
+                self.push_type_name(inner_type, output);
+                write!(output, "; {}",
+                    len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
+                output.push(']');
+            },
+            ty::TySlice(inner_type) => {
+                output.push('[');
+                self.push_type_name(inner_type, output);
+                output.push(']');
+            },
+            ty::TyDynamic(ref trait_data, ..) => {
+                if let Some(principal) = trait_data.principal() {
+                    self.push_def_path(principal.def_id(), output);
+                    self.push_type_params(principal.skip_binder().substs,
+                        trait_data.projection_bounds(),
+                        output);
+                }
+            },
+            ty::TyFnDef(..) |
+            ty::TyFnPtr(_) => {
+                let sig = t.fn_sig(self.tcx);
+                if sig.unsafety() == hir::Unsafety::Unsafe {
+                    output.push_str("unsafe ");
+                }
+
+                let abi = sig.abi();
+                if abi != ::syntax::abi::Abi::Rust {
+                    output.push_str("extern \"");
+                    output.push_str(abi.name());
+                    output.push_str("\" ");
+                }
+
+                output.push_str("fn(");
+
+                let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
+
+                if !sig.inputs().is_empty() {
+                    for &parameter_type in sig.inputs() {
+                        self.push_type_name(parameter_type, output);
+                        output.push_str(", ");
+                    }
+                    output.pop();
+                    output.pop();
+                }
+
+                if sig.variadic {
+                    if !sig.inputs().is_empty() {
+                        output.push_str(", ...");
+                    } else {
+                        output.push_str("...");
+                    }
+                }
+
+                output.push(')');
+
+                if !sig.output().is_nil() {
+                    output.push_str(" -> ");
+                    self.push_type_name(sig.output(), output);
+                }
+            },
+            ty::TyGenerator(def_id, ref closure_substs, _) |
+            ty::TyClosure(def_id, ref closure_substs) => {
+                self.push_def_path(def_id, output);
+                let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
+                let substs = closure_substs.substs.truncate_to(self.tcx, generics);
+                self.push_type_params(substs, iter::empty(), output);
+            }
+            ty::TyError |
+            ty::TyInfer(_) |
+            ty::TyProjection(..) |
+            ty::TyParam(_) |
+            ty::TyAnon(..) => {
+                bug!("DefPathBasedNames: Trying to create type name for \
+                                         unexpected type: {:?}", t);
+            }
+        }
+    }
+
+    pub fn push_def_path(&self,
+                         def_id: DefId,
+                         output: &mut String) {
+        let def_path = self.tcx.def_path(def_id);
+
+        // some_crate::
+        if !(self.omit_local_crate_name && def_id.is_local()) {
+            output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
+            output.push_str("::");
+        }
+
+        // foo::bar::ItemName::
+        for part in self.tcx.def_path(def_id).data {
+            if self.omit_disambiguators {
+                write!(output, "{}::", part.data.as_interned_str()).unwrap();
+            } else {
+                write!(output, "{}[{}]::",
+                       part.data.as_interned_str(),
+                       part.disambiguator).unwrap();
+            }
+        }
+
+        // remove final "::"
+        output.pop();
+        output.pop();
+    }
+
+    fn push_type_params<I>(&self,
+                            substs: &Substs<'tcx>,
+                            projections: I,
+                            output: &mut String)
+        where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
+    {
+        let mut projections = projections.peekable();
+        if substs.types().next().is_none() && projections.peek().is_none() {
+            return;
+        }
+
+        output.push('<');
+
+        for type_parameter in substs.types() {
+            self.push_type_name(type_parameter, output);
+            output.push_str(", ");
+        }
+
+        for projection in projections {
+            let projection = projection.skip_binder();
+            let name = &self.tcx.associated_item(projection.item_def_id).name.as_str();
+            output.push_str(name);
+            output.push_str("=");
+            self.push_type_name(projection.ty, output);
+            output.push_str(", ");
+        }
+
+        output.pop();
+        output.pop();
+
+        output.push('>');
+    }
+
+    pub fn push_instance_as_string(&self,
+                                   instance: Instance<'tcx>,
+                                   output: &mut String) {
+        self.push_def_path(instance.def_id(), output);
+        self.push_type_params(instance.substs, iter::empty(), output);
+    }
+}
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index af8cc2c806a..7c9497badfb 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -18,6 +18,7 @@ use hir;
 use hir::def::Def;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
+use namespace::Namespace;
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
@@ -827,8 +828,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let trait_did = bound.0.def_id;
         let (assoc_ident, def_scope) = tcx.adjust(assoc_name, trait_did, ref_id);
-        let item = tcx.associated_items(trait_did).find(|i| i.name.to_ident() == assoc_ident)
-                                                  .expect("missing associated type");
+        let item = tcx.associated_items(trait_did).find(|i| {
+            Namespace::from(i.kind) == Namespace::Type &&
+            i.name.to_ident() == assoc_ident
+        })
+        .expect("missing associated type");
 
         let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, bound);
         let ty = self.normalize_ty(span, ty);
@@ -1464,7 +1468,7 @@ impl<'tcx> ExplicitSelf<'tcx> {
     /// declaration like `self: SomeType` into either `self`,
     /// `&self`, `&mut self`, or `Box<self>`. We do this here
     /// by some simple pattern matching. A more precise check
-    /// is done later in `check_method_self_type()`.
+    /// is done later in `check_method_receiver()`.
     ///
     /// Examples:
     ///
@@ -1475,7 +1479,7 @@ impl<'tcx> ExplicitSelf<'tcx> {
     ///     fn method2(self: &T); // ExplicitSelf::ByValue
     ///     fn method3(self: Box<&T>); // ExplicitSelf::ByBox
     ///
-    ///     // Invalid cases will be caught later by `check_method_self_type`:
+    ///     // Invalid cases will be caught later by `check_method_receiver`:
     ///     fn method_err1(self: &mut T); // ExplicitSelf::ByReference
     /// }
     /// ```
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 7461df8bda5..91ce4511a31 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -271,6 +271,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                             fn_sig.output(),
                                             fn_sig.inputs());
         self.check_argument_types(call_expr.span,
+                                  call_expr.span,
                                   fn_sig.inputs(),
                                   &expected_arg_tys[..],
                                   arg_exprs,
@@ -298,6 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                fn_sig.inputs());
 
         self.check_argument_types(call_expr.span,
+                                  call_expr.span,
                                   fn_sig.inputs(),
                                   &expected_arg_tys,
                                   arg_exprs,
@@ -315,6 +317,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                method_callee: MethodCallee<'tcx>)
                                -> Ty<'tcx> {
         let output_type = self.check_method_argument_types(call_expr.span,
+                                                           call_expr.span,
                                                            Ok(method_callee),
                                                            arg_exprs,
                                                            TupleArgumentsFlag::TupleArguments,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index b21d4888612..554a858bcc1 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -568,15 +568,11 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let num_trait_m_type_params = trait_m_generics.types.len();
     if num_impl_m_type_params != num_trait_m_type_params {
         let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap();
-        let span = match tcx.hir.expect_impl_item(impl_m_node_id).node {
-            ImplItemKind::Method(ref impl_m_sig, _) => {
-                if impl_m_sig.generics.is_parameterized() {
-                    impl_m_sig.generics.span
-                } else {
-                    impl_m_span
-                }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
+        let impl_m_item = tcx.hir.expect_impl_item(impl_m_node_id);
+        let span = if impl_m_item.generics.is_parameterized() {
+            impl_m_item.generics.span
+        } else {
+            impl_m_span
         };
 
         let mut err = struct_span_err!(tcx.sess,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 3ddeba9d440..58d72e37d51 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -13,6 +13,7 @@
 use check::FnCtxt;
 use hir::def::Def;
 use hir::def_id::DefId;
+use namespace::Namespace;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
@@ -24,6 +25,8 @@ use syntax_pos::Span;
 
 use rustc::hir;
 
+use std::rc::Rc;
+
 pub use self::MethodError::*;
 pub use self::CandidateSource::*;
 
@@ -162,7 +165,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
+            Rc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
+                                        .unwrap().insert(import_def_id);
         }
 
         self.tcx.check_stability(pick.item.def_id, call_expr.id, span);
@@ -275,7 +279,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Trait must have a method named `m_name` and it should not have
         // type parameters or early-bound regions.
         let tcx = self.tcx;
-        let method_item = self.associated_item(trait_def_id, m_name).unwrap();
+        let method_item = self.associated_item(trait_def_id, m_name, Namespace::Value).unwrap();
         let def_id = method_item.def_id;
         let generics = tcx.generics_of(def_id);
         assert_eq!(generics.types.len(), 0);
@@ -360,7 +364,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some(import_id) = pick.import_id {
             let import_def_id = self.tcx.hir.local_def_id(import_id);
             debug!("used_trait_import: {:?}", import_def_id);
-            self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
+            Rc::get_mut(&mut self.tables.borrow_mut().used_trait_imports)
+                                        .unwrap().insert(import_def_id);
         }
 
         let def = pick.item.def();
@@ -371,10 +376,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     /// Find item with name `item_name` defined in impl/trait `def_id`
     /// and return it, or `None`, if no such item was defined there.
-    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name)
+    pub fn associated_item(&self, def_id: DefId, item_name: ast::Name, ns: Namespace)
                            -> Option<ty::AssociatedItem> {
         self.tcx.associated_items(def_id)
-                .find(|item| self.tcx.hygienic_eq(item_name, item.name, def_id))
-
+                .find(|item| Namespace::from(item.kind) == ns &&
+                             self.tcx.hygienic_eq(item_name, item.name, def_id))
     }
 }
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index a3b196f99d6..78941cb3a56 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -16,6 +16,7 @@ use super::suggest;
 use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
+use namespace::Namespace;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
@@ -1317,11 +1318,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                 self.tcx.associated_items(def_id)
                     .filter(|x| {
                         let dist = lev_distance(&*name.as_str(), &x.name.as_str());
-                        dist > 0 && dist <= max_dist
+                        Namespace::from(x.kind) == Namespace::Value && dist > 0
+                        && dist <= max_dist
                     })
                     .collect()
             } else {
-                self.fcx.associated_item(def_id, name).map_or(Vec::new(), |x| vec![x])
+                self.fcx
+                    .associated_item(def_id, name, Namespace::Value)
+                    .map_or(Vec::new(), |x| vec![x])
             }
         } else {
             self.tcx.associated_items(def_id).collect()
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 90c5297b399..23148406a11 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -17,6 +17,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use hir::def::Def;
 use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
+use namespace::Namespace;
 use rustc::traits::{Obligation, SelectionContext};
 use util::nodemap::FxHashSet;
 
@@ -92,12 +93,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     CandidateSource::ImplSource(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
-                        let item = self.associated_item(impl_did, item_name)
+                        let item = self.associated_item(impl_did, item_name, Namespace::Value)
                             .or_else(|| {
                                 self.associated_item(
                                     self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
-
-                                    item_name
+                                    item_name,
+                                    Namespace::Value,
                                 )
                             }).unwrap();
                         let note_span = self.tcx.hir.span_if_local(item.def_id).or_else(|| {
@@ -127,7 +128,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        let item = self.associated_item(trait_did, item_name).unwrap();
+                        let item = self
+                            .associated_item(trait_did, item_name, Namespace::Value)
+                            .unwrap();
                         let item_span = self.tcx.def_span(item.def_id);
                         span_note!(err,
                                    item_span,
@@ -402,7 +405,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // implementing a trait would be legal but is rejected
                 // here).
                 (type_is_local || info.def_id.is_local())
-                    && self.associated_item(info.def_id, item_name).is_some()
+                    && self.associated_item(info.def_id, item_name, Namespace::Value).is_some()
             })
             .collect::<Vec<_>>();
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9c6a4abfbd7..c82cafd3a62 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -88,6 +88,7 @@ use astconv::AstConv;
 use hir::def::{Def, CtorKind};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_back::slice::ref_slice;
+use namespace::Namespace;
 use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
@@ -105,9 +106,10 @@ use session::{CompileIncomplete, Session};
 use TypeAndSubsts;
 use lint;
 use util::common::{ErrorReported, indenter};
-use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
+use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, NodeMap};
 
 use std::cell::{Cell, RefCell, Ref, RefMut};
+use std::rc::Rc;
 use std::collections::hash_map::Entry;
 use std::cmp;
 use std::fmt::Display;
@@ -728,7 +730,7 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum
     debug_assert!(crate_num == LOCAL_CRATE);
     Ok(tcx.sess.track_errors(|| {
         for body_owner_def_id in tcx.body_owners() {
-            tcx.typeck_tables_of(body_owner_def_id);
+            ty::maps::queries::typeck_tables_of::ensure(tcx, body_owner_def_id);
         }
     })?)
 }
@@ -741,6 +743,7 @@ pub fn provide(providers: &mut Providers) {
         closure_kind,
         generator_sig,
         adt_destructor,
+        used_trait_imports,
         ..*providers
     };
 }
@@ -844,6 +847,12 @@ fn has_typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     primary_body_of(tcx, id).is_some()
 }
 
+fn used_trait_imports<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              def_id: DefId)
+                              -> Rc<DefIdSet> {
+    tcx.typeck_tables_of(def_id).used_trait_imports.clone()
+}
+
 fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               def_id: DefId)
                               -> &'tcx ty::TypeckTables<'tcx> {
@@ -1293,7 +1302,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     for impl_item in impl_items() {
         let ty_impl_item = tcx.associated_item(tcx.hir.local_def_id(impl_item.id));
         let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id)
-            .find(|ac| tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id));
+            .find(|ac| Namespace::from(&impl_item.node) == Namespace::from(ac.kind) &&
+                         tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id))
+            .or_else(|| {
+                // Not compatible, but needed for the error message
+                tcx.associated_items(impl_trait_ref.def_id)
+                   .find(|ac| tcx.hygienic_eq(ty_impl_item.name, ac.name, impl_trait_ref.def_id))
+            });
 
         // Check that impl definition matches trait definition
         if let Some(ty_trait_item) = ty_trait_item {
@@ -2352,6 +2367,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     fn check_method_argument_types(&self,
                                    sp: Span,
+                                   expr_sp: Span,
                                    method: Result<MethodCallee<'tcx>, ()>,
                                    args_no_rcvr: &'gcx [hir::Expr],
                                    tuple_arguments: TupleArgumentsFlag,
@@ -2371,7 +2387,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..], false)],
             };
 
-            self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
+            self.check_argument_types(sp, expr_sp, &err_inputs[..], &[], args_no_rcvr,
                                       false, tuple_arguments, None);
             return self.tcx.types.err;
         }
@@ -2384,7 +2400,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             method.sig.output(),
             &method.sig.inputs()[1..]
         );
-        self.check_argument_types(sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
+        self.check_argument_types(sp, expr_sp, &method.sig.inputs()[1..], &expected_arg_tys[..],
                                   args_no_rcvr, method.sig.variadic, tuple_arguments,
                                   self.tcx.hir.span_if_local(method.def_id));
         method.sig.output()
@@ -2394,6 +2410,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// method calls and overloaded operators.
     fn check_argument_types(&self,
                             sp: Span,
+                            expr_sp: Span,
                             fn_inputs: &[Ty<'tcx>],
                             expected_arg_tys: &[Ty<'tcx>],
                             args: &'gcx [hir::Expr],
@@ -2434,9 +2451,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             sp
         };
 
-        fn parameter_count_error<'tcx>(sess: &Session, sp: Span, expected_count: usize,
-                                       arg_count: usize, error_code: &str, variadic: bool,
-                                       def_span: Option<Span>, sugg_unit: bool) {
+        fn parameter_count_error<'tcx>(sess: &Session,
+                                       sp: Span,
+                                       expr_sp: Span,
+                                       expected_count: usize,
+                                       arg_count: usize,
+                                       error_code: &str,
+                                       variadic: bool,
+                                       def_span: Option<Span>,
+                                       sugg_unit: bool) {
             let mut err = sess.struct_span_err_with_code(sp,
                 &format!("this function takes {}{} parameter{} but {} parameter{} supplied",
                     if variadic {"at least "} else {""},
@@ -2450,12 +2473,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 err.span_label(def_s, "defined here");
             }
             if sugg_unit {
-                let sugg_span = sp.end_point();
+                let sugg_span = expr_sp.end_point();
                 // remove closing `)` from the span
                 let sugg_span = sugg_span.with_hi(sugg_span.lo());
                 err.span_suggestion(
                     sugg_span,
-                    "expected the unit value `()`. You can create one with a pair of parenthesis",
+                    "expected the unit value `()`; create it with empty parentheses",
                     String::from("()"));
             } else {
                 err.span_label(sp, format!("expected {}{} parameter{}",
@@ -2470,7 +2493,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
             match tuple_type.sty {
                 ty::TyTuple(arg_types, _) if arg_types.len() != args.len() => {
-                    parameter_count_error(tcx.sess, sp_args, arg_types.len(), args.len(),
+                    parameter_count_error(tcx.sess, sp_args, expr_sp, arg_types.len(), args.len(),
                                           "E0057", false, def_span, false);
                     expected_arg_tys = &[];
                     self.err_args(args.len())
@@ -2499,7 +2522,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if supplied_arg_count >= expected_arg_count {
                 fn_inputs.to_vec()
             } else {
-                parameter_count_error(tcx.sess, sp_args, expected_arg_count,
+                parameter_count_error(tcx.sess, sp_args, expr_sp, expected_arg_count,
                                       supplied_arg_count, "E0060", true, def_span, false);
                 expected_arg_tys = &[];
                 self.err_args(supplied_arg_count)
@@ -2513,7 +2536,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             } else {
                 false
             };
-            parameter_count_error(tcx.sess, sp_args, expected_arg_count,
+            parameter_count_error(tcx.sess, sp_args, expr_sp, expected_arg_count,
                                   supplied_arg_count, "E0061", false, def_span, sugg_unit);
             expected_arg_tys = &[];
             self.err_args(supplied_arg_count)
@@ -2866,7 +2889,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         };
 
         // Call the generic checker.
-        self.check_method_argument_types(span, method,
+        self.check_method_argument_types(span,
+                                         expr.span,
+                                         method,
                                          &args[1..],
                                          DontTupleArguments,
                                          expected)
@@ -4274,6 +4299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
         };
 
+        let prev_diverges = self.diverges.get();
         let ctxt = BreakableCtxt {
             coerce: Some(coerce),
             may_break: false,
@@ -4323,6 +4349,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         });
 
+        if ctxt.may_break {
+            // If we can break from the block, then the block's exit is always reachable
+            // (... as long as the entry is reachable) - regardless of the tail of the block.
+            self.diverges.set(prev_diverges);
+        }
+
         let mut ty = ctxt.coerce.unwrap().complete(self);
 
         if self.has_errors.get() || ty.references_error() {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 609af638e97..ad7978480a6 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -815,7 +815,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
                 // the type of the node expr.id here *before applying
                 // adjustments*.
                 //
-                // FIXME(#6268) nested method calls requires that this rule change
+                // FIXME(https://github.com/rust-lang/rfcs/issues/811)
+                // nested method calls requires that this rule change
                 let ty0 = self.resolve_node_type(expr.hir_id);
                 self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region);
                 intravisit::walk_expr(self, expr);
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index b3648d357e5..ce2ac73a27e 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -23,6 +23,7 @@ use rustc::util::nodemap::DefIdSet;
 use syntax::ast;
 use syntax_pos::Span;
 use std::mem;
+use std::rc::Rc;
 
 ///////////////////////////////////////////////////////////////////////////
 // Entry point
@@ -49,7 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_generator_interiors();
 
         let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
-                                              DefIdSet());
+                                              Rc::new(DefIdSet()));
         debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
         wbcx.tables.used_trait_imports = used_trait_imports;
 
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 0c35b5e6834..b867a655b4a 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -66,10 +66,9 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut used_trait_imports = DefIdSet();
     for &body_id in tcx.hir.krate().bodies.keys() {
         let item_def_id = tcx.hir.body_owner_def_id(body_id);
-        let tables = tcx.typeck_tables_of(item_def_id);
-        let imports = &tables.used_trait_imports;
+        let imports = tcx.used_trait_imports(item_def_id);
         debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
-        used_trait_imports.extend(imports);
+        used_trait_imports.extend(imports.iter());
     }
 
     let mut visitor = CheckVisitor { tcx, used_trait_imports };
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index 76dcfe36e4f..1355f711a4b 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use namespace::Namespace;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::traits;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::TyCtxt;
 
 pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     crate_num: CrateNum) {
@@ -28,19 +29,10 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> {
 impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
     fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId,
                                        overlap: traits::OverlapResult) {
-        #[derive(Copy, Clone, PartialEq)]
-        enum Namespace {
-            Type,
-            Value,
-        }
 
         let name_and_namespace = |def_id| {
             let item = self.tcx.associated_item(def_id);
-            (item.name, match item.kind {
-                ty::AssociatedKind::Type => Namespace::Type,
-                ty::AssociatedKind::Const |
-                ty::AssociatedKind::Method => Namespace::Value,
-            })
+            (item.name, Namespace::from(item.kind))
         };
 
         let impl_items1 = self.tcx.associated_item_def_ids(impl1);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 25a37a2c48c..68ba1b4c44c 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -261,19 +261,9 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
     let ast_generics = match tcx.hir.get(item_node_id) {
-        NodeTraitItem(item) => {
-            match item.node {
-                TraitItemKind::Method(ref sig, _) => &sig.generics,
-                _ => return result
-            }
-        }
+        NodeTraitItem(item) => &item.generics,
 
-        NodeImplItem(item) => {
-            match item.node {
-                ImplItemKind::Method(ref sig, _) => &sig.generics,
-                _ => return result
-            }
-        }
+        NodeImplItem(item) => &item.generics,
 
         NodeItem(item) => {
             match item.node {
@@ -818,12 +808,12 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     match node {
         hir_map::NodeTraitItem(item) => match item.node {
             hir::TraitItemKind::Method(ref sig, _) =>
-                has_late_bound_regions(tcx, &sig.generics, &sig.decl),
+                has_late_bound_regions(tcx, &item.generics, &sig.decl),
             _ => None,
         },
         hir_map::NodeImplItem(item) => match item.node {
             hir::ImplItemKind::Method(ref sig, _) =>
-                has_late_bound_regions(tcx, &sig.generics, &sig.decl),
+                has_late_bound_regions(tcx, &item.generics, &sig.decl),
             _ => None,
         },
         hir_map::NodeForeignItem(item) => match item.node {
@@ -881,19 +871,9 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let no_generics = hir::Generics::empty();
     let ast_generics = match node {
-        NodeTraitItem(item) => {
-            match item.node {
-                TraitItemKind::Method(ref sig, _) => &sig.generics,
-                _ => &no_generics
-            }
-        }
+        NodeTraitItem(item) => &item.generics,
 
-        NodeImplItem(item) => {
-            match item.node {
-                ImplItemKind::Method(ref sig, _) => &sig.generics,
-                _ => &no_generics
-            }
-        }
+        NodeImplItem(item) => &item.generics,
 
         NodeItem(item) => {
             match item.node {
@@ -1332,7 +1312,11 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
 fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            def_id: DefId)
                            -> ty::GenericPredicates<'tcx> {
-    explicit_predicates_of(tcx, def_id)
+    let explicit = explicit_predicates_of(tcx, def_id);
+    ty::GenericPredicates {
+        parent: explicit.parent,
+        predicates: [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
+    }
 }
 
 fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -1349,19 +1333,9 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let icx = ItemCtxt::new(tcx, def_id);
     let no_generics = hir::Generics::empty();
     let ast_generics = match node {
-        NodeTraitItem(item) => {
-            match item.node {
-                TraitItemKind::Method(ref sig, _) => &sig.generics,
-                _ => &no_generics
-            }
-        }
+        NodeTraitItem(item) => &item.generics,
 
-        NodeImplItem(item) => {
-            match item.node {
-                ImplItemKind::Method(ref sig, _) => &sig.generics,
-                _ => &no_generics
-            }
-        }
+        NodeImplItem(item) => &item.generics,
 
         NodeItem(item) => {
             match item.node {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 8df97355574..594cd0878cb 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3986,6 +3986,10 @@ details.
 "##,
 
 E0599: r##"
+This error occurs when a method is used on a type which doesn't implement it:
+
+Erroneous code example:
+
 ```compile_fail,E0599
 struct Mouth;
 
@@ -4676,6 +4680,7 @@ register_diagnostics! {
     E0588, // packed struct cannot transitively contain a `[repr(align)]` struct
     E0592, // duplicate definitions with name `{}`
 //  E0613, // Removed (merged with E0609)
+    E0640, // infer outlives
     E0627, // yield statement outside of generator literal
     E0632, // cannot provide explicit type parameters when `impl Trait` is used in
            // argument position.
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 7a6ee73b9b9..49ba0499f78 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -50,6 +50,8 @@ independently:
 
 - variance: variance inference
 
+- outlives: outlives inference
+
 - check: walks over function bodies and type checks them, inferring types for
   local variables, type parameters, etc as necessary.
 
@@ -122,7 +124,9 @@ mod collect;
 mod constrained_type_params;
 mod impl_wf_check;
 mod coherence;
+mod outlives;
 mod variance;
+mod namespace;
 
 pub struct TypeAndSubsts<'tcx> {
     substs: &'tcx Substs<'tcx>,
@@ -285,6 +289,7 @@ pub fn provide(providers: &mut Providers) {
     coherence::provide(providers);
     check::provide(providers);
     variance::provide(providers);
+    outlives::provide(providers);
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
@@ -301,6 +306,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
     })?;
 
     tcx.sess.track_errors(|| {
+        time(time_passes, "outlives testing", ||
+            outlives::test::test_inferred_outlives(tcx));
+    })?;
+
+    tcx.sess.track_errors(|| {
         time(time_passes, "impl wf inference", ||
              impl_wf_check::impl_wf_check(tcx));
     })?;
diff --git a/src/librustc_typeck/namespace.rs b/src/librustc_typeck/namespace.rs
new file mode 100644
index 00000000000..6f0e46b3afe
--- /dev/null
+++ b/src/librustc_typeck/namespace.rs
@@ -0,0 +1,39 @@
+// 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 rustc::hir;
+use rustc::ty;
+
+// Whether an item exists in the type or value namespace.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Namespace {
+    Type,
+    Value,
+}
+
+impl From<ty::AssociatedKind> for Namespace {
+    fn from(a_kind: ty::AssociatedKind) -> Self {
+        match a_kind {
+            ty::AssociatedKind::Type => Namespace::Type,
+            ty::AssociatedKind::Const |
+            ty::AssociatedKind::Method => Namespace::Value,
+        }
+    }
+}
+
+impl<'a> From <&'a hir::ImplItemKind> for Namespace {
+    fn from(impl_kind: &'a hir::ImplItemKind) -> Self {
+        match *impl_kind {
+            hir::ImplItemKind::Type(..) => Namespace::Type,
+            hir::ImplItemKind::Const(..) |
+            hir::ImplItemKind::Method(..) => Namespace::Value,
+        }
+    }
+}
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
new file mode 100644
index 00000000000..1127028cbc8
--- /dev/null
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -0,0 +1,29 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::maps::Providers;
+
+/// Code to write unit test for outlives.
+pub mod test;
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        inferred_outlives_of,
+        ..*providers
+    };
+}
+
+//todo
+fn inferred_outlives_of<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId)
+                                  -> Vec<ty::Predicate<'tcx>> {
+    Vec::new()
+}
diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs
new file mode 100644
index 00000000000..196e6605494
--- /dev/null
+++ b/src/librustc_typeck/outlives/test.rs
@@ -0,0 +1,41 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ty::TyCtxt;
+
+pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    tcx.hir.krate().visit_all_item_likes(&mut OutlivesTest { tcx });
+}
+
+struct OutlivesTest<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        let item_def_id = self.tcx.hir.local_def_id(item.id);
+
+        // For unit testing: check for a special "rustc_outlives"
+        // attribute and report an error with various results if found.
+        if self.tcx.has_attr(item_def_id, "rustc_outlives") {
+            let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
+            span_err!(self.tcx.sess,
+                      item.span,
+                      E0640,
+                      "{:?}",
+                      inferred_outlives_of);
+        }
+    }
+
+    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { }
+    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
+}
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index b295b414a03..e168222058f 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -18,4 +18,4 @@ html-diff = "0.0.4"
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0"
+cc = "1.0.1"
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index da8c3a5cf20..e3ce403f3c1 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -337,7 +337,6 @@ impl<'a> fmt::Display for Html<'a> {
                         "l4re" => "L4Re",
                         "linux" => "Linux",
                         "macos" => "macOS",
-                        "nacl" => "NaCl",
                         "netbsd" => "NetBSD",
                         "openbsd" => "OpenBSD",
                         "redox" => "Redox",
@@ -886,4 +885,4 @@ mod test {
                 only."
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c9afa3646b2..4e8bf5f9109 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -112,6 +112,7 @@ impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
 #[derive(Clone, Debug)]
 pub struct Crate {
     pub name: String,
+    pub version: Option<String>,
     pub src: PathBuf,
     pub module: Option<Item>,
     pub externs: Vec<(CrateNum, ExternalCrate)>,
@@ -183,6 +184,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
 
         Crate {
             name,
+            version: None,
             src,
             module: Some(module),
             externs,
@@ -236,6 +238,7 @@ impl Clean<ExternalCrate> for CrateNum {
                             if prim.is_some() {
                                 break;
                             }
+                            // FIXME: should warn on unknown primitives?
                         }
                     }
                 }
@@ -1138,13 +1141,13 @@ pub struct Method {
     pub abi: Abi,
 }
 
-impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
+impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
     fn clean(&self, cx: &DocContext) -> Method {
         Method {
-            generics: self.0.generics.clean(cx),
+            generics: self.1.clean(cx),
             unsafety: self.0.unsafety,
             constness: self.0.constness,
-            decl: (&*self.0.decl, self.1).clean(cx),
+            decl: (&*self.0.decl, self.2).clean(cx),
             abi: self.0.abi
         }
     }
@@ -1377,13 +1380,13 @@ impl Clean<Item> for hir::TraitItem {
                                     default.map(|e| print_const_expr(cx, e)))
             }
             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
-                MethodItem((sig, body).clean(cx))
+                MethodItem((sig, &self.generics, body).clean(cx))
             }
             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
                 TyMethodItem(TyMethod {
                     unsafety: sig.unsafety.clone(),
                     decl: (&*sig.decl, &names[..]).clean(cx),
-                    generics: sig.generics.clean(cx),
+                    generics: self.generics.clean(cx),
                     abi: sig.abi
                 })
             }
@@ -1412,7 +1415,7 @@ impl Clean<Item> for hir::ImplItem {
                                     Some(print_const_expr(cx, expr)))
             }
             hir::ImplItemKind::Method(ref sig, body) => {
-                MethodItem((sig, body).clean(cx))
+                MethodItem((sig, &self.generics, body).clean(cx))
             }
             hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
                 type_: ty.clean(cx),
@@ -1625,6 +1628,7 @@ pub enum PrimitiveType {
     Slice,
     Array,
     Tuple,
+    Unit,
     RawPointer,
     Reference,
     Fn,
@@ -1660,7 +1664,11 @@ impl Type {
             Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
             Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
             Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
-            Tuple(..) => Some(PrimitiveType::Tuple),
+            Tuple(ref tys) => if tys.is_empty() {
+                Some(PrimitiveType::Unit)
+            } else {
+                Some(PrimitiveType::Tuple)
+            },
             RawPointer(..) => Some(PrimitiveType::RawPointer),
             BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
             BareFunction(..) => Some(PrimitiveType::Fn),
@@ -1681,6 +1689,21 @@ impl Type {
             _ => false
         }
     }
+
+    pub fn generics(&self) -> Option<&[Type]> {
+        match *self {
+            ResolvedPath { ref path, .. } => {
+                path.segments.last().and_then(|seg| {
+                    if let PathParameters::AngleBracketed { ref types, .. } = seg.params {
+                        Some(&**types)
+                    } else {
+                        None
+                    }
+                })
+            }
+            _ => None,
+        }
+    }
 }
 
 impl GetDefId for Type {
@@ -1691,7 +1714,11 @@ impl GetDefId for Type {
             BorrowedRef { type_: box Generic(..), .. } =>
                 Primitive(PrimitiveType::Reference).def_id(),
             BorrowedRef { ref type_, .. } => type_.def_id(),
-            Tuple(..) => Primitive(PrimitiveType::Tuple).def_id(),
+            Tuple(ref tys) => if tys.is_empty() {
+                Primitive(PrimitiveType::Unit).def_id()
+            } else {
+                Primitive(PrimitiveType::Tuple).def_id()
+            },
             BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
             Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
             Array(..) => Primitive(PrimitiveType::Array).def_id(),
@@ -1725,6 +1752,7 @@ impl PrimitiveType {
             "array" => Some(PrimitiveType::Array),
             "slice" => Some(PrimitiveType::Slice),
             "tuple" => Some(PrimitiveType::Tuple),
+            "unit" => Some(PrimitiveType::Unit),
             "pointer" => Some(PrimitiveType::RawPointer),
             "reference" => Some(PrimitiveType::Reference),
             "fn" => Some(PrimitiveType::Fn),
@@ -1755,6 +1783,7 @@ impl PrimitiveType {
             Array => "array",
             Slice => "slice",
             Tuple => "tuple",
+            Unit => "unit",
             RawPointer => "pointer",
             Reference => "reference",
             Fn => "fn",
@@ -2491,7 +2520,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
                 type_params: Vec::new(),
                 where_predicates: Vec::new()
             },
-            decl: (&*self.decl, &[][..]).clean(cx),
+            decl: (&*self.decl, &self.arg_names[..]).clean(cx),
             abi: self.abi,
         }
     }
@@ -2676,6 +2705,7 @@ fn build_deref_target_impls(cx: &DocContext,
             Slice => tcx.lang_items().slice_impl(),
             Array => tcx.lang_items().slice_impl(),
             Tuple => None,
+            Unit => None,
             RawPointer => tcx.lang_items().const_ptr_impl(),
             Reference => None,
             Fn => None,
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 111ae4ede27..2f7bd5e39a1 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -10,7 +10,6 @@
 
 use std::fs::File;
 use std::io::prelude::*;
-use std::io;
 use std::path::Path;
 use std::str;
 use html::markdown::{Markdown, RenderType};
@@ -70,17 +69,13 @@ pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringErr
     let result = File::open(file_path)
                       .and_then(|mut f| f.read_to_end(&mut contents));
     if let Err(e) = result {
-        let _ = writeln!(&mut io::stderr(),
-                         "error reading `{}`: {}",
-                         file_path.display(), e);
+        eprintln!("error reading `{}`: {}", file_path.display(), e);
         return Err(LoadStringError::ReadFail);
     }
     match str::from_utf8(&contents) {
         Ok(s) => Ok(s.to_string()),
         Err(_) => {
-            let _ = writeln!(&mut io::stderr(),
-                             "error reading `{}`: not UTF-8",
-                             file_path.display());
+            eprintln!("error reading `{}`: not UTF-8", file_path.display());
             Err(LoadStringError::BadUtf8)
         }
     }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6303fd662bf..18d6b1cc1e0 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -614,7 +614,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
         }
         clean::Tuple(ref typs) => {
             match &typs[..] {
-                &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
+                &[] => primitive_link(f, PrimitiveType::Unit, "()"),
                 &[ref one] => {
                     primitive_link(f, PrimitiveType::Tuple, "(")?;
                     //carry f.alternate() into this display w/o branching manually
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index d08a7bde71c..79eaabe31e8 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -97,10 +97,12 @@ r##"<!DOCTYPE html>
                     <dd>Show this help dialog</dd>
                     <dt>S</dt>
                     <dd>Focus the search field</dd>
-                    <dt>&larrb;</dt>
+                    <dt>↑</dt>
                     <dd>Move up in search results</dd>
-                    <dt>&rarrb;</dt>
+                    <dt>↓</dt>
                     <dd>Move down in search results</dd>
+                    <dt>↹</dt>
+                    <dd>Switch tab</dd>
                     <dt>&#9166;</dt>
                     <dd>Go to active search result</dd>
                     <dt>+</dt>
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index a3f446885f9..d538428a7e9 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -125,6 +125,21 @@ pub struct SharedContext {
     /// Warnings for the user if rendering would differ using different markdown
     /// parsers.
     pub markdown_warnings: RefCell<Vec<(Span, String, Vec<html_diff::Difference>)>>,
+    /// The directories that have already been created in this doc run. Used to reduce the number
+    /// of spurious `create_dir_all` calls.
+    pub created_dirs: RefCell<FxHashSet<PathBuf>>,
+}
+
+impl SharedContext {
+    fn ensure_dir(&self, dst: &Path) -> io::Result<()> {
+        let mut dirs = self.created_dirs.borrow_mut();
+        if !dirs.contains(dst) {
+            fs::create_dir_all(dst)?;
+            dirs.insert(dst.to_path_buf());
+        }
+
+        Ok(())
+    }
 }
 
 /// Indicates where an external crate can be found.
@@ -256,6 +271,9 @@ pub struct Cache {
     // the access levels from crateanalysis.
     pub access_levels: Arc<AccessLevels<DefId>>,
 
+    /// The version of the crate being documented, if given fron the `--crate-version` flag.
+    pub crate_version: Option<String>,
+
     // Private fields only used when initially crawling a crate to build a cache
 
     stack: Vec<String>,
@@ -460,6 +478,7 @@ pub fn run(mut krate: clean::Crate,
         },
         css_file_extension: css_file_extension.clone(),
         markdown_warnings: RefCell::new(vec![]),
+        created_dirs: RefCell::new(FxHashSet()),
     };
 
     // If user passed in `--playground-url` arg, we fill in crate name here
@@ -534,6 +553,7 @@ pub fn run(mut krate: clean::Crate,
         primitive_locations: FxHashMap(),
         stripped_mod: false,
         access_levels: krate.access_levels.clone(),
+        crate_version: krate.version.take(),
         orphan_impl_items: Vec::new(),
         traits: mem::replace(&mut krate.external_traits, FxHashMap()),
         deref_trait_did,
@@ -790,7 +810,6 @@ fn write_shared(cx: &Context,
     // Write out the shared files. Note that these are shared among all rustdoc
     // docs placed in the output directory, so this needs to be a synchronized
     // operation with respect to all other rustdocs running around.
-    try_err!(fs::create_dir_all(&cx.dst), &cx.dst);
     let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true);
 
     // Add all the static files. These may already exist, but we just
@@ -1306,7 +1325,8 @@ impl DocFolder for Cache {
                 // Figure out the id of this impl. This may map to a
                 // primitive rather than always to a struct/enum.
                 // Note: matching twice to restrict the lifetime of the `i` borrow.
-                let did = if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
+                let mut dids = vec![];
+                if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
                     let masked_trait = i.trait_.def_id().map_or(false,
                         |d| self.masked_crates.contains(&d.krate));
                     if !masked_trait {
@@ -1315,23 +1335,33 @@ impl DocFolder for Cache {
                             clean::BorrowedRef {
                                 type_: box clean::ResolvedPath { did, .. }, ..
                             } => {
-                                Some(did)
+                                dids.push(did);
                             }
                             ref t => {
-                                t.primitive_type().and_then(|t| {
+                                let did = t.primitive_type().and_then(|t| {
                                     self.primitive_locations.get(&t).cloned()
-                                })
+                                });
+
+                                if let Some(did) = did {
+                                    dids.push(did);
+                                }
+                            }
+                        }
+                    }
+
+                    if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
+                        for bound in generics {
+                            if let Some(did) = bound.def_id() {
+                                dids.push(did);
                             }
                         }
-                    } else {
-                        None
                     }
                 } else {
                     unreachable!()
                 };
-                if let Some(did) = did {
+                for did in dids {
                     self.impls.entry(did).or_insert(vec![]).push(Impl {
-                        impl_item: item,
+                        impl_item: item.clone(),
                     });
                 }
                 None
@@ -1503,8 +1533,8 @@ impl Context {
                 this.render_item(&mut buf, &item, false).unwrap();
                 // buf will be empty if the module is stripped and there is no redirect for it
                 if !buf.is_empty() {
+                    try_err!(this.shared.ensure_dir(&this.dst), &this.dst);
                     let joint_dst = this.dst.join("index.html");
-                    try_err!(fs::create_dir_all(&this.dst), &this.dst);
                     let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
                     try_err!(dst.write_all(&buf), &joint_dst);
                 }
@@ -1538,8 +1568,8 @@ impl Context {
                 let name = item.name.as_ref().unwrap();
                 let item_type = item.type_();
                 let file_name = &item_path(item_type, name);
+                try_err!(self.shared.ensure_dir(&self.dst), &self.dst);
                 let joint_dst = self.dst.join(file_name);
-                try_err!(fs::create_dir_all(&self.dst), &self.dst);
                 let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
                 try_err!(dst.write_all(&buf), &joint_dst);
 
@@ -1547,9 +1577,10 @@ impl Context {
                 // URL for the page.
                 let redir_name = format!("{}.{}.html", name, item_type.name_space());
                 let redir_dst = self.dst.join(redir_name);
-                if let Ok(mut redirect_out) = OpenOptions::new().create_new(true)
+                if let Ok(redirect_out) = OpenOptions::new().create_new(true)
                                                                 .write(true)
                                                                 .open(&redir_dst) {
+                    let mut redirect_out = BufWriter::new(redirect_out);
                     try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
                 }
 
@@ -1559,7 +1590,8 @@ impl Context {
                 if item_type == ItemType::Macro {
                     let redir_name = format!("{}.{}!.html", item_type, name);
                     let redir_dst = self.dst.join(redir_name);
-                    let mut redirect_out = try_err!(File::create(&redir_dst), &redir_dst);
+                    let redirect_out = try_err!(File::create(&redir_dst), &redir_dst);
+                    let mut redirect_out = BufWriter::new(redirect_out);
                     try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
                 }
             }
@@ -1794,37 +1826,32 @@ fn render_markdown(w: &mut fmt::Formatter,
                    prefix: &str,
                    scx: &SharedContext)
                    -> fmt::Result {
-    // We only emit warnings if the user has opted-in to Pulldown rendering.
-    let output = if render_type == RenderType::Pulldown {
-        // Save the state of USED_ID_MAP so it only gets updated once even
-        // though we're rendering twice.
-        let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
-        let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
-        USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
-        let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
-        let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
-        differences.retain(|s| {
-            match *s {
-                html_diff::Difference::NodeText { ref elem_text,
-                                                  ref opposite_elem_text,
-                                                  .. }
-                    if elem_text.split_whitespace().eq(opposite_elem_text.split_whitespace()) => {
-                        false
-                }
-                _ => true,
+    // Save the state of USED_ID_MAP so it only gets updated once even
+    // though we're rendering twice.
+    let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+    let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+    USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
+    let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
+    let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
+    differences.retain(|s| {
+        match *s {
+            html_diff::Difference::NodeText { ref elem_text,
+                                              ref opposite_elem_text,
+                                              .. }
+                if elem_text.split_whitespace().eq(opposite_elem_text.split_whitespace()) => {
+                    false
             }
-        });
-
-        if !differences.is_empty() {
-            scx.markdown_warnings.borrow_mut().push((span, md_text.to_owned(), differences));
+            _ => true,
         }
+    });
 
-        pulldown_output
-    } else {
-        format!("{}", Markdown(md_text, RenderType::Hoedown))
-    };
+    if !differences.is_empty() {
+        scx.markdown_warnings.borrow_mut().push((span, md_text.to_owned(), differences));
+    }
 
-    write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
+    write!(w, "<div class='docblock'>{}{}</div>",
+           prefix,
+           if render_type == RenderType::Pulldown { pulldown_output } else { hoedown_output })
 }
 
 fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
@@ -3422,6 +3449,16 @@ impl<'a> fmt::Display for Sidebar<'a> {
             write!(fmt, "{}", it.name.as_ref().unwrap())?;
             write!(fmt, "</p>")?;
 
+            if it.is_crate() {
+                if let Some(ref version) = cache().crate_version {
+                    write!(fmt,
+                           "<div class='block version'>\
+                            <p>Version {}</p>\
+                            </div>",
+                           version)?;
+                }
+            }
+
             match it.inner {
                 clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?,
                 clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?,
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index da4430d8a15..04bf466a780 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -39,6 +39,13 @@
                      "associatedconstant",
                      "union"];
 
+    // On the search screen, so you remain on the last tab you opened.
+    //
+    // 0 for "Types/modules"
+    // 1 for "As parameters"
+    // 2 for "As return value"
+    var currentTab = 0;
+
     function hasClass(elem, className) {
         if (elem && className && elem.className) {
             var elemClass = elem.className;
@@ -163,6 +170,20 @@
         return String.fromCharCode(c);
     }
 
+    function displayHelp(display, ev) {
+        if (display === true) {
+            if (hasClass(help, "hidden")) {
+                ev.preventDefault();
+                removeClass(help, "hidden");
+                addClass(document.body, "blur");
+            }
+        } else if (!hasClass(help, "hidden")) {
+            ev.preventDefault();
+            addClass(help, "hidden");
+            removeClass(document.body, "blur");
+        }
+    }
+
     function handleShortcut(ev) {
         if (document.activeElement.tagName === "INPUT")
             return;
@@ -176,9 +197,7 @@
         case "Escape":
             var search = document.getElementById("search");
             if (!hasClass(help, "hidden")) {
-                ev.preventDefault();
-                addClass(help, "hidden");
-                removeClass(document.body, "blur");
+                displayHelp(false, ev);
             } else if (!hasClass(search, "hidden")) {
                 ev.preventDefault();
                 addClass(search, "hidden");
@@ -188,6 +207,7 @@
 
         case "s":
         case "S":
+            displayHelp(false, ev);
             ev.preventDefault();
             focusSearchBar();
             break;
@@ -198,10 +218,8 @@
             break;
 
         case "?":
-            if (ev.shiftKey && hasClass(help, "hidden")) {
-                ev.preventDefault();
-                removeClass(help, "hidden");
-                addClass(document.body, "blur");
+            if (ev.shiftKey) {
+                displayHelp(true, ev);
             }
             break;
         }
@@ -342,6 +360,17 @@
                 }
             }
 
+            function findArg(obj, val) {
+                if (obj && obj.type && obj.type.inputs.length > 0) {
+                    for (var i = 0; i < obj.type.inputs.length; i++) {
+                        if (obj.type.inputs[i].name === val) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            }
+
             function typePassesFilter(filter, type) {
                 // No filter
                 if (filter < 0) return true;
@@ -376,18 +405,28 @@
                         if (typePassesFilter(typeFilter, searchIndex[i].ty)) {
                             results.push({id: i, index: -1});
                         }
+                    } else if (findArg(searchIndex[i], val.toLowerCase()) ||
+                               (searchIndex[i].type &&
+                                searchIndex[i].type.output &&
+                                searchIndex[i].type.output.name === val.toLowerCase())) {
+                        if (typePassesFilter(typeFilter, searchIndex[i].ty)) {
+                            results.push({id: i, index: -1, dontValidate: true});
+                        }
                     }
                     if (results.length === max) {
                         break;
                     }
                 }
+                query.inputs = [val];
+                query.output = val;
+                query.search = val;
             // searching by type
             } else if (val.search("->") > -1) {
                 var trimmer = function (s) { return s.trim(); };
                 var parts = val.split("->").map(trimmer);
                 var input = parts[0];
                 // sort inputs so that order does not matter
-                var inputs = input.split(",").map(trimmer).sort().toString();
+                var inputs = input.split(",").map(trimmer).sort();
                 var output = parts[1];
 
                 for (var i = 0; i < nSearchWords; ++i) {
@@ -403,12 +442,30 @@
 
                     // allow searching for void (no output) functions as well
                     var typeOutput = type.output ? type.output.name : "";
-                    if ((inputs === "*" || inputs === typeInputs.toString()) &&
-                        (output === "*" || output == typeOutput)) {
-                        results.push({id: i, index: -1, dontValidate: true});
+                    if (output === "*" || output == typeOutput) {
+                        if (input === "*") {
+                            results.push({id: i, index: -1, dontValidate: true});
+                        } else {
+                            var allFound = true;
+                            for (var it = 0; allFound === true && it < inputs.length; it++) {
+                                var found = false;
+                                for (var y = 0; found === false && y < typeInputs.length; y++) {
+                                    found = typeInputs[y] === inputs[it];
+                                }
+                                allFound = found;
+                            }
+                            if (allFound === true) {
+                                results.push({id: i, index: -1, dontValidate: true});
+                            }
+                        }
                     }
                 }
+                query.inputs = inputs;
+                query.output = output;
             } else {
+                query.inputs = [val];
+                query.output = val;
+                query.search = val;
                 // gather matching search results up to a certain maximum
                 val = val.replace(/\_/g, "");
                 for (var i = 0; i < split.length; ++i) {
@@ -437,6 +494,15 @@
                                     lev: lev_distance,
                                 });
                             }
+                        } else if (findArg(searchIndex[j], val)) {
+                            if (typePassesFilter(typeFilter, searchIndex[j].ty)) {
+                                results.push({
+                                    id: j,
+                                    index: 0,
+                                    // we want lev results to go lower than others
+                                    lev: lev_distance,
+                                });
+                            }
                         }
                         if (results.length === max) {
                             break;
@@ -576,8 +642,7 @@
                     (parent !== undefined &&
                         parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
                     // lastly check to see if the name was a levenshtein match
-                    levenshtein(name.toLowerCase(), keys[i]) <=
-                        MAX_LEV_DISTANCE)) {
+                    levenshtein(name.toLowerCase(), keys[i]) <= MAX_LEV_DISTANCE)) {
                     return false;
                 }
             }
@@ -647,41 +712,56 @@
             });
 
             var search_input = document.getElementsByClassName('search-input')[0];
-            search_input.onkeydown = null;
             search_input.onkeydown = function(e) {
-                var actives = [];
+                // "actives" references the currently highlighted item in each search tab.
+                // Each array in "actives" represents a tab.
+                var actives = [[], [], []];
+                // "current" is used to know which tab we're looking into.
+                var current = 0;
                 onEach(document.getElementsByClassName('search-results'), function(e) {
-                    onEach(document.getElementsByClassName('highlighted'), function(e) {
-                        actives.push(e);
+                    onEach(e.getElementsByClassName('highlighted'), function(e) {
+                        actives[current].push(e);
                     });
+                    current += 1;
                 });
 
                 if (e.which === 38) { // up
-                    if (!actives.length || !actives[0].previousElementSibling) {
+                    if (!actives[currentTab].length ||
+                        !actives[currentTab][0].previousElementSibling) {
                         return;
                     }
 
-                    addClass(actives[0].previousElementSibling, 'highlighted');
-                    removeClass(actives[0], 'highlighted');
+                    addClass(actives[currentTab][0].previousElementSibling, 'highlighted');
+                    removeClass(actives[currentTab][0], 'highlighted');
                 } else if (e.which === 40) { // down
-                    if (!actives.length) {
+                    if (!actives[currentTab].length) {
                         var results = document.getElementsByClassName('search-results');
                         if (results.length > 0) {
-                            var res = results[0].getElementsByClassName('result');
+                            var res = results[currentTab].getElementsByClassName('result');
                             if (res.length > 0) {
                                 addClass(res[0], 'highlighted');
                             }
                         }
-                    } else if (actives[0].nextElementSibling) {
-                        addClass(actives[0].nextElementSibling, 'highlighted');
-                        removeClass(actives[0], 'highlighted');
+                    } else if (actives[currentTab][0].nextElementSibling) {
+                        addClass(actives[currentTab][0].nextElementSibling, 'highlighted');
+                        removeClass(actives[currentTab][0], 'highlighted');
                     }
                 } else if (e.which === 13) { // return
-                    if (actives.length) {
-                        document.location.href = actives[0].getElementsByTagName('a')[0].href;
+                    if (actives[currentTab].length) {
+                        document.location.href =
+                            actives[currentTab][0].getElementsByTagName('a')[0].href;
+                    }
+                } else if (e.which === 9) { // tab
+                    if (e.shiftKey) {
+                        printTab(currentTab > 0 ? currentTab - 1 : 2);
+                    } else {
+                        printTab(currentTab > 1 ? 0 : currentTab + 1);
                     }
-                } else if (actives.length > 0) {
-                    removeClass(actives[0], 'highlighted');
+                    e.preventDefault();
+                } else if (e.which === 16) { // shift
+                    // Does nothing, it's just to avoid losing "focus" on the highlighted element.
+                } else if (actives[currentTab].length > 0) {
+                    removeClass(actives[currentTab][0], 'highlighted');
                 }
             };
         }
@@ -692,18 +772,18 @@
             return h1.innerHTML;
         }
 
-        function showResults(results) {
-            var output, shown, query = getQuery();
-
-            currentResults = query.id;
-            output = '<h1>Results for ' + escape(query.query) +
-                (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>';
-            output += '<table class="search-results">';
+        function addTab(array, query, display) {
+            var extraStyle = '';
+            if (display === false) {
+                extraStyle = ' style="display: none;"';
+            }
 
-            if (results.length > 0) {
-                shown = [];
+            var output = '';
+            if (array.length > 0) {
+                output = '<table class="search-results"' + extraStyle + '>';
+                var shown = [];
 
-                results.forEach(function(item) {
+                array.forEach(function(item) {
                     var name, type, href, displayPath;
 
                     if (shown.indexOf(item) !== -1) {
@@ -752,13 +832,40 @@
                               '<span class="desc">' + escape(item.desc) +
                               '&nbsp;</span></a></td></tr>';
                 });
+                output += '</table>';
             } else {
-                output += 'No results :( <a href="https://duckduckgo.com/?q=' +
+                output = '<div class="search-failed"' + extraStyle + '>No results :(<br/>' +
+                    'Try on <a href="https://duckduckgo.com/?q=' +
                     encodeURIComponent('rust ' + query.query) +
-                    '">Try on DuckDuckGo?</a>';
+                    '">DuckDuckGo</a>?</div>';
             }
+            return output;
+        }
+
+        function makeTabHeader(tabNb, text) {
+            if (currentTab === tabNb) {
+                return '<div class="selected">' + text + '</div>';
+            }
+            return '<div>' + text + '</div>';
+        }
+
+        function showResults(results) {
+            var output, query = getQuery();
+
+            currentResults = query.id;
+            output = '<h1>Results for ' + escape(query.query) +
+                (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
+                '<div id="titles">' +
+                makeTabHeader(0, "Types/modules") +
+                makeTabHeader(1, "As parameters") +
+                makeTabHeader(2, "As return value") +
+                '</div><div id="results">';
+
+            output += addTab(results['others'], query);
+            output += addTab(results['in_args'], query, false);
+            output += addTab(results['returned'], query, false);
+            output += '</div>';
 
-            output += "</p>";
             addClass(document.getElementById('main'), 'hidden');
             var search = document.getElementById('search');
             removeClass(search, 'hidden');
@@ -773,13 +880,17 @@
                 e.style.width = width + 'px';
             });
             initSearchNav();
+            var elems = document.getElementById('titles').childNodes;
+            elems[0].onclick = function() { printTab(0); };
+            elems[1].onclick = function() { printTab(1); };
+            elems[2].onclick = function() { printTab(2); };
         }
 
         function search(e) {
             var query,
                 filterdata = [],
                 obj, i, len,
-                results = [],
+                results = {"in_args": [], "returned": [], "others": []},
                 maxResults = 200,
                 resultIndex;
             var params = getQueryStringParams();
@@ -810,11 +921,43 @@
             len = resultIndex.length;
             for (i = 0; i < len; ++i) {
                 if (resultIndex[i].id > -1) {
+                    var added = false;
                     obj = searchIndex[resultIndex[i].id];
                     filterdata.push([obj.name, obj.ty, obj.path, obj.desc]);
-                    results.push(obj);
+                    if (obj.type) {
+                        if (results['returned'].length < maxResults &&
+                            obj.type.output &&
+                            obj.type.output.name.toLowerCase() === query.output) {
+                            results['returned'].push(obj);
+                            added = true;
+                        }
+                        if (results['in_args'].length < maxResults && obj.type.inputs.length > 0) {
+                            var all_founds = true;
+                            for (var it = 0;
+                                 all_founds === true && it < query.inputs.length;
+                                 it++) {
+                                var found = false;
+                                for (var y = 0;
+                                     found === false && y < obj.type.inputs.length;
+                                     y++) {
+                                    found = query.inputs[it] === obj.type.inputs[y].name;
+                                }
+                                all_founds = found;
+                            }
+                            if (all_founds === true) {
+                                results['in_args'].push(obj);
+                                added = true;
+                            }
+                        }
+                    }
+                    if (results['others'].length < maxResults &&
+                        ((query.search && obj.name.indexOf(query.search)) || added === false)) {
+                        results['others'].push(obj);
+                    }
                 }
-                if (results.length >= maxResults) {
+                if (results['others'].length >= maxResults &&
+                    results['in_args'].length >= maxResults &&
+                    results['returned'].length >= maxResults) {
                     break;
                 }
             }
@@ -1290,6 +1433,30 @@
         return wrapper;
     }
 
+    // In the search display, allows to switch between tabs.
+    function printTab(nb) {
+        if (nb === 0 || nb === 1 || nb === 2) {
+            currentTab = nb;
+        }
+        var nb_copy = nb;
+        onEach(document.getElementById('titles').childNodes, function(elem) {
+            if (nb_copy === 0) {
+                addClass(elem, 'selected');
+            } else {
+                removeClass(elem, 'selected');
+            }
+            nb_copy -= 1;
+        });
+        onEach(document.getElementById('results').childNodes, function(elem) {
+            if (nb === 0) {
+                elem.style.display = '';
+            } else {
+                elem.style.display = 'none';
+            }
+            nb -= 1;
+        });
+    }
+
     onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) {
         onEach(e.getElementsByClassName('attributes'), function(i_e) {
             i_e.parentNode.insertBefore(createToggleWrapper(), i_e);
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 27574e67bc8..18270654aa9 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -203,6 +203,15 @@ nav.sub {
 	word-wrap: break-word;
 }
 
+.sidebar .version {
+	font-size: 15px;
+	text-align: center;
+	border-bottom: #DDDDDD 1px solid;
+	overflow-wrap: break-word;
+	word-wrap: break-word; /* deprecated */
+	word-break: break-word; /* Chrome, non-standard */
+}
+
 .location:empty {
 	border: none;
 }
@@ -385,7 +394,7 @@ h4 > code, h3 > code, .invisible > code {
 	padding: 0;
 }
 
-.content .item-list li { margin-bottom: 3px; }
+.content .item-list li { margin-bottom: 1em; }
 
 .content .multi-column {
 	-moz-column-count: 5;
@@ -543,7 +552,7 @@ body.blur > :not(#help) {
 	flex: 0 0 auto;
 	box-shadow: 0 0 6px rgba(0,0,0,.2);
 	width: 550px;
-	height: 330px;
+	height: 354px;
 	border: 1px solid;
 }
 #help dt {
@@ -764,17 +773,19 @@ span.since {
 	}
 
 	.sidebar {
-		height: 40px;
+		height: 45px;
 		min-height: 40px;
-		width: 100%;
-		margin: 0px;
-		padding: 0px;
+		width: calc(100% + 30px);
+		margin: 0;
+		margin-left: -15px;
+		padding: 0 15px;
 		position: static;
 	}
 
 	.sidebar .location {
 		float: right;
 		margin: 0px;
+		margin-top: 2px;
 		padding: 3px 10px 1px 10px;
 		min-height: 39px;
 		background: inherit;
@@ -789,7 +800,7 @@ span.since {
 	.sidebar img {
 		width: 35px;
 		margin-top: 5px;
-		margin-bottom: 0px;
+		margin-bottom: 5px;
 		float: left;
 	}
 
@@ -820,6 +831,10 @@ span.since {
 	.toggle-wrapper {
 		height: 1.5em;
 	}
+
+	#search {
+		margin-left: 0;
+	}
 }
 
 @media print {
@@ -873,3 +888,29 @@ span.since {
 pre.rust {
 	position: relative;
 }
+
+.search-failed {
+	text-align: center;
+	margin-top: 20px;
+}
+
+#titles {
+	height: 35px;
+}
+
+#titles > div {
+	float: left;
+	width: 33.3%;
+	text-align: center;
+	border-bottom: 1px solid #ccc;
+	font-size: 18px;
+	cursor: pointer;
+}
+
+#titles > div.selected {
+	border-bottom: 3px solid #0078ee;
+}
+
+#titles > div:hover {
+	border-bottom: 3px solid #0089ff;
+}
diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css
index 42d0ec704f4..4a4ca15170a 100644
--- a/src/librustdoc/html/static/styles/main.css
+++ b/src/librustdoc/html/static/styles/main.css
@@ -235,3 +235,7 @@ pre.ignore:hover, .information:hover + pre.ignore {
 .information > .ignore:hover {
 	color: rgba(255,142,0,1);
 }
+
+.search-failed > a {
+	color: #0089ff;
+}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 9563ccfcc65..20da99a6b13 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -170,6 +170,9 @@ pub fn opts() -> Vec<RustcOptGroup> {
         stable("no-default", |o| {
             o.optflag("", "no-defaults", "don't run the default passes")
         }),
+        stable("document-private-items", |o| {
+            o.optflag("", "document-private-items", "document private items")
+        }),
         stable("test", |o| o.optflag("", "test", "run code examples as tests")),
         stable("test-args", |o| {
             o.optmulti("", "test-args", "arguments to pass to the test runner",
@@ -243,6 +246,12 @@ pub fn opts() -> Vec<RustcOptGroup> {
         unstable("display-warnings", |o| {
             o.optflag("", "display-warnings", "to print code warnings when testing doc")
         }),
+        unstable("crate-version", |o| {
+            o.optopt("", "crate-version", "crate version to print into documentation", "VERSION")
+        }),
+        unstable("linker", |o| {
+            o.optopt("", "linker", "linker used for building executable test code", "PATH")
+        }),
     ]
 }
 
@@ -269,6 +278,9 @@ pub fn main_args(args: &[String]) -> isize {
     // Check for unstable options.
     nightly_options::check_nightly_options(&matches, &opts());
 
+    // check for deprecated options
+    check_deprecated_options(&matches);
+
     if matches.opt_present("h") || matches.opt_present("help") {
         usage("rustdoc");
         return 0;
@@ -354,15 +366,16 @@ pub fn main_args(args: &[String]) -> isize {
     let playground_url = matches.opt_str("playground-url");
     let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
     let display_warnings = matches.opt_present("display-warnings");
+    let linker = matches.opt_str("linker");
 
     match (should_test, markdown_input) {
         (true, true) => {
             return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type,
-                                  display_warnings)
+                                  display_warnings, linker)
         }
         (true, false) => {
             return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
-                             render_type, display_warnings)
+                             render_type, display_warnings, linker)
         }
         (false, true) => return markdown::render(input,
                                                  output.unwrap_or(PathBuf::from("doc")),
@@ -451,6 +464,18 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
     let mut passes = matches.opt_strs("passes");
     let mut plugins = matches.opt_strs("plugins");
 
+    // We hardcode in the passes here, as this is a new flag and we
+    // are generally deprecating passes.
+    if matches.opt_present("document-private-items") {
+        default_passes = false;
+
+        passes = vec![
+            String::from("strip-hidden"),
+            String::from("collapse-docs"),
+            String::from("unindent-comments"),
+        ];
+    }
+
     // First, parse the crate and extract all relevant information.
     let mut paths = SearchPaths::new();
     for s in &matches.opt_strs("L") {
@@ -460,6 +485,7 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
     let triple = matches.opt_str("target");
     let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
     let crate_name = matches.opt_str("crate-name");
+    let crate_version = matches.opt_str("crate-version");
     let plugin_path = matches.opt_str("plugin-path");
 
     let cr = PathBuf::from(cratefile);
@@ -484,6 +510,8 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
             krate.name = name
         }
 
+        krate.version = crate_version;
+
         // Process all of the crate attributes, extracting plugin metadata along
         // with the passes which we are supposed to run.
         for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
@@ -540,3 +568,26 @@ where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
     });
     rx.recv().unwrap()
 }
+
+/// Prints deprecation warnings for deprecated options
+fn check_deprecated_options(matches: &getopts::Matches) {
+    let deprecated_flags = [
+       "input-format",
+       "output-format",
+       "plugin-path",
+       "plugins",
+       "no-defaults",
+       "passes",
+    ];
+
+    for flag in deprecated_flags.into_iter() {
+        if matches.opt_present(flag) {
+            eprintln!("WARNING: the '{}' flag is considered deprecated", flag);
+            eprintln!("WARNING: please see https://github.com/rust-lang/rust/issues/44136");
+        }
+    }
+
+    if matches.opt_present("no-defaults") {
+        eprintln!("WARNING: (you may want to use --document-private-items)");
+    }
+}
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 57e8e88cd13..fe6bd985bb6 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -11,7 +11,6 @@
 use std::default::Default;
 use std::fs::File;
 use std::io::prelude::*;
-use std::io;
 use std::path::{PathBuf, Path};
 
 use getopts;
@@ -75,9 +74,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 
     let mut out = match File::create(&output) {
         Err(e) => {
-            let _ = writeln!(&mut io::stderr(),
-                             "rustdoc: {}: {}",
-                             output.display(), e);
+            eprintln!("rustdoc: {}: {}", output.display(), e);
             return 4;
         }
         Ok(f) => f
@@ -85,10 +82,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 
     let (metadata, text) = extract_leading_metadata(&input_str);
     if metadata.is_empty() {
-        let _ = writeln!(
-            &mut io::stderr(),
-            "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`"
-        );
+        eprintln!("rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`");
         return 5;
     }
     let title = metadata[0];
@@ -138,9 +132,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 
     match err {
         Err(e) => {
-            let _ = writeln!(&mut io::stderr(),
-                             "rustdoc: cannot write to `{}`: {}",
-                             output.display(), e);
+            eprintln!("rustdoc: cannot write to `{}`: {}", output.display(), e);
             6
         }
         Ok(_) => 0
@@ -150,7 +142,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 /// Run any tests/code examples in the markdown file `input`.
 pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
             mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
-            render_type: RenderType, display_warnings: bool) -> isize {
+            render_type: RenderType, display_warnings: bool, linker: Option<String>) -> isize {
     let input_str = match load_string(input) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
@@ -162,7 +154,7 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
     let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                        true, opts, maybe_sysroot, None,
                                        Some(input.to_owned()),
-                                       render_type);
+                                       render_type, linker);
     if render_type == RenderType::Pulldown {
         old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
         find_testable_code(&input_str, &mut collector, DUMMY_SP);
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 5ce73d38fdf..8b2c8d2da39 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -61,7 +61,8 @@ pub fn run(input: &str,
            crate_name: Option<String>,
            maybe_sysroot: Option<PathBuf>,
            render_type: RenderType,
-           display_warnings: bool)
+           display_warnings: bool,
+           linker: Option<String>)
            -> isize {
     let input_path = PathBuf::from(input);
     let input = config::Input::File(input_path.clone());
@@ -121,7 +122,8 @@ pub fn run(input: &str,
                                        maybe_sysroot,
                                        Some(codemap),
                                        None,
-                                       render_type);
+                                       render_type,
+                                       linker);
 
     {
         let map = hir::map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
@@ -180,7 +182,8 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec<String>, libs
             externs: Externs,
             should_panic: bool, no_run: bool, as_test_harness: bool,
             compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
-            maybe_sysroot: Option<PathBuf>) {
+            maybe_sysroot: Option<PathBuf>,
+            linker: Option<String>) {
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
     let test = make_test(test, Some(cratename), as_test_harness, opts);
@@ -201,6 +204,7 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec<String>, libs
         externs,
         cg: config::CodegenOptions {
             prefer_dynamic: true,
+            linker,
             .. config::basic_codegen_options()
         },
         test: as_test_harness,
@@ -407,13 +411,33 @@ pub struct Collector {
     pub tests: Vec<testing::TestDescAndFn>,
     // to be removed when hoedown will be definitely gone
     pub old_tests: HashMap<String, Vec<String>>,
+
+    // The name of the test displayed to the user, separated by `::`.
+    //
+    // In tests from Rust source, this is the path to the item
+    // e.g. `["std", "vec", "Vec", "push"]`.
+    //
+    // In tests from a markdown file, this is the titles of all headers (h1~h6)
+    // of the sections that contain the code block, e.g. if the markdown file is
+    // written as:
+    //
+    // ``````markdown
+    // # Title
+    //
+    // ## Subtitle
+    //
+    // ```rust
+    // assert!(true);
+    // ```
+    // ``````
+    //
+    // the `names` vector of that test will be `["Title", "Subtitle"]`.
     names: Vec<String>,
+
     cfgs: Vec<String>,
     libs: SearchPaths,
     externs: Externs,
-    cnt: usize,
     use_headers: bool,
-    current_header: Option<String>,
     cratename: String,
     opts: TestOptions,
     maybe_sysroot: Option<PathBuf>,
@@ -422,13 +446,14 @@ pub struct Collector {
     filename: Option<String>,
     // to be removed when hoedown will be removed as well
     pub render_type: RenderType,
+    linker: Option<String>,
 }
 
 impl Collector {
     pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
                use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
                codemap: Option<Rc<CodeMap>>, filename: Option<String>,
-               render_type: RenderType) -> Collector {
+               render_type: RenderType, linker: Option<String>) -> Collector {
         Collector {
             tests: Vec::new(),
             old_tests: HashMap::new(),
@@ -436,9 +461,7 @@ impl Collector {
             cfgs,
             libs,
             externs,
-            cnt: 0,
             use_headers,
-            current_header: None,
             cratename,
             opts,
             maybe_sysroot,
@@ -446,32 +469,17 @@ impl Collector {
             codemap,
             filename,
             render_type,
+            linker,
         }
     }
 
     fn generate_name(&self, line: usize, filename: &str) -> String {
-        if self.use_headers {
-            if let Some(ref header) = self.current_header {
-                format!("{} - {} (line {})", filename, header, line)
-            } else {
-                format!("{} - (line {})", filename, line)
-            }
-        } else {
-            format!("{} - {} (line {})", filename, self.names.join("::"), line)
-        }
+        format!("{} - {} (line {})", filename, self.names.join("::"), line)
     }
 
     // to be removed once hoedown is gone
     fn generate_name_beginning(&self, filename: &str) -> String {
-        if self.use_headers {
-            if let Some(ref header) = self.current_header {
-                format!("{} - {} (line", filename, header)
-            } else {
-                format!("{} - (line", filename)
-            }
-        } else {
-            format!("{} - {} (line", filename, self.names.join("::"))
-        }
+        format!("{} - {} (line", filename, self.names.join("::"))
     }
 
     pub fn add_old_test(&mut self, test: String, filename: String) {
@@ -495,11 +503,10 @@ impl Collector {
                 found = entry.remove_item(&test).is_some();
             }
             if !found {
-                let _ = writeln!(&mut io::stderr(),
-                                 "WARNING: {} Code block is not currently run as a test, but will \
-                                  in future versions of rustdoc. Please ensure this code block is \
-                                  a runnable test, or use the `ignore` directive.",
-                                 name);
+                eprintln!("WARNING: {} Code block is not currently run as a test, but will \
+                           in future versions of rustdoc. Please ensure this code block is \
+                           a runnable test, or use the `ignore` directive.",
+                          name);
                 return
             }
         }
@@ -509,6 +516,7 @@ impl Collector {
         let cratename = self.cratename.to_string();
         let opts = self.opts.clone();
         let maybe_sysroot = self.maybe_sysroot.clone();
+        let linker = self.linker.clone();
         debug!("Creating test {}: {}", name, test);
         self.tests.push(testing::TestDescAndFn {
             desc: testing::TestDesc {
@@ -537,7 +545,8 @@ impl Collector {
                                  compile_fail,
                                  error_codes,
                                  &opts,
-                                 maybe_sysroot)
+                                 maybe_sysroot,
+                                 linker)
                     })
                 } {
                     Ok(()) => (),
@@ -580,7 +589,7 @@ impl Collector {
     }
 
     pub fn register_header(&mut self, name: &str, level: u32) {
-        if self.use_headers && level == 1 {
+        if self.use_headers {
             // we use these headings as test names, so it's good if
             // they're valid identifiers.
             let name = name.chars().enumerate().map(|(i, c)| {
@@ -592,9 +601,28 @@ impl Collector {
                     }
                 }).collect::<String>();
 
-            // new header => reset count.
-            self.cnt = 0;
-            self.current_header = Some(name);
+            // Here we try to efficiently assemble the header titles into the
+            // test name in the form of `h1::h2::h3::h4::h5::h6`.
+            //
+            // Suppose originally `self.names` contains `[h1, h2, h3]`...
+            let level = level as usize;
+            if level <= self.names.len() {
+                // ... Consider `level == 2`. All headers in the lower levels
+                // are irrelevant in this new level. So we should reset
+                // `self.names` to contain headers until <h2>, and replace that
+                // slot with the new name: `[h1, name]`.
+                self.names.truncate(level);
+                self.names[level - 1] = name;
+            } else {
+                // ... On the other hand, consider `level == 5`. This means we
+                // need to extend `self.names` to contain five headers. We fill
+                // in the missing level (<h4>) with `_`. Thus `self.names` will
+                // become `[h1, h2, h3, "_", name]`.
+                if level - 1 > self.names.len() {
+                    self.names.resize(level - 1, "_".to_owned());
+                }
+                self.names.push(name);
+            }
         }
     }
 }
@@ -625,7 +653,6 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
         attrs.collapse_doc_comments();
         attrs.unindent_doc_comments();
         if let Some(doc) = attrs.doc_value() {
-            self.collector.cnt = 0;
             if self.collector.render_type == RenderType::Pulldown {
                 markdown::old_find_testable_code(doc, self.collector,
                                                  attrs.span.unwrap_or(DUMMY_SP));
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index fb276448ffa..5dd5f8953a0 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -15,7 +15,6 @@ alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
 alloc_system = { path = "../liballoc_system" }
 panic_unwind = { path = "../libpanic_unwind", optional = true }
 panic_abort = { path = "../libpanic_abort" }
-collections = { path = "../libcollections" }
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
 rand = { path = "../librand" }
@@ -36,7 +35,6 @@ rustc_tsan = { path = "../librustc_tsan" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0"
 
 [features]
 backtrace = []
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index 4e3781ecafa..327deb9b419 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -411,10 +411,12 @@ pub trait AsciiExt {
     fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
 
     /// Checks if the value is an ASCII punctuation character:
+    ///
     /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`
     /// U+003A ... U+0040 `: ; < = > ? @`
-    /// U+005B ... U+0060 `[ \\ ] ^ _ \``
+    /// U+005B ... U+0060 ``[ \\ ] ^ _ ` ``
     /// U+007B ... U+007E `{ | } ~`
+    ///
     /// For strings, true if all characters in the string are
     /// ASCII punctuation.
     ///
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 7ca762c801a..0e6214ea04f 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -11,7 +11,6 @@
 #![deny(warnings)]
 
 extern crate build_helper;
-extern crate cc;
 
 use std::env;
 use std::process::Command;
@@ -77,12 +76,6 @@ fn main() {
 fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
     let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?;
 
-    let compiler = cc::Build::new().get_compiler();
-    // only msvc returns None for ar so unwrap is okay
-    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
-    let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
-                             .collect::<Vec<_>>().join(" ");
-    cflags.push_str(" -fvisibility=hidden");
     run(Command::new("sh")
                 .current_dir(&native.out_dir)
                 .arg(native.src_dir.join("configure").to_str().unwrap()
@@ -94,10 +87,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
                 .arg("--disable-host-shared")
                 .arg(format!("--host={}", build_helper::gnu_target(target)))
                 .arg(format!("--build={}", build_helper::gnu_target(host)))
-                .env("CC", compiler.path())
-                .env("AR", &ar)
-                .env("RANLIB", format!("{} s", ar.display()))
-                .env("CFLAGS", cflags),
+                .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"),
         BuildExpectation::None);
 
     run(Command::new(build_helper::make(host))
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 3c0fa0860d3..d96a4f40d3f 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1113,6 +1113,7 @@ impl<K, V, S> HashMap<K, V, S>
     /// assert_eq!(map.get(&2), None);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
     pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
         where K: Borrow<Q>,
               Q: Hash + Eq
@@ -2554,6 +2555,7 @@ impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
 {
     type Key = K;
 
+    #[inline]
     fn get(&self, key: &Q) -> Option<&K> {
         self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0)
     }
@@ -2566,6 +2568,7 @@ impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
         self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0)
     }
 
+    #[inline]
     fn replace(&mut self, key: K) -> Option<K> {
         self.reserve(1);
 
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index 93929637e2f..7e623a0af17 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -717,26 +717,25 @@ fn calculate_offsets(hashes_size: usize,
     (pairs_offset, end_of_pairs, oflo)
 }
 
-// Returns a tuple of (minimum required malloc alignment, hash_offset,
+// Returns a tuple of (minimum required malloc alignment,
 // array_size), from the start of a mallocated array.
 fn calculate_allocation(hash_size: usize,
                         hash_align: usize,
                         pairs_size: usize,
                         pairs_align: usize)
-                        -> (usize, usize, usize, bool) {
-    let hash_offset = 0;
+                        -> (usize, usize, bool) {
     let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
 
     let align = cmp::max(hash_align, pairs_align);
 
-    (align, hash_offset, end_of_pairs, oflo)
+    (align, end_of_pairs, oflo)
 }
 
 #[test]
 fn test_offset_calculation() {
-    assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false));
-    assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false));
-    assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false));
+    assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false));
+    assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false));
+    assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false));
     assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
     assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
     assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
@@ -768,10 +767,10 @@ impl<K, V> RawTable<K, V> {
         // This is great in theory, but in practice getting the alignment
         // right is a little subtle. Therefore, calculating offsets has been
         // factored out into a different function.
-        let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
-                                                                        align_of::<HashUint>(),
-                                                                        pairs_size,
-                                                                        align_of::<(K, V)>());
+        let (alignment, size, oflo) = calculate_allocation(hashes_size,
+                                                           align_of::<HashUint>(),
+                                                           pairs_size,
+                                                           align_of::<(K, V)>());
         assert!(!oflo, "capacity overflow");
 
         // One check for overflow that covers calculation and rounding of size.
@@ -784,7 +783,7 @@ impl<K, V> RawTable<K, V> {
         let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap())
             .unwrap_or_else(|e| Heap.oom(e));
 
-        let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
+        let hashes = buffer as *mut HashUint;
 
         RawTable {
             capacity_mask: capacity.wrapping_sub(1),
@@ -1157,6 +1156,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
             }
 
             new_ht.size = self.size();
+            new_ht.set_tag(self.tag());
 
             new_ht
         }
@@ -1183,10 +1183,10 @@ 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 (align, _, size, oflo) = calculate_allocation(hashes_size,
-                                                          align_of::<HashUint>(),
-                                                          pairs_size,
-                                                          align_of::<(K, V)>());
+        let (align, size, oflo) = calculate_allocation(hashes_size,
+                                                       align_of::<HashUint>(),
+                                                       pairs_size,
+                                                       align_of::<(K, V)>());
 
         debug_assert!(!oflo, "should be impossible");
 
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index f9d80336477..b5460391942 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -23,19 +23,69 @@ use ptr;
 use slice;
 use str::{self, Utf8Error};
 
-/// A type representing an owned C-compatible string.
+/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
+/// middle.
 ///
-/// This type serves the primary purpose of being able to safely generate a
+/// This type serves the purpose of being able to safely generate a
 /// C-compatible string from a Rust byte slice or vector. An instance of this
 /// type is a static guarantee that the underlying bytes contain no interior 0
-/// bytes and the final byte is 0.
+/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
 ///
-/// A `CString` is created from either a byte slice or a byte vector. A [`u8`]
-/// slice can be obtained with the `as_bytes` method. Slices produced from a
-/// `CString` do *not* contain the trailing nul terminator unless otherwise
-/// specified.
+/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
 ///
+/// # Creating a `CString`
+///
+/// A `CString` is created from either a byte slice or a byte vector,
+/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// example, you can build a `CString` straight out of a [`String`] or
+/// a [`&str`], since both implement that trait).
+///
+/// The [`new`] method will actually check that the provided `&[u8]`
+/// does not have 0 bytes in the middle, and return an error if it
+/// finds one.
+///
+/// # Extracting a raw pointer to the whole C string
+///
+/// `CString` implements a [`as_ptr`] method through the [`Deref`]
+/// trait. This method will give you a `*const c_char` which you can
+/// feed directly to extern functions that expect a nul-terminated
+/// string, like C's `strdup()`.
+///
+/// # Extracting a slice of the whole C string
+///
+/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// `CString` with the [`as_bytes`] method. Slices produced in this
+/// way do *not* contain the trailing nul terminator. This is useful
+/// when you will be calling an extern function that takes a `*const
+/// u8` argument which is not necessarily nul-terminated, plus another
+/// argument with the length of the string — like C's `strndup()`.
+/// You can of course get the slice's length with its
+/// [`len`][slice.len] method.
+///
+/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// can use [`as_bytes_with_nul`] instead.
+///
+/// Once you have the kind of slice you need (with or without a nul
+/// terminator), you can call the slice's own
+/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// extern functions. See the documentation for that function for a
+/// discussion on ensuring the lifetime of the raw pointer.
+///
+/// [`Into`]: ../convert/trait.Into.html
+/// [`Vec`]: ../vec/struct.Vec.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
 /// [`u8`]: ../primitive.u8.html
+/// [`new`]: #method.new
+/// [`as_bytes`]: #method.as_bytes
+/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+/// [`as_ptr`]: #method.as_ptr
+/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
+/// [slice.len]: ../primitive.slice.html#method.len
+/// [`Deref`]: ../ops/trait.Deref.html
+/// [`CStr`]: struct.CStr.html
 ///
 /// # Examples
 ///
@@ -48,6 +98,8 @@ use str::{self, Utf8Error};
 ///     fn my_printer(s: *const c_char);
 /// }
 ///
+/// // We are certain that our string doesn't have 0 bytes in the middle,
+/// // so we can .unwrap()
 /// let c_to_print = CString::new("Hello, world!").unwrap();
 /// unsafe {
 ///     my_printer(c_to_print.as_ptr());
@@ -58,7 +110,7 @@ use str::{self, Utf8Error};
 /// # Safety
 ///
 /// `CString` is intended for working with traditional C-style strings
-/// (a sequence of non-null bytes terminated by a single null byte); the
+/// (a sequence of non-nul bytes terminated by a single nul byte); the
 /// primary use case for these kinds of strings is interoperating with C-like
 /// code. Often you will need to transfer ownership to/from that external
 /// code. It is strongly recommended that you thoroughly read through the
@@ -77,17 +129,21 @@ pub struct CString {
 
 /// Representation of a borrowed C string.
 ///
-/// This dynamically sized type is only safely constructed via a borrowed
-/// version of an instance of `CString`. This type can be constructed from a raw
-/// C string as well and represents a C string borrowed from another location.
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// into an owned [`CString`].
+///
+/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
 ///
 /// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead safe wrappers of FFI
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
 /// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe
 /// interface to other consumers.
 ///
-/// [`from_ptr`]: #method.from_ptr
-///
 /// # Examples
 ///
 /// Inspecting a foreign C string:
@@ -100,7 +156,7 @@ pub struct CString {
 ///
 /// unsafe {
 ///     let slice = CStr::from_ptr(my_string());
-///     println!("string length: {}", slice.to_bytes().len());
+///     println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
 /// }
 /// ```
 ///
@@ -122,8 +178,6 @@ pub struct CString {
 ///
 /// Converting a foreign C string into a Rust [`String`]:
 ///
-/// [`String`]: ../string/struct.String.html
-///
 /// ```no_run
 /// use std::ffi::CStr;
 /// use std::os::raw::c_char;
@@ -138,6 +192,12 @@ pub struct CString {
 ///
 /// println!("string: {}", my_string_safe());
 /// ```
+///
+/// [`u8`]: ../primitive.u8.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`from_ptr`]: #method.from_ptr
 #[derive(Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct CStr {
@@ -148,9 +208,15 @@ pub struct CStr {
     inner: [c_char]
 }
 
-/// An error returned from [`CString::new`] to indicate that a nul byte was found
-/// in the vector provided.
+/// An error indicating that an interior nul byte was found.
+///
+/// While Rust strings may contain nul bytes in the middle, C strings
+/// can't, as that byte would effectively truncate the string.
 ///
+/// This error is created by the [`new`][`CString::new`] method on
+/// [`CString`]. See its documentation for more.
+///
+/// [`CString`]: struct.CString.html
 /// [`CString::new`]: struct.CString.html#method.new
 ///
 /// # Examples
@@ -164,9 +230,16 @@ pub struct CStr {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct NulError(usize, Vec<u8>);
 
-/// An error returned from [`CStr::from_bytes_with_nul`] to indicate that a nul
-/// byte was found too early in the slice provided or one wasn't found at all.
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul
+/// byte at the end of the slice.
 ///
+/// This error is created by the
+/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
+/// [`CStr`]. See its documentation for more.
+///
+/// [`CStr`]: struct.CStr.html
 /// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
 ///
 /// # Examples
@@ -201,9 +274,18 @@ impl FromBytesWithNulError {
     }
 }
 
-/// An error returned from [`CString::into_string`] to indicate that a UTF-8 error
-/// was encountered during the conversion.
+/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
+///
+/// `CString` is just a wrapper over a buffer of bytes with a nul
+/// terminator; [`into_string`][`CString::into_string`] performs UTF-8
+/// validation on those bytes and may return this error.
+///
+/// This `struct` is created by the
+/// [`into_string`][`CString::into_string`] method on [`CString`]. See
+/// its documentation for more.
 ///
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
 /// [`CString::into_string`]: struct.CString.html#method.into_string
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "cstring_into", since = "1.7.0")]
@@ -215,8 +297,11 @@ pub struct IntoStringError {
 impl CString {
     /// Creates a new C-compatible string from a container of bytes.
     ///
-    /// This method will consume the provided data and use the underlying bytes
-    /// to construct a new string, ensuring that there is a trailing 0 byte.
+    /// This function will consume the provided data and use the
+    /// underlying bytes to construct a new string, ensuring that
+    /// there is a trailing 0 byte. This trailing 0 byte will be
+    /// appended by this function; the provided data should *not*
+    /// contain any 0 bytes in it.
     ///
     /// # Examples
     ///
@@ -234,9 +319,11 @@ impl CString {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the bytes yielded contain an
-    /// internal 0 byte. The error returned will contain the bytes as well as
+    /// This function will return an error if the supplied bytes contain an
+    /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
     /// the position of the nul byte.
+    ///
+    /// [`NulError`]: struct.NulError.html
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
         Self::_new(t.into())
@@ -249,8 +336,8 @@ impl CString {
         }
     }
 
-    /// Creates a C-compatible string from a byte vector without checking for
-    /// interior 0 bytes.
+    /// Creates a C-compatible string by consuming a byte vector,
+    /// without checking for interior 0 bytes.
     ///
     /// This method is equivalent to [`new`] except that no runtime assertion
     /// is made that `v` contains no 0 bytes, and it requires an actual
@@ -275,7 +362,7 @@ impl CString {
         CString { inner: v.into_boxed_slice() }
     }
 
-    /// Retakes ownership of a `CString` that was transferred to C.
+    /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
     ///
     /// Additionally, the length of the string will be recalculated from the pointer.
     ///
@@ -286,7 +373,14 @@ impl CString {
     /// ownership of a string that was allocated by foreign code) is likely to lead
     /// to undefined behavior or allocator corruption.
     ///
+    /// > **Note:** If you need to borrow a string that was allocated by
+    /// > foreign code, use [`CStr`]. If you need to take ownership of
+    /// > a string that was allocated by foreign code, you will need to
+    /// > make your own provisions for freeing it appropriately, likely
+    /// > with the foreign code's API to do that.
+    ///
     /// [`into_raw`]: #method.into_raw
+    /// [`CStr`]: struct.CStr.html
     ///
     /// # Examples
     ///
@@ -315,11 +409,11 @@ impl CString {
         CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
     }
 
-    /// Transfers ownership of the string to a C caller.
+    /// Consumes the `CString` and transfers ownership of the string to a C caller.
     ///
-    /// The pointer must be returned to Rust and reconstituted using
+    /// The pointer which this function returns must be returned to Rust and reconstituted using
     /// [`from_raw`] to be properly deallocated. Specifically, one
-    /// should *not* use the standard C `free` function to deallocate
+    /// should *not* use the standard C `free()` function to deallocate
     /// this string.
     ///
     /// Failure to call [`from_raw`] will lead to a memory leak.
@@ -351,11 +445,27 @@ impl CString {
         Box::into_raw(self.into_inner()) as *mut c_char
     }
 
-    /// Converts the `CString` into a [`String`] if it contains valid Unicode data.
+    /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data.
     ///
     /// On failure, ownership of the original `CString` is returned.
     ///
     /// [`String`]: ../string/struct.String.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let valid_utf8 = vec![b'f', b'o', b'o'];
+    /// let cstring = CString::new(valid_utf8).unwrap();
+    /// assert_eq!(cstring.into_string().unwrap(), "foo");
+    ///
+    /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
+    /// let cstring = CString::new(invalid_utf8).unwrap();
+    /// let err = cstring.into_string().err().unwrap();
+    /// assert_eq!(err.utf8_error().valid_up_to(), 1);
+    /// ```
+
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_string(self) -> Result<String, IntoStringError> {
         String::from_utf8(self.into_bytes())
@@ -365,10 +475,11 @@ impl CString {
             })
     }
 
-    /// Returns the underlying byte buffer.
+    /// Consumes the `CString` and returns the underlying byte buffer.
     ///
-    /// The returned buffer does **not** contain the trailing nul separator and
-    /// it is guaranteed to not have any interior nul bytes.
+    /// The returned buffer does **not** contain the trailing nul
+    /// terminator, and it is guaranteed to not have any interior nul
+    /// bytes.
     ///
     /// # Examples
     ///
@@ -388,7 +499,7 @@ impl CString {
     }
 
     /// Equivalent to the [`into_bytes`] function except that the returned vector
-    /// includes the trailing nul byte.
+    /// includes the trailing nul terminator.
     ///
     /// [`into_bytes`]: #method.into_bytes
     ///
@@ -408,8 +519,12 @@ impl CString {
 
     /// Returns the contents of this `CString` as a slice of bytes.
     ///
-    /// The returned slice does **not** contain the trailing nul separator and
-    /// it is guaranteed to not have any interior nul bytes.
+    /// The returned slice does **not** contain the trailing nul
+    /// terminator, and it is guaranteed to not have any interior nul
+    /// bytes. If you need the nul terminator, use
+    /// [`as_bytes_with_nul`] instead.
+    ///
+    /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
     ///
     /// # Examples
     ///
@@ -427,7 +542,7 @@ impl CString {
     }
 
     /// Equivalent to the [`as_bytes`] function except that the returned slice
-    /// includes the trailing nul byte.
+    /// includes the trailing nul terminator.
     ///
     /// [`as_bytes`]: #method.as_bytes
     ///
@@ -598,8 +713,8 @@ impl Default for Box<CStr> {
 }
 
 impl NulError {
-    /// Returns the position of the nul byte in the slice that was provided to
-    /// [`CString::new`].
+    /// Returns the position of the nul byte in the slice that caused
+    /// [`CString::new`] to fail.
     ///
     /// [`CString::new`]: struct.CString.html#method.new
     ///
@@ -711,9 +826,9 @@ impl fmt::Display for IntoStringError {
 }
 
 impl CStr {
-    /// Casts a raw C string to a safe C string wrapper.
+    /// Wraps a raw C string with a safe C string wrapper.
     ///
-    /// This function will cast the provided `ptr` to the `CStr` wrapper which
+    /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
     /// allows inspection and interoperation of non-owned C strings. This method
     /// is unsafe for a number of reasons:
     ///
@@ -753,9 +868,9 @@ impl CStr {
 
     /// Creates a C string wrapper from a byte slice.
     ///
-    /// This function will cast the provided `bytes` to a `CStr` wrapper after
-    /// ensuring that it is null terminated and does not contain any interior
-    /// nul bytes.
+    /// This function will cast the provided `bytes` to a `CStr`
+    /// wrapper after ensuring that the byte slice is nul-terminated
+    /// and does not contain any interior nul bytes.
     ///
     /// # Examples
     ///
@@ -766,7 +881,7 @@ impl CStr {
     /// assert!(cstr.is_ok());
     /// ```
     ///
-    /// Creating a `CStr` without a trailing nul byte is an error:
+    /// Creating a `CStr` without a trailing nul terminator is an error:
     ///
     /// ```
     /// use std::ffi::CStr;
@@ -800,7 +915,7 @@ impl CStr {
     /// Unsafely creates a C string wrapper from a byte slice.
     ///
     /// This function will cast the provided `bytes` to a `CStr` wrapper without
-    /// performing any sanity checks. The provided slice must be null terminated
+    /// performing any sanity checks. The provided slice **must** be nul-terminated
     /// and not contain any interior nul bytes.
     ///
     /// # Examples
@@ -822,7 +937,7 @@ impl CStr {
 
     /// Returns the inner pointer to this C string.
     ///
-    /// The returned pointer will be valid for as long as `self` is and points
+    /// The returned pointer will be valid for as long as `self` is, and points
     /// to a contiguous region of memory terminated with a 0 byte to represent
     /// the end of the string.
     ///
@@ -843,9 +958,9 @@ impl CStr {
     /// ```
     ///
     /// This happens because the pointer returned by `as_ptr` does not carry any
-    /// lifetime information and the string is deallocated immediately after
+    /// lifetime information and the [`CString`] is deallocated immediately after
     /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated.
-    /// To fix the problem, bind the string to a local variable:
+    /// To fix the problem, bind the `CString` to a local variable:
     ///
     /// ```no_run
     /// use std::ffi::{CString};
@@ -857,6 +972,11 @@ impl CStr {
     ///     *ptr;
     /// }
     /// ```
+    ///
+    /// This way, the lifetime of the `CString` in `hello` encompasses
+    /// the lifetime of `ptr` and the `unsafe` block.
+    ///
+    /// [`CString`]: struct.CString.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_ptr(&self) -> *const c_char {
@@ -865,11 +985,7 @@ impl CStr {
 
     /// Converts this C string to a byte slice.
     ///
-    /// This function will calculate the length of this string (which normally
-    /// requires a linear amount of work to be done) and then return the
-    /// resulting slice of `u8` elements.
-    ///
-    /// The returned slice will **not** contain the trailing nul that this C
+    /// The returned slice will **not** contain the trailing nul terminator that this C
     /// string has.
     ///
     /// > **Note**: This method is currently implemented as a 0-cost cast, but
@@ -894,7 +1010,7 @@ impl CStr {
     /// Converts this C string to a byte slice containing the trailing 0 byte.
     ///
     /// This function is the equivalent of [`to_bytes`] except that it will retain
-    /// the trailing nul instead of chopping it off.
+    /// the trailing nul terminator instead of chopping it off.
     ///
     /// > **Note**: This method is currently implemented as a 0-cost cast, but
     /// > it is planned to alter its definition in the future to perform the
@@ -918,8 +1034,9 @@ impl CStr {
 
     /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
     ///
-    /// This function will calculate the length of this string and check for
-    /// UTF-8 validity, and then return the [`&str`] if it's valid.
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
     ///
     /// > **Note**: This method is currently implemented to check for validity
     /// > after a 0-cost cast, but it is planned to alter its definition in the
@@ -947,10 +1064,12 @@ impl CStr {
 
     /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
     ///
-    /// This function will calculate the length of this string (which normally
-    /// requires a linear amount of work to be done) and then return the
-    /// resulting slice as a [`Cow`]`<`[`str`]`>`, replacing any invalid UTF-8 sequences
-    /// with `U+FFFD REPLACEMENT CHARACTER`.
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
+    /// with the the corresponding [`&str`] slice. Otherwise, it will
+    /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT
+    /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)`
+    /// with the result.
     ///
     /// > **Note**: This method is currently implemented to check for validity
     /// > after a 0-cost cast, but it is planned to alter its definition in the
@@ -958,7 +1077,9 @@ impl CStr {
     /// > check whenever this method is called.
     ///
     /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
     /// [`str`]: ../primitive.str.html
+    /// [`String`]: ../string/struct.String.html
     ///
     /// # Examples
     ///
diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs
index ca1ff18f1ca..a75596351e4 100644
--- a/src/libstd/ffi/mod.rs
+++ b/src/libstd/ffi/mod.rs
@@ -9,6 +9,157 @@
 // except according to those terms.
 
 //! Utilities related to FFI bindings.
+//!
+//! This module provides utilities to handle data across non-Rust
+//! interfaces, like other programming languages and the underlying
+//! operating system. It is mainly of use for FFI (Foreign Function
+//! Interface) bindings and code that needs to exchange C-like strings
+//! with other languages.
+//!
+//! # Overview
+//!
+//! Rust represents owned strings with the [`String`] type, and
+//! borrowed slices of strings with the [`str`] primitive. Both are
+//! always in UTF-8 encoding, and may contain nul bytes in the middle,
+//! i.e. if you look at the bytes that make up the string, there may
+//! be a `\0` among them. Both `String` and `str` store their length
+//! explicitly; there are no nul terminators at the end of strings
+//! like in C.
+//!
+//! C strings are different from Rust strings:
+//!
+//! * **Encodings** - Rust strings are UTF-8, but C strings may use
+//! other encodings. If you are using a string from C, you should
+//! check its encoding explicitly, rather than just assuming that it
+//! is UTF-8 like you can do in Rust.
+//!
+//! * **Character size** - C strings may use `char` or `wchar_t`-sized
+//! characters; please **note** that C's `char` is different from Rust's.
+//! The C standard leaves the actual sizes of those types open to
+//! interpretation, but defines different APIs for strings made up of
+//! each character type. Rust strings are always UTF-8, so different
+//! Unicode characters will be encoded in a variable number of bytes
+//! each. The Rust type [`char`] represents a '[Unicode scalar
+//! value]', which is similar to, but not the same as, a '[Unicode
+//! code point]'.
+//!
+//! * **Nul terminators and implicit string lengths** - Often, C
+//! strings are nul-terminated, i.e. they have a `\0` character at the
+//! end. The length of a string buffer is not stored, but has to be
+//! calculated; to compute the length of a string, C code must
+//! manually call a function like `strlen()` for `char`-based strings,
+//! or `wcslen()` for `wchar_t`-based ones. Those functions return
+//! the number of characters in the string excluding the nul
+//! terminator, so the buffer length is really `len+1` characters.
+//! Rust strings don't have a nul terminator; their length is always
+//! stored and does not need to be calculated. While in Rust
+//! accessing a string's length is a O(1) operation (becasue the
+//! length is stored); in C it is an O(length) operation because the
+//! length needs to be computed by scanning the string for the nul
+//! terminator.
+//!
+//! * **Internal nul characters** - When C strings have a nul
+//! terminator character, this usually means that they cannot have nul
+//! characters in the middle — a nul character would essentially
+//! truncate the string. Rust strings *can* have nul characters in
+//! the middle, because nul does not have to mark the end of the
+//! string in Rust.
+//!
+//! # Representations of non-Rust strings
+//!
+//! [`CString`] and [`CStr`] are useful when you need to transfer
+//! UTF-8 strings to and from languages with a C ABI, like Python.
+//!
+//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
+//! string: it is nul-terminated, and has no internal nul characters.
+//! Rust code can create a `CString` out of a normal string (provided
+//! that the string doesn't have nul characters in the middle), and
+//! then use a variety of methods to obtain a raw `*mut u8` that can
+//! then be passed as an argument to functions which use the C
+//! conventions for strings.
+//!
+//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
+//! is what you would use to wrap a raw `*const u8` that you got from
+//! a C function. A `CStr` is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a `CStr`, you can convert it to a Rust
+//! `&str` if it's valid UTF-8, or lossily convert it by adding
+//! replacement characters.
+//!
+//! [`OsString`] and [`OsStr`] are useful when you need to transfer
+//! strings to and from the operating system itself, or when capturing
+//! the output of external commands. Conversions between `OsString`,
+//! `OsStr` and Rust strings work similarly to those for [`CString`]
+//! and [`CStr`].
+//!
+//! * [`OsString`] represents an owned string in whatever
+//! representation the operating system prefers. In the Rust standard
+//! library, various APIs that transfer strings to/from the operating
+//! system use `OsString` instead of plain strings. For example,
+//! [`env::var_os()`] is used to query environment variables; it
+//! returns an `Option<OsString>`. If the environment variable exists
+//! you will get a `Some(os_string)`, which you can *then* try to
+//! convert to a Rust string. This yields a [`Result<>`], so that
+//! your code can detect errors in case the environment variable did
+//! not in fact contain valid Unicode data.
+//!
+//! * [`OsStr`] represents a borrowed reference to a string in a
+//! format that can be passed to the operating system. It can be
+//! converted into an UTF-8 Rust string slice in a similar way to
+//! `OsString`.
+//!
+//! # Conversions
+//!
+//! ## On Unix
+//!
+//! On Unix, [`OsStr`] implements the
+//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
+//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
+//! These do inexpensive conversions from and to UTF-8 byte slices.
+//!
+//! Additionally, on Unix [`OsString`] implements the
+//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait,
+//! which provides [`from_vec`] and [`into_vec`] methods that consume
+//! their arguments, and take or produce vectors of [`u8`].
+//!
+//! ## On Windows
+//!
+//! On Windows, [`OsStr`] implements the
+//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
+//! which provides an [`encode_wide`] method. This provides an
+//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//!
+//! Additionally, on Windows [`OsString`] implements the
+//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
+//! trait, which provides a [`from_wide`] method. The result of this
+//! method is an `OsString` which can be round-tripped to a Windows
+//! string losslessly.
+//!
+//! [`String`]: ../string/struct.String.html
+//! [`str`]: ../primitive.str.html
+//! [`char`]: ../primitive.char.html
+//! [`u8`]: ../primitive.u8.html
+//! [`u16`]: ../primitive.u16.html
+//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
+//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
+//! [`CString`]: struct.CString.html
+//! [`CStr`]: struct.CStr.html
+//! [`OsString`]: struct.OsString.html
+//! [`OsStr`]: struct.OsStr.html
+//! [`env::set_var()`]: ../env/fn.set_var.html
+//! [`env::var_os()`]: ../env/fn.var_os.html
+//! [`Result<>`]: ../result/enum.Result.html
+//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
+//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
+//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
+//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
+//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
+//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
+//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
+//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
+//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../iter/trait.Iterator.html#method.collect
+//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
+//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 88ee5c9a734..8c34660f821 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -32,18 +32,64 @@ use sys_common::{AsInner, IntoInner, FromInner};
 ///
 /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
 /// and platform-native string values, and in particular allowing a Rust string
-/// to be converted into an "OS" string with no cost.
+/// to be converted into an "OS" string with no cost if possible.
+///
+/// `OsString` is to [`OsStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating an `OsString`
+///
+/// **From a Rust string**: `OsString` implements
+/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to
+/// create an `OsString` from a normal Rust string.
+///
+/// **From slices:** Just like you can start with an empty Rust
+/// [`String`] and then [`push_str`][String.push_str] `&str`
+/// sub-string slices into it, you can create an empty `OsString` with
+/// the [`new`] method and then push string slices into it with the
+/// [`push`] method.
+///
+/// # Extracting a borrowed reference to the whole OS string
+///
+/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
+/// an `OsString`; this is effectively a borrowed reference to the
+/// whole string.
+///
+/// # Conversions
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsString` implements for conversions from/to native representations.
 ///
 /// [`OsStr`]: struct.OsStr.html
+/// [`From`]: ../convert/trait.From.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`u16`]: ../primitive.u16.html
+/// [String.push_str]: ../string/struct.String.html#method.push_str
+/// [`new`]: #method.new
+/// [`push`]: #method.push
+/// [`as_os_str`]: #method.as_os_str
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
     inner: Buf
 }
 
-/// Slices into OS strings (see [`OsString`]).
+/// Borrowed reference to an OS string (see [`OsString`]).
+///
+/// This type represents a borrowed reference to a string in the operating system's preferred
+/// representation.
+///
+/// `OsStr` is to [`OsString`] as [`String`] is to [`&str`]: the former in each pair are borrowed
+/// references; the latter are owned strings.
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsStr` implements for conversions from/to native representations.
 ///
 /// [`OsString`]: struct.OsString.html
+/// [conversions]: index.html#conversions
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsStr {
     inner: Slice
diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs
index d6b41ceda43..fe1179a3b4a 100644
--- a/src/libstd/io/impls.rs
+++ b/src/libstd/io/impls.rs
@@ -206,6 +206,14 @@ impl<'a> Read for &'a [u8] {
         *self = b;
         Ok(())
     }
+
+    #[inline]
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        buf.extend_from_slice(*self);
+        let len = self.len();
+        *self = &self[len..];
+        Ok(len)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 9fc7e2c01aa..83cc9ce582e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -244,6 +244,7 @@
 #![feature(allow_internal_unstable)]
 #![feature(align_offset)]
 #![feature(asm)]
+#![feature(attr_literals)]
 #![feature(box_syntax)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
@@ -290,6 +291,7 @@
 #![feature(prelude_import)]
 #![feature(rand)]
 #![feature(raw)]
+#![feature(repr_align)]
 #![feature(repr_simd)]
 #![feature(rustc_attrs)]
 #![cfg_attr(not(stage0), feature(rustc_const_unstable))]
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 8089671f309..6318e2e4087 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -490,7 +490,7 @@ pub mod builtin {
     #[macro_export]
     macro_rules! file { () => ({ /* compiler built-in */ }) }
 
-    /// A macro which stringifies its argument.
+    /// A macro which stringifies its arguments.
     ///
     /// This macro will yield an expression of type `&'static str` which is the
     /// stringification of all the tokens passed to the macro. No restrictions
@@ -507,7 +507,7 @@ pub mod builtin {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[macro_export]
-    macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
+    macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) }
 
     /// Includes a utf8-encoded file as a string.
     ///
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 8d1e7882e5d..539ff1df187 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -194,12 +194,12 @@ impl TcpStream {
     /// # Examples
     ///
     /// ```no_run
-    /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpStream};
+    /// use std::net::{IpAddr, Ipv4Addr, TcpStream};
     ///
     /// let stream = TcpStream::connect("127.0.0.1:8080")
     ///                        .expect("Couldn't connect to the server...");
-    /// assert_eq!(stream.local_addr().unwrap(),
-    ///            SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)));
+    /// assert_eq!(stream.local_addr().unwrap().ip(),
+    ///            IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn local_addr(&self) -> io::Result<SocketAddr> {
@@ -498,18 +498,46 @@ impl TcpStream {
 
     /// Moves this TCP stream into or out of nonblocking mode.
     ///
-    /// On Unix this corresponds to calling fcntl, and on Windows this
-    /// corresponds to calling ioctlsocket.
+    /// This will result in `read`, `write`, `recv` and `send` operations
+    /// becoming nonblocking, i.e. immediately returning from their calls.
+    /// If the IO operation is successful, `Ok` is returned and no further
+    /// action is required. If the IO operation could not be completed and needs
+    /// to be retried, an error with kind [`io::ErrorKind::WouldBlock`] is
+    /// returned.
+    ///
+    /// On Unix platforms, calling this method corresponds to calling `fcntl`
+    /// `FIONBIO`. On Windows calling this method corresponds to calling
+    /// `ioctlsocket` `FIONBIO`.
     ///
     /// # Examples
     ///
+    /// Reading bytes from a TCP stream in non-blocking mode:
+    ///
     /// ```no_run
+    /// use std::io::{self, Read};
     /// use std::net::TcpStream;
     ///
-    /// let stream = TcpStream::connect("127.0.0.1:8080")
-    ///                        .expect("Couldn't connect to the server...");
+    /// let mut stream = TcpStream::connect("127.0.0.1:7878")
+    ///     .expect("Couldn't connect to the server...");
     /// stream.set_nonblocking(true).expect("set_nonblocking call failed");
+    ///
+    /// # fn wait_for_fd() { unimplemented!() }
+    /// let mut buf = vec![];
+    /// loop {
+    ///     match stream.read_to_end(&mut buf) {
+    ///         Ok(_) => break,
+    ///         Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+    ///             // wait until network socket is ready, typically implemented
+    ///             // via platform-specific APIs such as epoll or IOCP
+    ///             wait_for_fd();
+    ///         }
+    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///     };
+    /// };
+    /// println!("bytes: {:?}", buf);
     /// ```
+    ///
+    /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
@@ -780,17 +808,48 @@ impl TcpListener {
 
     /// Moves this TCP stream into or out of nonblocking mode.
     ///
-    /// On Unix this corresponds to calling fcntl, and on Windows this
-    /// corresponds to calling ioctlsocket.
+    /// This will result in the `accept` operation becoming nonblocking,
+    /// i.e. immediately returning from their calls. If the IO operation is
+    /// successful, `Ok` is returned and no further action is required. If the
+    /// IO operation could not be completed and needs to be retried, an error
+    /// with kind [`io::ErrorKind::WouldBlock`] is returned.
+    ///
+    /// On Unix platforms, calling this method corresponds to calling `fcntl`
+    /// `FIONBIO`. On Windows calling this method corresponds to calling
+    /// `ioctlsocket` `FIONBIO`.
     ///
     /// # Examples
     ///
+    /// Bind a TCP listener to an address, listen for connections, and read
+    /// bytes in nonblocking mode:
+    ///
     /// ```no_run
+    /// use std::io;
     /// use std::net::TcpListener;
     ///
-    /// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+    /// let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
     /// listener.set_nonblocking(true).expect("Cannot set non-blocking");
+    ///
+    /// # fn wait_for_fd() { unimplemented!() }
+    /// # fn handle_connection(stream: std::net::TcpStream) { unimplemented!() }
+    /// for stream in listener.incoming() {
+    ///     match stream {
+    ///         Ok(s) => {
+    ///             // do something with the TcpStream
+    ///             handle_connection(s);
+    ///         }
+    ///         Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
+    ///             // wait until network socket is ready, typically implemented
+    ///             // via platform-specific APIs such as epoll or IOCP
+    ///             wait_for_fd();
+    ///             continue;
+    ///         }
+    ///         Err(e) => panic!("encountered IO error: {}", e),
+    ///     }
+    /// }
     /// ```
+    ///
+    /// [`io::ErrorKind::WouldBlock`]: ../io/enum.ErrorKind.html#variant.WouldBlock
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         self.0.set_nonblocking(nonblocking)
@@ -1580,6 +1639,21 @@ mod tests {
     }
 
     #[test]
+    fn connect_timeout_unbound() {
+        // bind and drop a socket to track down a "probably unassigned" port
+        let socket = TcpListener::bind("127.0.0.1:0").unwrap();
+        let addr = socket.local_addr().unwrap();
+        drop(socket);
+
+        let timeout = Duration::from_secs(1);
+        let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err();
+        assert!(e.kind() == io::ErrorKind::ConnectionRefused ||
+                e.kind() == io::ErrorKind::TimedOut ||
+                e.kind() == io::ErrorKind::Other,
+                "bad error: {} {:?}", e, e.kind());
+    }
+
+    #[test]
     fn connect_timeout_valid() {
         let listener = TcpListener::bind("127.0.0.1:0").unwrap();
         let addr = listener.local_addr().unwrap();
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index a8a242846d7..870d11298fe 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -168,7 +168,7 @@ impl UdpSocket {
     /// This will return an error when the IP version of the local socket
     /// does not match that returned from [`ToSocketAddrs`].
     ///
-    /// See https://github.com/rust-lang/rust/issues/34202 for more details.
+    /// See <https://github.com/rust-lang/rust/issues/34202> for more details.
     ///
     /// [`ToSocketAddrs`]: ../../std/net/trait.ToSocketAddrs.html
     ///
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
index b460bd90f17..122f15d1d4c 100644
--- a/src/libstd/os/mod.rs
+++ b/src/libstd/os/mod.rs
@@ -38,7 +38,6 @@ pub mod linux;
 #[cfg(all(not(dox), target_os = "haiku"))]      pub mod haiku;
 #[cfg(all(not(dox), target_os = "ios"))]        pub mod ios;
 #[cfg(all(not(dox), target_os = "macos"))]      pub mod macos;
-#[cfg(all(not(dox), target_os = "nacl"))]       pub mod nacl;
 #[cfg(all(not(dox), target_os = "netbsd"))]     pub mod netbsd;
 #[cfg(all(not(dox), target_os = "openbsd"))]    pub mod openbsd;
 #[cfg(all(not(dox), target_os = "solaris"))]    pub mod solaris;
diff --git a/src/libstd/os/nacl/fs.rs b/src/libstd/os/nacl/fs.rs
deleted file mode 100644
index 3e0fb44b01e..00000000000
--- a/src/libstd/os/nacl/fs.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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.
-
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use libc;
-
-use fs::Metadata;
-use sys_common::AsInner;
-
-#[allow(deprecated)]
-use os::nacl::raw;
-
-/// OS-specific extension methods for `fs::Metadata`
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned `stat` are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(since = "1.8.0",
-                       reason = "deprecated in favor of the accessor \
-                                 methods of this trait")]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe {
-            &*(self.as_inner().as_inner() as *const libc::stat64
-                                          as *const raw::stat)
-        }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-}
diff --git a/src/libstd/os/nacl/raw.rs b/src/libstd/os/nacl/raw.rs
deleted file mode 100644
index 3c3d4410a2a..00000000000
--- a/src/libstd/os/nacl/raw.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Nacl-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(since = "1.8.0",
-                    reason = "these type aliases are no longer supported by \
-                              the standard library, the `libc` crate on \
-                              crates.io should be used instead for the correct \
-                              definitions")]
-#![allow(deprecated)]
-
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_dev: dev_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ino: ino_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_mode: mode_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_nlink: nlink_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_uid: uid_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_gid: gid_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_rdev: dev_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_size: off_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_blksize: blksize_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_blocks: blkcnt_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_atime: time_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_atime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_mtime: time_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_mtime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ctime: time_t,
-    #[stable(feature = "raw_ext", since = "1.1.0")] pub st_ctime_nsec: i64,
-}
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index 1edb35d8fe7..9e1da318242 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -284,7 +284,6 @@ mod prim_pointer { }
 /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if
 /// the element type allows it:
 ///
-/// - [`Clone`][clone] (only if `T: `[`Copy`][copy])
 /// - [`Debug`][debug]
 /// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`)
 /// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord]
@@ -299,8 +298,10 @@ mod prim_pointer { }
 /// entirely different types. As a stopgap, trait implementations are
 /// statically generated up to size 32.
 ///
-/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]. This
-/// works because the [`Copy`][copy] trait is specially known to the compiler.
+/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]
+/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works
+/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known
+/// to the compiler.
 ///
 /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
 /// an array. Indeed, this provides most of the API for working with arrays.
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index dbb58991215..7c107177c64 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -343,7 +343,7 @@ impl Command {
     /// The search path to be used may be controlled by setting the
     /// `PATH` environment variable on the Command,
     /// but this has some implementation limitations on Windows
-    /// (see https://github.com/rust-lang/rust/issues/37519).
+    /// (see <https://github.com/rust-lang/rust/issues/37519>).
     ///
     /// # Examples
     ///
@@ -552,6 +552,12 @@ impl Command {
 
     /// Configuration for the child process's standard input (stdin) handle.
     ///
+    /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+    /// defaults to [`piped`] when used with `output`.
+    ///
+    /// [`inherit`]: struct.Stdio.html#method.inherit
+    /// [`piped`]: struct.Stdio.html#method.piped
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -572,6 +578,12 @@ impl Command {
 
     /// Configuration for the child process's standard output (stdout) handle.
     ///
+    /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+    /// defaults to [`piped`] when used with `output`.
+    ///
+    /// [`inherit`]: struct.Stdio.html#method.inherit
+    /// [`piped`]: struct.Stdio.html#method.piped
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -592,6 +604,12 @@ impl Command {
 
     /// Configuration for the child process's standard error (stderr) handle.
     ///
+    /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+    /// defaults to [`piped`] when used with `output`.
+    ///
+    /// [`inherit`]: struct.Stdio.html#method.inherit
+    /// [`piped`]: struct.Stdio.html#method.piped
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -702,6 +720,15 @@ impl AsInnerMut<imp::Command> for Command {
 }
 
 /// The output of a finished process.
+///
+/// This is returned in a Result by either the [`output`] method of a
+/// [`Command`], or the [`wait_with_output`] method of a [`Child`]
+/// process.
+///
+/// [`Command`]: struct.Command.html
+/// [`Child`]: struct.Child.html
+/// [`output`]: struct.Command.html#method.output
+/// [`wait_with_output`]: struct.Child.html#method.wait_with_output
 #[derive(PartialEq, Eq, Clone)]
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Output {
@@ -742,21 +769,128 @@ impl fmt::Debug for Output {
     }
 }
 
-/// Describes what to do with a standard I/O stream for a child process.
+/// Describes what to do with a standard I/O stream for a child process when
+/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`].
+///
+/// [`stdin`]: struct.Command.html#method.stdin
+/// [`stdout`]: struct.Command.html#method.stdout
+/// [`stderr`]: struct.Command.html#method.stderr
+/// [`Command`]: struct.Command.html
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Stdio(imp::Stdio);
 
 impl Stdio {
     /// A new pipe should be arranged to connect the parent and child processes.
+    ///
+    /// # Examples
+    ///
+    /// With stdout:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("echo")
+    ///     .arg("Hello, world!")
+    ///     .stdout(Stdio::piped())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n");
+    /// // Nothing echoed to console
+    /// ```
+    ///
+    /// With stdin:
+    ///
+    /// ```no_run
+    /// use std::io::Write;
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let mut child = Command::new("rev")
+    ///     .stdin(Stdio::piped())
+    ///     .stdout(Stdio::piped())
+    ///     .spawn()
+    ///     .expect("Failed to spawn child process");
+    ///
+    /// {
+    ///     let mut stdin = child.stdin.as_mut().expect("Failed to open stdin");
+    ///     stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin");
+    /// }
+    ///
+    /// let output = child.wait_with_output().expect("Failed to read stdout");
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n");
+    /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) }
 
     /// The child inherits from the corresponding parent descriptor.
+    ///
+    /// # Examples
+    ///
+    /// With stdout:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("echo")
+    ///     .arg("Hello, world!")
+    ///     .stdout(Stdio::inherit())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+    /// // "Hello, world!" echoed to console
+    /// ```
+    ///
+    /// With stdin:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("rev")
+    ///     .stdin(Stdio::inherit())
+    ///     .stdout(Stdio::piped())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout));
+    /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) }
 
     /// This stream will be ignored. This is the equivalent of attaching the
     /// stream to `/dev/null`
+    ///
+    /// # Examples
+    ///
+    /// With stdout:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("echo")
+    ///     .arg("Hello, world!")
+    ///     .stdout(Stdio::null())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+    /// // Nothing echoed to console
+    /// ```
+    ///
+    /// With stdin:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("rev")
+    ///     .stdin(Stdio::null())
+    ///     .stdout(Stdio::piped())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+    /// // Ignores any piped-in input
+    /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn null() -> Stdio { Stdio(imp::Stdio::Null) }
 }
@@ -1083,8 +1217,6 @@ impl Child {
 /// function and compute the exit code from its return value:
 ///
 /// ```
-/// use std::io::{self, Write};
-///
 /// fn run_app() -> Result<(), ()> {
 ///     // Application logic here
 ///     Ok(())
@@ -1094,7 +1226,7 @@ impl Child {
 ///     ::std::process::exit(match run_app() {
 ///        Ok(_) => 0,
 ///        Err(err) => {
-///            writeln!(io::stderr(), "error: {:?}", err).unwrap();
+///            eprintln!("error: {:?}", err);
 ///            1
 ///        }
 ///     });
diff --git a/src/libstd/sync/mpsc/cache_aligned.rs b/src/libstd/sync/mpsc/cache_aligned.rs
new file mode 100644
index 00000000000..5af01262573
--- /dev/null
+++ b/src/libstd/sync/mpsc/cache_aligned.rs
@@ -0,0 +1,37 @@
+// 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 ops::{Deref, DerefMut};
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(align(64))]
+pub(super) struct Aligner;
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+
+impl<T> Deref for CacheAligned<T> {
+     type Target = T;
+     fn deref(&self) -> &Self::Target {
+         &self.0
+     }
+}
+
+impl<T> DerefMut for CacheAligned<T> {
+     fn deref_mut(&mut self) -> &mut Self::Target {
+         &mut self.0
+     }
+}
+
+impl<T> CacheAligned<T> {
+    pub(super) fn new(t: T) -> Self {
+        CacheAligned(t, Aligner)
+    }
+}
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index dcd4c8dfdf5..45a26e594b0 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -297,6 +297,8 @@ mod sync;
 mod mpsc_queue;
 mod spsc_queue;
 
+mod cache_aligned;
+
 /// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type.
 /// This half can only be owned by one thread.
 ///
@@ -919,7 +921,7 @@ impl<T> Drop for Sender<T> {
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for Sender<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Sender {{ .. }}")
+        f.debug_struct("Sender").finish()
     }
 }
 
@@ -1049,7 +1051,7 @@ impl<T> Drop for SyncSender<T> {
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for SyncSender<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "SyncSender {{ .. }}")
+        f.debug_struct("SyncSender").finish()
     }
 }
 
@@ -1551,7 +1553,7 @@ impl<T> Drop for Receiver<T> {
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for Receiver<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Receiver {{ .. }}")
+        f.debug_struct("Receiver").finish()
     }
 }
 
@@ -3009,22 +3011,4 @@ mod sync_tests {
             repro()
         }
     }
-
-    #[test]
-    fn fmt_debug_sender() {
-        let (tx, _) = channel::<i32>();
-        assert_eq!(format!("{:?}", tx), "Sender { .. }");
-    }
-
-    #[test]
-    fn fmt_debug_recv() {
-        let (_, rx) = channel::<i32>();
-        assert_eq!(format!("{:?}", rx), "Receiver { .. }");
-    }
-
-    #[test]
-    fn fmt_debug_sync_sender() {
-        let (tx, _) = sync_channel::<i32>(1);
-        assert_eq!(format!("{:?}", tx), "SyncSender { .. }");
-    }
 }
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
index e49f4cff024..a9f3cea243f 100644
--- a/src/libstd/sync/mpsc/select.rs
+++ b/src/libstd/sync/mpsc/select.rs
@@ -354,13 +354,13 @@ impl Iterator for Packets {
 
 impl fmt::Debug for Select {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Select {{ .. }}")
+        f.debug_struct("Select").finish()
     }
 }
 
 impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Handle {{ .. }}")
+        f.debug_struct("Handle").finish()
     }
 }
 
@@ -774,18 +774,4 @@ mod tests {
             }
         }
     }
-
-    #[test]
-    fn fmt_debug_select() {
-        let sel = Select::new();
-        assert_eq!(format!("{:?}", sel), "Select { .. }");
-    }
-
-    #[test]
-    fn fmt_debug_handle() {
-        let (_, rx) = channel::<i32>();
-        let sel = Select::new();
-        let handle = sel.handle(&rx);
-        assert_eq!(format!("{:?}", handle), "Handle { .. }");
-    }
 }
diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs
index 1148bc66fba..cc4be92276a 100644
--- a/src/libstd/sync/mpsc/spsc_queue.rs
+++ b/src/libstd/sync/mpsc/spsc_queue.rs
@@ -22,12 +22,15 @@ use core::cell::UnsafeCell;
 
 use sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
 
+use super::cache_aligned::CacheAligned;
+
 // Node within the linked list queue of messages to send
 struct Node<T> {
     // FIXME: this could be an uninitialized T if we're careful enough, and
     //      that would reduce memory usage (and be a bit faster).
     //      is it worth it?
     value: Option<T>,           // nullable for re-use of nodes
+    cached: bool,               // This node goes into the node cache
     next: AtomicPtr<Node<T>>,   // next node in the queue
 }
 
@@ -35,38 +38,55 @@ struct Node<T> {
 /// but it can be safely shared in an Arc if it is guaranteed that there
 /// is only one popper and one pusher touching the queue at any one point in
 /// time.
-pub struct Queue<T> {
+pub struct Queue<T, ProducerAddition=(), ConsumerAddition=()> {
     // consumer fields
+    consumer: CacheAligned<Consumer<T, ConsumerAddition>>,
+
+    // producer fields
+    producer: CacheAligned<Producer<T, ProducerAddition>>,
+}
+
+struct Consumer<T, Addition> {
     tail: UnsafeCell<*mut Node<T>>, // where to pop from
     tail_prev: AtomicPtr<Node<T>>, // where to pop from
+    cache_bound: usize, // maximum cache size
+    cached_nodes: AtomicUsize, // number of nodes marked as cachable
+    addition: Addition,
+}
 
-    // producer fields
+struct Producer<T, Addition> {
     head: UnsafeCell<*mut Node<T>>,      // where to push to
     first: UnsafeCell<*mut Node<T>>,     // where to get new nodes from
     tail_copy: UnsafeCell<*mut Node<T>>, // between first/tail
-
-    // Cache maintenance fields. Additions and subtractions are stored
-    // separately in order to allow them to use nonatomic addition/subtraction.
-    cache_bound: usize,
-    cache_additions: AtomicUsize,
-    cache_subtractions: AtomicUsize,
+    addition: Addition,
 }
 
-unsafe impl<T: Send> Send for Queue<T> { }
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Send for Queue<T, P, C> { }
 
-unsafe impl<T: Send> Sync for Queue<T> { }
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Sync for Queue<T, P, C> { }
 
 impl<T> Node<T> {
     fn new() -> *mut Node<T> {
         Box::into_raw(box Node {
             value: None,
+            cached: false,
             next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
         })
     }
 }
 
-impl<T> Queue<T> {
-    /// Creates a new queue.
+impl<T, ProducerAddition, ConsumerAddition> Queue<T, ProducerAddition, ConsumerAddition> {
+
+    /// Creates a new queue. With given additional elements in the producer and
+    /// consumer portions of the queue.
+    ///
+    /// Due to the performance implications of cache-contention,
+    /// we wish to keep fields used mainly by the producer on a separate cache
+    /// line than those used by the consumer.
+    /// Since cache lines are usually 64 bytes, it is unreasonably expensive to
+    /// allocate one for small fields, so we allow users to insert additional
+    /// fields into the cache lines already allocated by this for the producer
+    /// and consumer.
     ///
     /// This is unsafe as the type system doesn't enforce a single
     /// consumer-producer relationship. It also allows the consumer to `pop`
@@ -83,19 +103,28 @@ impl<T> Queue<T> {
     ///               cache (if desired). If the value is 0, then the cache has
     ///               no bound. Otherwise, the cache will never grow larger than
     ///               `bound` (although the queue itself could be much larger.
-    pub unsafe fn new(bound: usize) -> Queue<T> {
+    pub unsafe fn with_additions(
+        bound: usize,
+        producer_addition: ProducerAddition,
+        consumer_addition: ConsumerAddition,
+    ) -> Self {
         let n1 = Node::new();
         let n2 = Node::new();
         (*n1).next.store(n2, Ordering::Relaxed);
         Queue {
-            tail: UnsafeCell::new(n2),
-            tail_prev: AtomicPtr::new(n1),
-            head: UnsafeCell::new(n2),
-            first: UnsafeCell::new(n1),
-            tail_copy: UnsafeCell::new(n1),
-            cache_bound: bound,
-            cache_additions: AtomicUsize::new(0),
-            cache_subtractions: AtomicUsize::new(0),
+            consumer: CacheAligned::new(Consumer {
+                tail: UnsafeCell::new(n2),
+                tail_prev: AtomicPtr::new(n1),
+                cache_bound: bound,
+                cached_nodes: AtomicUsize::new(0),
+                addition: consumer_addition
+            }),
+            producer: CacheAligned::new(Producer {
+                head: UnsafeCell::new(n2),
+                first: UnsafeCell::new(n1),
+                tail_copy: UnsafeCell::new(n1),
+                addition: producer_addition
+            }),
         }
     }
 
@@ -109,35 +138,25 @@ impl<T> Queue<T> {
             assert!((*n).value.is_none());
             (*n).value = Some(t);
             (*n).next.store(ptr::null_mut(), Ordering::Relaxed);
-            (**self.head.get()).next.store(n, Ordering::Release);
-            *self.head.get() = n;
+            (**self.producer.head.get()).next.store(n, Ordering::Release);
+            *(&self.producer.head).get() = n;
         }
     }
 
     unsafe fn alloc(&self) -> *mut Node<T> {
         // First try to see if we can consume the 'first' node for our uses.
-        // We try to avoid as many atomic instructions as possible here, so
-        // the addition to cache_subtractions is not atomic (plus we're the
-        // only one subtracting from the cache).
-        if *self.first.get() != *self.tail_copy.get() {
-            if self.cache_bound > 0 {
-                let b = self.cache_subtractions.load(Ordering::Relaxed);
-                self.cache_subtractions.store(b + 1, Ordering::Relaxed);
-            }
-            let ret = *self.first.get();
-            *self.first.get() = (*ret).next.load(Ordering::Relaxed);
+        if *self.producer.first.get() != *self.producer.tail_copy.get() {
+            let ret = *self.producer.first.get();
+            *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
             return ret;
         }
         // If the above fails, then update our copy of the tail and try
         // again.
-        *self.tail_copy.get() = self.tail_prev.load(Ordering::Acquire);
-        if *self.first.get() != *self.tail_copy.get() {
-            if self.cache_bound > 0 {
-                let b = self.cache_subtractions.load(Ordering::Relaxed);
-                self.cache_subtractions.store(b + 1, Ordering::Relaxed);
-            }
-            let ret = *self.first.get();
-            *self.first.get() = (*ret).next.load(Ordering::Relaxed);
+        *self.producer.0.tail_copy.get() =
+            self.consumer.tail_prev.load(Ordering::Acquire);
+        if *self.producer.first.get() != *self.producer.tail_copy.get() {
+            let ret = *self.producer.first.get();
+            *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
             return ret;
         }
         // If all of that fails, then we have to allocate a new node
@@ -153,27 +172,27 @@ impl<T> Queue<T> {
             // sentinel from where we should start popping from. Hence, look at
             // tail's next field and see if we can use it. If we do a pop, then
             // the current tail node is a candidate for going into the cache.
-            let tail = *self.tail.get();
+            let tail = *self.consumer.tail.get();
             let next = (*tail).next.load(Ordering::Acquire);
             if next.is_null() { return None }
             assert!((*next).value.is_some());
             let ret = (*next).value.take();
 
-            *self.tail.get() = next;
-            if self.cache_bound == 0 {
-                self.tail_prev.store(tail, Ordering::Release);
+            *self.consumer.0.tail.get() = next;
+            if self.consumer.cache_bound == 0 {
+                self.consumer.tail_prev.store(tail, Ordering::Release);
             } else {
-                // FIXME: this is dubious with overflow.
-                let additions = self.cache_additions.load(Ordering::Relaxed);
-                let subtractions = self.cache_subtractions.load(Ordering::Relaxed);
-                let size = additions - subtractions;
-
-                if size < self.cache_bound {
-                    self.tail_prev.store(tail, Ordering::Release);
-                    self.cache_additions.store(additions + 1, Ordering::Relaxed);
+                let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed);
+                if cached_nodes < self.consumer.cache_bound && !(*tail).cached {
+                    self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed);
+                    (*tail).cached = true;
+                }
+
+                if (*tail).cached {
+                    self.consumer.tail_prev.store(tail, Ordering::Release);
                 } else {
-                    (*self.tail_prev.load(Ordering::Relaxed))
-                          .next.store(next, Ordering::Relaxed);
+                    (*self.consumer.tail_prev.load(Ordering::Relaxed))
+                        .next.store(next, Ordering::Relaxed);
                     // We have successfully erased all references to 'tail', so
                     // now we can safely drop it.
                     let _: Box<Node<T>> = Box::from_raw(tail);
@@ -194,17 +213,25 @@ impl<T> Queue<T> {
         // This is essentially the same as above with all the popping bits
         // stripped out.
         unsafe {
-            let tail = *self.tail.get();
+            let tail = *self.consumer.tail.get();
             let next = (*tail).next.load(Ordering::Acquire);
             if next.is_null() { None } else { (*next).value.as_mut() }
         }
     }
+
+    pub fn producer_addition(&self) -> &ProducerAddition {
+        &self.producer.addition
+    }
+
+    pub fn consumer_addition(&self) -> &ConsumerAddition {
+        &self.consumer.addition
+    }
 }
 
-impl<T> Drop for Queue<T> {
+impl<T, ProducerAddition, ConsumerAddition> Drop for Queue<T, ProducerAddition, ConsumerAddition> {
     fn drop(&mut self) {
         unsafe {
-            let mut cur = *self.first.get();
+            let mut cur = *self.producer.first.get();
             while !cur.is_null() {
                 let next = (*cur).next.load(Ordering::Relaxed);
                 let _n: Box<Node<T>> = Box::from_raw(cur);
@@ -224,7 +251,7 @@ mod tests {
     #[test]
     fn smoke() {
         unsafe {
-            let queue = Queue::new(0);
+            let queue = Queue::with_additions(0, (), ());
             queue.push(1);
             queue.push(2);
             assert_eq!(queue.pop(), Some(1));
@@ -241,7 +268,7 @@ mod tests {
     #[test]
     fn peek() {
         unsafe {
-            let queue = Queue::new(0);
+            let queue = Queue::with_additions(0, (), ());
             queue.push(vec![1]);
 
             // Ensure the borrowchecker works
@@ -264,7 +291,7 @@ mod tests {
     #[test]
     fn drop_full() {
         unsafe {
-            let q: Queue<Box<_>> = Queue::new(0);
+            let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
             q.push(box 1);
             q.push(box 2);
         }
@@ -273,7 +300,7 @@ mod tests {
     #[test]
     fn smoke_bound() {
         unsafe {
-            let q = Queue::new(0);
+            let q = Queue::with_additions(0, (), ());
             q.push(1);
             q.push(2);
             assert_eq!(q.pop(), Some(1));
@@ -295,7 +322,7 @@ mod tests {
         }
 
         unsafe fn stress_bound(bound: usize) {
-            let q = Arc::new(Queue::new(bound));
+            let q = Arc::new(Queue::with_additions(bound, (), ()));
 
             let (tx, rx) = channel();
             let q2 = q.clone();
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
index 47cd8977fda..d1515eba68c 100644
--- a/src/libstd/sync/mpsc/stream.rs
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -41,15 +41,22 @@ const MAX_STEALS: isize = 5;
 const MAX_STEALS: isize = 1 << 20;
 
 pub struct Packet<T> {
-    queue: spsc::Queue<Message<T>>, // internal queue for all message
+    // internal queue for all messages
+    queue: spsc::Queue<Message<T>, ProducerAddition, ConsumerAddition>,
+}
 
+struct ProducerAddition {
     cnt: AtomicIsize, // How many items are on this channel
-    steals: UnsafeCell<isize>, // How many times has a port received without blocking?
     to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
 
     port_dropped: AtomicBool, // flag if the channel has been destroyed.
 }
 
+struct ConsumerAddition {
+    steals: UnsafeCell<isize>,  // How many times has a port received without blocking?
+}
+
+
 pub enum Failure<T> {
     Empty,
     Disconnected,
@@ -78,13 +85,18 @@ enum Message<T> {
 impl<T> Packet<T> {
     pub fn new() -> Packet<T> {
         Packet {
-            queue: unsafe { spsc::Queue::new(128) },
-
-            cnt: AtomicIsize::new(0),
-            steals: UnsafeCell::new(0),
-            to_wake: AtomicUsize::new(0),
-
-            port_dropped: AtomicBool::new(false),
+            queue: unsafe { spsc::Queue::with_additions(
+                128,
+                ProducerAddition {
+                    cnt: AtomicIsize::new(0),
+                    to_wake: AtomicUsize::new(0),
+
+                    port_dropped: AtomicBool::new(false),
+                },
+                ConsumerAddition {
+                    steals: UnsafeCell::new(0),
+                }
+            )},
         }
     }
 
@@ -92,7 +104,7 @@ impl<T> Packet<T> {
         // If the other port has deterministically gone away, then definitely
         // must return the data back up the stack. Otherwise, the data is
         // considered as being sent.
-        if self.port_dropped.load(Ordering::SeqCst) { return Err(t) }
+        if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) }
 
         match self.do_send(Data(t)) {
             UpSuccess | UpDisconnected => {},
@@ -104,14 +116,16 @@ impl<T> Packet<T> {
     pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
         // If the port has gone away, then there's no need to proceed any
         // further.
-        if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected }
+        if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) {
+            return UpDisconnected
+        }
 
         self.do_send(GoUp(up))
     }
 
     fn do_send(&self, t: Message<T>) -> UpgradeResult {
         self.queue.push(t);
-        match self.cnt.fetch_add(1, Ordering::SeqCst) {
+        match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) {
             // As described in the mod's doc comment, -1 == wakeup
             -1 => UpWoke(self.take_to_wake()),
             // As as described before, SPSC queues must be >= -2
@@ -125,7 +139,7 @@ impl<T> Packet<T> {
             // will never remove this data. We can only have at most one item to
             // drain (the port drains the rest).
             DISCONNECTED => {
-                self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
                 let first = self.queue.pop();
                 let second = self.queue.pop();
                 assert!(second.is_none());
@@ -144,8 +158,8 @@ impl<T> Packet<T> {
 
     // Consumes ownership of the 'to_wake' field.
     fn take_to_wake(&self) -> SignalToken {
-        let ptr = self.to_wake.load(Ordering::SeqCst);
-        self.to_wake.store(0, Ordering::SeqCst);
+        let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst);
+        self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
         assert!(ptr != 0);
         unsafe { SignalToken::cast_from_usize(ptr) }
     }
@@ -154,14 +168,16 @@ impl<T> Packet<T> {
     // back if it shouldn't sleep. Note that this is the location where we take
     // steals into account.
     fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
         let ptr = unsafe { token.cast_to_usize() };
-        self.to_wake.store(ptr, Ordering::SeqCst);
+        self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst);
 
-        let steals = unsafe { ptr::replace(self.steals.get(), 0) };
+        let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) };
 
-        match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
-            DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
+        match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
+            DISCONNECTED => {
+                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
+            }
             // If we factor in our steals and notice that the channel has no
             // data, we successfully sleep
             n => {
@@ -170,7 +186,7 @@ impl<T> Packet<T> {
             }
         }
 
-        self.to_wake.store(0, Ordering::SeqCst);
+        self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
         Err(unsafe { SignalToken::cast_from_usize(ptr) })
     }
 
@@ -201,7 +217,7 @@ impl<T> Packet<T> {
             // "steal" factored into the channel count above).
             data @ Ok(..) |
             data @ Err(Upgraded(..)) => unsafe {
-                *self.steals.get() -= 1;
+                *self.queue.consumer_addition().steals.get() -= 1;
                 data
             },
 
@@ -223,20 +239,21 @@ impl<T> Packet<T> {
             // down as much as possible (without going negative), and then
             // adding back in whatever we couldn't factor into steals.
             Some(data) => unsafe {
-                if *self.steals.get() > MAX_STEALS {
-                    match self.cnt.swap(0, Ordering::SeqCst) {
+                if *self.queue.consumer_addition().steals.get() > MAX_STEALS {
+                    match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) {
                         DISCONNECTED => {
-                            self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+                            self.queue.producer_addition().cnt.store(
+                                DISCONNECTED, Ordering::SeqCst);
                         }
                         n => {
-                            let m = cmp::min(n, *self.steals.get());
-                            *self.steals.get() -= m;
+                            let m = cmp::min(n, *self.queue.consumer_addition().steals.get());
+                            *self.queue.consumer_addition().steals.get() -= m;
                             self.bump(n - m);
                         }
                     }
-                    assert!(*self.steals.get() >= 0);
+                    assert!(*self.queue.consumer_addition().steals.get() >= 0);
                 }
-                *self.steals.get() += 1;
+                *self.queue.consumer_addition().steals.get() += 1;
                 match data {
                     Data(t) => Ok(t),
                     GoUp(up) => Err(Upgraded(up)),
@@ -244,7 +261,7 @@ impl<T> Packet<T> {
             },
 
             None => {
-                match self.cnt.load(Ordering::SeqCst) {
+                match self.queue.producer_addition().cnt.load(Ordering::SeqCst) {
                     n if n != DISCONNECTED => Err(Empty),
 
                     // This is a little bit of a tricky case. We failed to pop
@@ -273,7 +290,7 @@ impl<T> Packet<T> {
     pub fn drop_chan(&self) {
         // Dropping a channel is pretty simple, we just flag it as disconnected
         // and then wakeup a blocker if there is one.
-        match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
+        match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) {
             -1 => { self.take_to_wake().signal(); }
             DISCONNECTED => {}
             n => { assert!(n >= 0); }
@@ -300,7 +317,7 @@ impl<T> Packet<T> {
         // sends are gated on this flag, so we're immediately guaranteed that
         // there are a bounded number of active sends that we'll have to deal
         // with.
-        self.port_dropped.store(true, Ordering::SeqCst);
+        self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst);
 
         // Now that we're guaranteed to deal with a bounded number of senders,
         // we need to drain the queue. This draining process happens atomically
@@ -310,9 +327,9 @@ impl<T> Packet<T> {
         // continue to fail while active senders send data while we're dropping
         // data, but eventually we're guaranteed to break out of this loop
         // (because there is a bounded number of senders).
-        let mut steals = unsafe { *self.steals.get() };
+        let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
         while {
-            let cnt = self.cnt.compare_and_swap(
+            let cnt = self.queue.producer_addition().cnt.compare_and_swap(
                             steals, DISCONNECTED, Ordering::SeqCst);
             cnt != DISCONNECTED && cnt != steals
         } {
@@ -353,9 +370,9 @@ impl<T> Packet<T> {
 
     // increment the count on the channel (used for selection)
     fn bump(&self, amt: isize) -> isize {
-        match self.cnt.fetch_add(amt, Ordering::SeqCst) {
+        match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
             DISCONNECTED => {
-                self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
                 DISCONNECTED
             }
             n => n
@@ -404,8 +421,8 @@ impl<T> Packet<T> {
         // this end. This is fine because we know it's a small bounded windows
         // of time until the data is actually sent.
         if was_upgrade {
-            assert_eq!(unsafe { *self.steals.get() }, 0);
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0);
+            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
             return Ok(true)
         }
 
@@ -418,7 +435,7 @@ impl<T> Packet<T> {
         // If we were previously disconnected, then we know for sure that there
         // is no thread in to_wake, so just keep going
         let has_data = if prev == DISCONNECTED {
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
             true // there is data, that data is that we're disconnected
         } else {
             let cur = prev + steals + 1;
@@ -441,13 +458,13 @@ impl<T> Packet<T> {
             if prev < 0 {
                 drop(self.take_to_wake());
             } else {
-                while self.to_wake.load(Ordering::SeqCst) != 0 {
+                while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 {
                     thread::yield_now();
                 }
             }
             unsafe {
-                assert_eq!(*self.steals.get(), 0);
-                *self.steals.get() = steals;
+                assert_eq!(*self.queue.consumer_addition().steals.get(), 0);
+                *self.queue.consumer_addition().steals.get() = steals;
             }
 
             // if we were previously positive, then there's surely data to
@@ -481,7 +498,7 @@ impl<T> Drop for Packet<T> {
         // disconnection, but also a proper fence before the read of
         // `to_wake`, so this assert cannot be removed with also removing
         // the `to_wake` assert.
-        assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED);
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+        assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED);
+        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
     }
 }
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 1d62853e906..eb507858b92 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -394,11 +394,18 @@ impl<T: ?Sized + Default> Default for Mutex<T> {
 impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.try_lock() {
-            Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
+            Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
             Err(TryLockError::Poisoned(err)) => {
-                write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
+                f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish()
             },
-            Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
+            Err(TryLockError::WouldBlock) => {
+                struct LockedPlaceholder;
+                impl fmt::Debug for LockedPlaceholder {
+                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+                }
+
+                f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish()
+            }
         }
     }
 }
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 015106fc2e5..30dbf02087d 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -103,8 +103,8 @@ unsafe impl Sync for Once {}
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl Send for Once {}
 
-/// State yielded to the [`call_once_force`] method which can be used to query
-/// whether the [`Once`] was previously poisoned or not.
+/// State yielded to [`call_once_force`]’s closure parameter. The state can be
+/// used to query the poison status of the [`Once`].
 ///
 /// [`call_once_force`]: struct.Once.html#method.call_once_force
 /// [`Once`]: struct.Once.html
@@ -230,17 +230,50 @@ impl Once {
 
     /// Performs the same function as [`call_once`] except ignores poisoning.
     ///
+    /// Unlike [`call_once`], if this `Once` has been poisoned (i.e. a previous
+    /// call to `call_once` or `call_once_force` caused a panic), calling
+    /// `call_once_force` will still invoke the closure `f` and will _not_
+    /// result in an immediate panic. If `f` panics, the `Once` will remain
+    /// in a poison state. If `f` does _not_ panic, the `Once` will no
+    /// longer be in a poison state and all future calls to `call_once` or
+    /// `call_one_force` will no-op.
+    ///
+    /// The closure `f` is yielded a [`OnceState`] structure which can be used
+    /// to query the poison status of the `Once`.
+    ///
     /// [`call_once`]: struct.Once.html#method.call_once
+    /// [`OnceState`]: struct.OnceState.html
     ///
-    /// If this `Once` has been poisoned (some initialization panicked) then
-    /// this function will continue to attempt to call initialization functions
-    /// until one of them doesn't panic.
+    /// # Examples
     ///
-    /// The closure `f` is yielded a [`OnceState`] structure which can be used to query the
-    /// state of this `Once` (whether initialization has previously panicked or
-    /// not).
+    /// ```
+    /// #![feature(once_poison)]
     ///
-    /// [`OnceState`]: struct.OnceState.html
+    /// use std::sync::{Once, ONCE_INIT};
+    /// use std::thread;
+    ///
+    /// static INIT: Once = ONCE_INIT;
+    ///
+    /// // poison the once
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| panic!());
+    /// });
+    /// assert!(handle.join().is_err());
+    ///
+    /// // poisoning propagates
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| {});
+    /// });
+    /// assert!(handle.join().is_err());
+    ///
+    /// // call_once_force will still run and reset the poisoned state
+    /// INIT.call_once_force(|state| {
+    ///     assert!(state.poisoned());
+    /// });
+    ///
+    /// // once any success happens, we stop propagating the poison
+    /// INIT.call_once(|| {});
+    /// ```
     #[unstable(feature = "once_poison", issue = "33577")]
     pub fn call_once_force<F>(&'static self, f: F) where F: FnOnce(&OnceState) {
         // same as above, just with a different parameter to `call_inner`.
@@ -386,12 +419,47 @@ impl Drop for Finish {
 }
 
 impl OnceState {
-    /// Returns whether the associated [`Once`] has been poisoned.
-    ///
-    /// Once an initialization routine for a [`Once`] has panicked it will forever
-    /// indicate to future forced initialization routines that it is poisoned.
+    /// Returns whether the associated [`Once`] was poisoned prior to the
+    /// invocation of the closure passed to [`call_once_force`].
     ///
+    /// [`call_once_force`]: struct.Once.html#method.call_once_force
     /// [`Once`]: struct.Once.html
+    ///
+    /// # Examples
+    ///
+    /// A poisoned `Once`:
+    ///
+    /// ```
+    /// #![feature(once_poison)]
+    ///
+    /// use std::sync::{Once, ONCE_INIT};
+    /// use std::thread;
+    ///
+    /// static INIT: Once = ONCE_INIT;
+    ///
+    /// // poison the once
+    /// let handle = thread::spawn(|| {
+    ///     INIT.call_once(|| panic!());
+    /// });
+    /// assert!(handle.join().is_err());
+    ///
+    /// INIT.call_once_force(|state| {
+    ///     assert!(state.poisoned());
+    /// });
+    /// ```
+    ///
+    /// An unpoisoned `Once`:
+    ///
+    /// ```
+    /// #![feature(once_poison)]
+    ///
+    /// use std::sync::{Once, ONCE_INIT};
+    ///
+    /// static INIT: Once = ONCE_INIT;
+    ///
+    /// INIT.call_once_force(|state| {
+    ///     assert!(!state.poisoned());
+    /// });
     #[unstable(feature = "once_poison", issue = "33577")]
     pub fn poisoned(&self) -> bool {
         self.poisoned
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index 4757faabfb8..5c49d6b5845 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -428,11 +428,18 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
 impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.try_read() {
-            Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard),
+            Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(),
             Err(TryLockError::Poisoned(err)) => {
-                write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref())
+                f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish()
             },
-            Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ <locked> }}")
+            Err(TryLockError::WouldBlock) => {
+                struct LockedPlaceholder;
+                impl fmt::Debug for LockedPlaceholder {
+                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+                }
+
+                f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish()
+            }
         }
     }
 }
diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs
index 89a44b97657..4f878d8ad1f 100644
--- a/src/libstd/sys/unix/condvar.rs
+++ b/src/libstd/sys/unix/condvar.rs
@@ -92,14 +92,15 @@ impl Condvar {
         assert_eq!(r, 0);
 
         // Nanosecond calculations can't overflow because both values are below 1e9.
-        let nsec = dur.subsec_nanos() as libc::c_long + now.tv_nsec as libc::c_long;
+        let nsec = dur.subsec_nanos() + now.tv_nsec as u32;
+
         let sec = saturating_cast_to_time_t(dur.as_secs())
             .checked_add((nsec / 1_000_000_000) as libc::time_t)
             .and_then(|s| s.checked_add(now.tv_sec));
         let nsec = nsec % 1_000_000_000;
 
         let timeout = sec.map(|s| {
-            libc::timespec { tv_sec: s, tv_nsec: nsec }
+            libc::timespec { tv_sec: s, tv_nsec: nsec as _}
         }).unwrap_or(TIMESPEC_MAX);
 
         let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
index 3d9a06bedd5..00cf7eca75d 100644
--- a/src/libstd/sys/unix/env.rs
+++ b/src/libstd/sys/unix/env.rs
@@ -118,27 +118,6 @@ pub mod os {
     pub const EXE_EXTENSION: &'static str = "";
 }
 
-#[cfg(all(target_os = "nacl", not(target_arch = "le32")))]
-pub mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "nacl";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".so";
-    pub const DLL_EXTENSION: &'static str = "so";
-    pub const EXE_SUFFIX: &'static str = ".nexe";
-    pub const EXE_EXTENSION: &'static str = "nexe";
-}
-#[cfg(all(target_os = "nacl", target_arch = "le32"))]
-pub mod os {
-    pub const FAMILY: &'static str = "unix";
-    pub const OS: &'static str = "pnacl";
-    pub const DLL_PREFIX: &'static str = "lib";
-    pub const DLL_SUFFIX: &'static str = ".pso";
-    pub const DLL_EXTENSION: &'static str = "pso";
-    pub const EXE_SUFFIX: &'static str = ".pexe";
-    pub const EXE_EXTENSION: &'static str = "pexe";
-}
-
 #[cfg(target_os = "haiku")]
 pub mod os {
     pub const FAMILY: &'static str = "unix";
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index c4616c3b395..a1ca839dc18 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -132,14 +132,14 @@ impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(libc::timespec {
             tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: self.stat.st_mtime_nsec as libc::c_long,
+            tv_nsec: self.stat.st_mtime_nsec as _,
         }))
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
         Ok(SystemTime::from(libc::timespec {
             tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: self.stat.st_atime_nsec as libc::c_long,
+            tv_nsec: self.stat.st_atime_nsec as _,
         }))
     }
 
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 1b3f1000b77..c2772e2e2cc 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -22,7 +22,6 @@ use libc;
 #[cfg(all(not(dox), target_os = "haiku"))]     pub use os::haiku as platform;
 #[cfg(all(not(dox), target_os = "ios"))]       pub use os::ios as platform;
 #[cfg(all(not(dox), target_os = "macos"))]     pub use os::macos as platform;
-#[cfg(all(not(dox), target_os = "nacl"))]      pub use os::nacl as platform;
 #[cfg(all(not(dox), target_os = "netbsd"))]    pub use os::netbsd as platform;
 #[cfg(all(not(dox), target_os = "openbsd"))]   pub use os::openbsd as platform;
 #[cfg(all(not(dox), target_os = "solaris"))]   pub use os::solaris as platform;
@@ -77,11 +76,11 @@ pub fn init() {
         reset_sigpipe();
     }
 
-    #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
+    #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
-    #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))]
+    #[cfg(any(target_os = "emscripten", target_os="fuchsia"))]
     unsafe fn reset_sigpipe() {}
 }
 
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index c8019d1c768..e775f857f2b 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -176,11 +176,16 @@ impl Socket {
                 }
                 0 => {}
                 _ => {
-                    if pollfd.revents & libc::POLLOUT == 0 {
-                        if let Some(e) = self.take_error()? {
-                            return Err(e);
-                        }
+                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+                    // for POLLHUP rather than read readiness
+                    if pollfd.revents & libc::POLLHUP != 0 {
+                        let e = self.take_error()?
+                            .unwrap_or_else(|| {
+                                io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+                            });
+                        return Err(e);
                     }
+
                     return Ok(());
                 }
             }
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 5ef98d24710..d8c30534eed 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -483,12 +483,10 @@ pub fn home_dir() -> Option<PathBuf> {
 
     #[cfg(any(target_os = "android",
               target_os = "ios",
-              target_os = "nacl",
               target_os = "emscripten"))]
     unsafe fn fallback() -> Option<OsString> { None }
     #[cfg(not(any(target_os = "android",
                   target_os = "ios",
-                  target_os = "nacl",
                   target_os = "emscripten")))]
     unsafe fn fallback() -> Option<OsString> {
         let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index 689ccd78524..383434b1cd8 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -464,7 +464,6 @@ mod tests {
     // test from being flaky we ignore it on macOS.
     #[test]
     #[cfg_attr(target_os = "macos", ignore)]
-    #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl.
     // When run under our current QEMU emulation test suite this test fails,
     // although the reason isn't very clear as to why. For now this test is
     // ignored there.
diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs
index 5d34da04446..a7a67ed36e8 100644
--- a/src/libstd/sys/unix/process/process_fuchsia.rs
+++ b/src/libstd/sys/unix/process/process_fuchsia.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use io;
-use libc;
+use libc::{self, size_t};
 use mem;
 use ptr;
 
@@ -148,8 +148,8 @@ impl Process {
         use sys::process::zircon::*;
 
         let mut proc_info: zx_info_process_t = Default::default();
-        let mut actual: zx_size_t = 0;
-        let mut avail: zx_size_t = 0;
+        let mut actual: size_t = 0;
+        let mut avail: size_t = 0;
 
         unsafe {
             zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
@@ -171,8 +171,8 @@ impl Process {
         use sys::process::zircon::*;
 
         let mut proc_info: zx_info_process_t = Default::default();
-        let mut actual: zx_size_t = 0;
-        let mut avail: zx_size_t = 0;
+        let mut actual: size_t = 0;
+        let mut avail: size_t = 0;
 
         unsafe {
             let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED,
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index 870db820027..743c458d580 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -184,8 +184,8 @@ impl Command {
             *sys::os::environ() = envp.as_ptr();
         }
 
-        // NaCl has no signal support.
-        #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))]
+        // emscripten has no signal support.
+        #[cfg(not(any(target_os = "emscripten")))]
         {
             use mem;
             // Reset signal handling so the child process starts in a
diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs
index b5ec11b40fd..90864e6ef3f 100644
--- a/src/libstd/sys/unix/process/zircon.rs
+++ b/src/libstd/sys/unix/process/zircon.rs
@@ -15,15 +15,13 @@ use io;
 use os::raw::c_char;
 use u64;
 
-use libc::{c_int, c_void};
+use libc::{c_int, c_void, size_t};
 
-pub type zx_handle_t = i32;
+pub type zx_handle_t = u32;
 pub type zx_vaddr_t = usize;
 pub type zx_rights_t = u32;
 pub type zx_status_t = i32;
 
-pub type zx_size_t = usize;
-
 pub const ZX_HANDLE_INVALID: zx_handle_t = 0;
 
 pub type zx_time_t = u64;
@@ -115,36 +113,37 @@ extern {
                               pending: *mut zx_signals_t) -> zx_status_t;
 
     pub fn zx_object_get_info(handle: zx_handle_t, topic: u32, buffer: *mut c_void,
-                              buffer_size: zx_size_t, actual_size: *mut zx_size_t,
-                              avail: *mut zx_size_t) -> zx_status_t;
+                              buffer_size: size_t, actual_size: *mut size_t,
+                              avail: *mut size_t) -> zx_status_t;
 }
 
 // From `enum special_handles` in system/ulib/launchpad/launchpad.c
 // HND_LOADER_SVC = 0
 // HND_EXEC_VMO = 1
-pub const HND_SPECIAL_COUNT: usize = 2;
+// HND_SEGMENTS_VMAR = 2
+const HND_SPECIAL_COUNT: c_int = 3;
 
 #[repr(C)]
 pub struct launchpad_t {
     argc: u32,
     envc: u32,
     args: *const c_char,
-    args_len: usize,
+    args_len: size_t,
     env: *const c_char,
-    env_len: usize,
+    env_len: size_t,
 
     handles: *mut zx_handle_t,
     handles_info: *mut u32,
-    handle_count: usize,
-    handle_alloc: usize,
+    handle_count: size_t,
+    handle_alloc: size_t,
 
     entry: zx_vaddr_t,
     base: zx_vaddr_t,
     vdso_base: zx_vaddr_t,
 
-    stack_size: usize,
+    stack_size: size_t,
 
-    special_handles: [zx_handle_t; HND_SPECIAL_COUNT],
+    special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize],
     loader_message: bool,
 }
 
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index 6c4a3324296..cc889454ce9 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -149,7 +149,7 @@ impl Thread {
 
     pub fn sleep(dur: Duration) {
         let mut secs = dur.as_secs();
-        let mut nsecs = dur.subsec_nanos() as libc::c_long;
+        let mut nsecs = dur.subsec_nanos() as _;
 
         // If we're awoken with a signal then the return value will be -1 and
         // nanosleep will fill in `ts` with the remaining time.
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index c1bea95ce91..837cd7292e2 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -60,7 +60,7 @@ impl Timespec {
         Timespec {
             t: libc::timespec {
                 tv_sec: secs,
-                tv_nsec: nsec as libc::c_long,
+                tv_nsec: nsec as _,
             },
         }
     }
@@ -83,7 +83,7 @@ impl Timespec {
         Timespec {
             t: libc::timespec {
                 tv_sec: secs,
-                tv_nsec: nsec as libc::c_long,
+                tv_nsec: nsec as _,
             },
         }
     }
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 762e39809cc..39e00270233 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -37,7 +37,6 @@ pub type BOOL = c_int;
 pub type BYTE = u8;
 pub type BOOLEAN = BYTE;
 pub type GROUP = c_uint;
-pub type LONG_PTR = isize;
 pub type LARGE_INTEGER = c_longlong;
 pub type LONG = c_long;
 pub type UINT = c_uint;
@@ -46,7 +45,6 @@ pub type USHORT = c_ushort;
 pub type SIZE_T = usize;
 pub type WORD = u16;
 pub type CHAR = c_char;
-pub type HCRYPTPROV = LONG_PTR;
 pub type ULONG_PTR = usize;
 pub type ULONG = c_ulong;
 #[cfg(target_arch = "x86_64")]
@@ -288,10 +286,6 @@ pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c;
 #[cfg(feature = "backtrace")]
 pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664;
 
-pub const PROV_RSA_FULL: DWORD = 1;
-pub const CRYPT_SILENT: DWORD = 64;
-pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
-
 pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
 pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
 pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
@@ -1136,15 +1130,6 @@ extern "system" {
     pub fn GetProcAddress(handle: HMODULE,
                           name: LPCSTR) -> *mut c_void;
     pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
-    pub fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
-                                pszContainer: LPCSTR,
-                                pszProvider: LPCSTR,
-                                dwProvType: DWORD,
-                                dwFlags: DWORD) -> BOOL;
-    pub fn CryptGenRandom(hProv: HCRYPTPROV,
-                          dwLen: DWORD,
-                          pbBuffer: *mut BYTE) -> BOOL;
-    pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
 
     pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
 
@@ -1175,6 +1160,9 @@ extern "system" {
                   writefds: *mut fd_set,
                   exceptfds: *mut fd_set,
                   timeout: *const timeval) -> c_int;
+
+    #[link_name = "SystemFunction036"]
+    pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
 }
 
 // Functions that aren't available on every version of Windows that we support,
diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs
index 3f6c2827a3f..d6b8896ac09 100644
--- a/src/libstd/sys/windows/ext/ffi.rs
+++ b/src/libstd/sys/windows/ext/ffi.rs
@@ -9,6 +9,62 @@
 // except according to those terms.
 
 //! Windows-specific extensions to the primitives in the `std::ffi` module.
+//!
+//! # Overview
+//!
+//! For historical reasons, the Windows API uses a form of potentially
+//! ill-formed UTF-16 encoding for strings.  Specifically, the 16-bit
+//! code units in Windows strings may contain [isolated surrogate code
+//! points which are not paired together][ill-formed-utf-16].  The
+//! Unicode standard requires that surrogate code points (those in the
+//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
+//! encoding a *surrogate code unit pair* is used to encode a single
+//! character.  For compatibility with code that does not enforce
+//! these pairings, Windows does not enforce them, either.
+//!
+//! While it is not always possible to convert such a string losslessly into
+//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
+//! able to round-trip such a string from and to Windows APIs
+//! losslessly.  For example, some Rust code may be "bridging" some
+//! Windows APIs together, just passing `WCHAR` strings among those
+//! APIs without ever really looking into the strings.
+//!
+//! If Rust code *does* need to look into those strings, it can
+//! convert them to valid UTF-8, possibly lossily, by substituting
+//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is
+//! conventionally done in other Rust APIs that deal with string
+//! encodings.
+//!
+//! # `OsStringExt` and `OsStrExt`
+//!
+//! [`OsString`] is the Rust wrapper for owned strings in the
+//! preferred representation of the operating system.  On Windows,
+//! this struct gets augmented with an implementation of the
+//! [`OsStringExt`] trait, which has a [`from_wide`] method.  This
+//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
+//! you get such a slice out of a `WCHAR` Windows API.
+//!
+//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
+//! preferred representation of the operating system.  On Windows, the
+//! [`OsStrExt`] trait provides the [`encode_wide`] method, which
+//! outputs an [`EncodeWide`] iterator.  You can [`collect`] this
+//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
+//! pointer to this vector's contents and feed it to Windows APIs.
+//!
+//! These traits, along with [`OsString`] and [`OsStr`], work in
+//! conjunction so that it is possible to **round-trip** strings from
+//! Windows and back, with no loss of data, even if the strings are
+//! ill-formed UTF-16.
+//!
+//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
+//! [`OsString`]: ../../../ffi/struct.OsString.html
+//! [`OsStr`]: ../../../ffi/struct.OsStr.html
+//! [`OsStringExt`]: trait.OsStringExt.html
+//! [`OsStrExt`]: trait.OsStrExt.html
+//! [`EncodeWide`]: struct.EncodeWide.html
+//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
+//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index d58a3505154..24c41046f26 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -32,7 +32,7 @@ pub trait FileExt {
     /// function, it is set to the end of the read.
     ///
     /// Reading beyond the end of the file will always return with a length of
-    /// 0.
+    /// 0\.
     ///
     /// Note that similar to `File::read`, it is not an error to return with a
     /// short read. When returning from such a short read, the file pointer is
@@ -393,8 +393,8 @@ pub trait MetadataExt {
     /// to. For a directory, the structure specifies when the directory was
     /// created.
     ///
-    /// If the underlying filesystem does not support the last write time
-    /// time, the returned value is 0.
+    /// If the underlying filesystem does not support the last write time,
+    /// the returned value is 0.
     ///
     /// # Examples
     ///
diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs
index 10e3d45f9d5..f66b0a3bdc3 100644
--- a/src/libstd/sys/windows/rand.rs
+++ b/src/libstd/sys/windows/rand.rs
@@ -14,25 +14,12 @@ use mem;
 use rand::Rng;
 use sys::c;
 
-pub struct OsRng {
-    hcryptprov: c::HCRYPTPROV
-}
+pub struct OsRng;
 
 impl OsRng {
     /// Create a new `OsRng`.
     pub fn new() -> io::Result<OsRng> {
-        let mut hcp = 0;
-        let ret = unsafe {
-            c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
-                                    c::PROV_RSA_FULL,
-                                    c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
-        };
-
-        if ret == 0 {
-            Err(io::Error::last_os_error())
-        } else {
-            Ok(OsRng { hcryptprov: hcp })
-        }
+        Ok(OsRng)
     }
 }
 
@@ -42,18 +29,19 @@ impl Rng for OsRng {
         self.fill_bytes(&mut v);
         unsafe { mem::transmute(v) }
     }
+
     fn next_u64(&mut self) -> u64 {
         let mut v = [0; 8];
         self.fill_bytes(&mut v);
         unsafe { mem::transmute(v) }
     }
+
     fn fill_bytes(&mut self, v: &mut [u8]) {
-        // CryptGenRandom takes a DWORD (u32) for the length so we need to
+        // RtlGenRandom takes an ULONG (u32) for the length so we need to
         // split up the buffer.
-        for slice in v.chunks_mut(<c::DWORD>::max_value() as usize) {
+        for slice in v.chunks_mut(<c::ULONG>::max_value() as usize) {
             let ret = unsafe {
-                c::CryptGenRandom(self.hcryptprov, slice.len() as c::DWORD,
-                                  slice.as_mut_ptr())
+                c::RtlGenRandom(slice.as_mut_ptr(), slice.len() as c::ULONG)
             };
             if ret == 0 {
                 panic!("couldn't generate random bytes: {}",
@@ -62,15 +50,3 @@ impl Rng for OsRng {
         }
     }
 }
-
-impl Drop for OsRng {
-    fn drop(&mut self) {
-        let ret = unsafe {
-            c::CryptReleaseContext(self.hcryptprov, 0)
-        };
-        if ret == 0 {
-            panic!("couldn't release context: {}",
-                   io::Error::last_os_error());
-        }
-    }
-}
diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index 617218fe7a5..8f78c2e6f59 100644
--- a/src/libstd/sys_common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![cfg_attr(target_os = "nacl", allow(dead_code))]
-
 /// Common code for printing the backtrace in the same way across the different
 /// supported platforms.
 
diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs
index 4d0407ccf6c..ce43ec6d9ab 100644
--- a/src/libstd/sys_common/remutex.rs
+++ b/src/libstd/sys_common/remutex.rs
@@ -116,11 +116,18 @@ impl<T> Drop for ReentrantMutex<T> {
 impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.try_lock() {
-            Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
+            Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
             Err(TryLockError::Poisoned(err)) => {
-                write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
+                f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish()
             },
-            Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}")
+            Err(TryLockError::WouldBlock) => {
+                struct LockedPlaceholder;
+                impl fmt::Debug for LockedPlaceholder {
+                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+                }
+
+                f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
+            }
         }
     }
 }
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index a53c76a333a..cb18eed8ee5 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -325,7 +325,10 @@ impl<T: 'static> LocalKey<T> {
     ///
     /// Once the initialization expression succeeds, the key transitions to the
     /// `Valid` state which will guarantee that future calls to [`with`] will
-    /// succeed within the thread.
+    /// succeed within the thread. Some keys might skip the `Uninitialized`
+    /// state altogether and start in the `Valid` state as an optimization
+    /// (e.g. keys initialized with a constant expression), but no guarantees
+    /// are made.
     ///
     /// When a thread exits, each key will be destroyed in turn, and as keys are
     /// destroyed they will enter the `Destroyed` state just before the
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 30887b16c60..07bbddc62b9 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -485,15 +485,17 @@ impl Builder {
 /// let (tx, rx) = channel();
 ///
 /// let sender = thread::spawn(move || {
-///     let _ = tx.send("Hello, thread".to_owned());
+///     tx.send("Hello, thread".to_owned())
+///         .expect("Unable to send on channel");
 /// });
 ///
 /// let receiver = thread::spawn(move || {
-///     println!("{}", rx.recv().unwrap());
+///     let value = rx.recv().expect("Unable to receive from channel");
+///     println!("{}", value);
 /// });
 ///
-/// let _ = sender.join();
-/// let _ = receiver.join();
+/// sender.join().expect("The sender thread has panicked");
+/// receiver.join().expect("The receiver thread has panicked");
 /// ```
 ///
 /// A thread can also return a value through its [`JoinHandle`], you can use
@@ -1192,7 +1194,7 @@ impl<T> JoinInner<T> {
 ///     });
 /// });
 ///
-/// let _ = original_thread.join();
+/// original_thread.join().expect("The thread being joined has panicked");
 /// println!("Original thread is joined.");
 ///
 /// // We make sure that the new thread has time to run, before the main
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 021f96aff8c..090fc193b38 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1178,7 +1178,6 @@ pub struct MethodSig {
     pub constness: Spanned<Constness>,
     pub abi: Abi,
     pub decl: P<FnDecl>,
-    pub generics: Generics,
 }
 
 /// Represents an item declaration within a trait declaration,
@@ -1190,6 +1189,7 @@ pub struct TraitItem {
     pub id: NodeId,
     pub ident: Ident,
     pub attrs: Vec<Attribute>,
+    pub generics: Generics,
     pub node: TraitItemKind,
     pub span: Span,
     /// See `Item::tokens` for what this is
@@ -1211,6 +1211,7 @@ pub struct ImplItem {
     pub vis: Visibility,
     pub defaultness: Defaultness,
     pub attrs: Vec<Attribute>,
+    pub generics: Generics,
     pub node: ImplItemKind,
     pub span: Span,
     /// See `Item::tokens` for what this is
@@ -1419,7 +1420,7 @@ pub enum TyKind {
     Path(Option<QSelf>, Path),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TraitObject(TyParamBounds),
+    TraitObject(TyParamBounds, TraitObjectSyntax),
     /// An `impl Bound1 + Bound2 + Bound3` type
     /// where `Bound` is a trait or a lifetime.
     ImplTrait(TyParamBounds),
@@ -1438,6 +1439,13 @@ pub enum TyKind {
     Err,
 }
 
+/// Syntax used to declare a trait object.
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitObjectSyntax {
+    Dyn,
+    None,
+}
+
 /// Inline assembly dialect.
 ///
 /// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")``
@@ -1780,10 +1788,19 @@ impl PolyTraitRef {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum CrateSugar {
+    /// Source is `pub(crate)`
+    PubCrate,
+
+    /// Source is (just) `crate`
+    JustCrate,
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Visibility {
     Public,
-    Crate(Span),
+    Crate(Span, CrateSugar),
     Restricted { path: P<Path>, id: NodeId },
     Inherited,
 }
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index efaa5e5e3da..dd46903bb88 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -471,6 +471,17 @@ impl CodeMap {
         }
     }
 
+    /// Given a `Span`, try to get a shorter span ending just after the first
+    /// occurrence of `char` `c`.
+    pub fn span_through_char(&self, sp: Span, c: char) -> Span {
+        if let Ok(snippet) = self.span_to_snippet(sp) {
+            if let Some(offset) = snippet.find(c) {
+                return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
+            }
+        }
+        sp
+    }
+
     pub fn def_span(&self, sp: Span) -> Span {
         self.span_until_char(sp, '{')
     }
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 4fc2b92d3cd..2f5b386346b 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -32,6 +32,7 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
 
     let ident = keywords::Invalid.ident();
     let attrs = Vec::new();
+    let generics = ast::Generics::default();
     let vis = ast::Visibility::Inherited;
     let span = DUMMY_SP;
     let expr_placeholder = || P(ast::Expr {
@@ -49,12 +50,12 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
             tokens: None,
         }))),
         ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem {
-            id, span, ident, attrs,
+            id, span, ident, attrs, generics,
             node: ast::TraitItemKind::Macro(mac_placeholder()),
             tokens: None,
         })),
         ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem {
-            id, span, ident, vis, attrs,
+            id, span, ident, vis, attrs, generics,
             node: ast::ImplItemKind::Macro(mac_placeholder()),
             defaultness: ast::Defaultness::Final,
             tokens: None,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index a2f29181a20..02aba8a3612 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -398,6 +398,12 @@ declare_features! (
 
     // Default match binding modes (RFC 2005)
     (active, match_default_bindings, "1.22.0", Some(42640)),
+
+    // Trait object syntax with `dyn` prefix
+    (active, dyn_trait, "1.22.0", Some(44662)),
+
+    // `crate` as visibility modifier, synonymous to `pub(crate)`
+    (active, crate_visibility_modifier, "1.23.0", Some(45388)),
 );
 
 declare_features! (
@@ -1417,6 +1423,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 gate_feature_post!(&self, never_type, ty.span,
                                    "The `!` type is experimental");
             },
+            ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
+                gate_feature_post!(&self, dyn_trait, ty.span,
+                                   "`dyn Trait` syntax is unstable");
+            }
             _ => {}
         }
         visit::walk_ty(self, ty)
@@ -1519,7 +1529,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 span: Span,
                 _node_id: NodeId) {
         // check for const fn declarations
-        if let FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
+        if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
             fn_kind {
             gate_feature_post!(&self, const_fn, span, "const fn is unstable");
         }
@@ -1529,7 +1539,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         // point.
 
         match fn_kind {
-            FnKind::ItemFn(_, _, _, _, abi, _, _) |
+            FnKind::ItemFn(_, _, _, abi, _, _) |
             FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
                 self.check_abi(abi, span);
             }
@@ -1575,6 +1585,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_impl_item(self, ii);
     }
 
+    fn visit_vis(&mut self, vis: &'a ast::Visibility) {
+        if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
+            gate_feature_post!(&self, crate_visibility_modifier, span,
+                               "`crate` visibility modifier is experimental");
+        }
+        visit::walk_vis(self, vis);
+    }
+
     fn visit_generics(&mut self, g: &'a ast::Generics) {
         for t in &g.ty_params {
             if !t.attrs.is_empty() {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 03c47b71d02..518386a2ad2 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -400,8 +400,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
             TyKind::Typeof(expr) => {
                 TyKind::Typeof(fld.fold_expr(expr))
             }
-            TyKind::TraitObject(bounds) => {
-                TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+            TyKind::TraitObject(bounds, syntax) => {
+                TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax)
             }
             TyKind::ImplTrait(bounds) => {
                 TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
@@ -943,6 +943,7 @@ pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T)
         id: folder.new_id(i.id),
         ident: folder.fold_ident(i.ident),
         attrs: fold_attrs(i.attrs, folder),
+        generics: folder.fold_generics(i.generics),
         node: match i.node {
             TraitItemKind::Const(ty, default) => {
                 TraitItemKind::Const(folder.fold_ty(ty),
@@ -972,6 +973,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
         vis: folder.fold_vis(i.vis),
         ident: folder.fold_ident(i.ident),
         attrs: fold_attrs(i.attrs, folder),
+        generics: folder.fold_generics(i.generics),
         defaultness: i.defaultness,
         node: match i.node  {
             ast::ImplItemKind::Const(ty, expr) => {
@@ -1074,7 +1076,6 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
 
 pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
     MethodSig {
-        generics: folder.fold_generics(sig.generics),
         abi: sig.abi,
         unsafety: sig.unsafety,
         constness: sig.constness,
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index 39b5482a066..35afe8dd56d 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -144,7 +144,7 @@ const UNICODE_ARRAY: &'static [(char, &'static str, char)] = &[
     ('‵', "Reversed Prime", '\''),
     ('՚', "Armenian Apostrophe", '\''),
     ('׳', "Hebrew Punctuation Geresh", '\''),
-    ('`', "Greek Accent", '\''),
+    ('`', "Grave Accent", '\''),
     ('`', "Greek Varia", '\''),
     ('`', "Fullwidth Grave Accent", '\''),
     ('´', "Acute Accent", '\''),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 65dabe98a06..a2c431dc8b1 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -33,10 +33,10 @@ use ast::{Stmt, StmtKind};
 use ast::{VariantData, StructField};
 use ast::StrStyle;
 use ast::SelfKind;
-use ast::{TraitItem, TraitRef};
+use ast::{TraitItem, TraitRef, TraitObjectSyntax};
 use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
-use ast::{Visibility, WhereClause};
+use ast::{Visibility, WhereClause, CrateSugar};
 use ast::{BinOpKind, UnOp};
 use ast::{RangeEnd, RangeSyntax};
 use {ast, attr};
@@ -364,6 +364,13 @@ fn is_ident_or_underscore(t: &token::Token) -> bool {
     t.is_ident() || *t == token::Underscore
 }
 
+// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
+// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
+fn can_continue_type_after_ident(t: &token::Token) -> bool {
+    t == &token::ModSep || t == &token::Lt ||
+    t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
+}
+
 /// Information about the path to a module.
 pub struct ModulePath {
     pub name: String,
@@ -1280,10 +1287,10 @@ impl<'a> Parser<'a> {
                          mut attrs: Vec<Attribute>) -> PResult<'a, TraitItem> {
         let lo = self.span;
 
-        let (name, node) = if self.eat_keyword(keywords::Type) {
+        let (name, node, generics) = if self.eat_keyword(keywords::Type) {
             let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?;
             self.expect(&token::Semi)?;
-            (ident, TraitItemKind::Type(bounds, default))
+            (ident, TraitItemKind::Type(bounds, default), ast::Generics::default())
         } else if self.is_const_item() {
             self.expect_keyword(keywords::Const)?;
             let ident = self.parse_ident()?;
@@ -1298,7 +1305,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?;
                 None
             };
-            (ident, TraitItemKind::Const(ty, default))
+            (ident, TraitItemKind::Const(ty, default), ast::Generics::default())
         } else if self.token.is_path_start() {
             // trait item macro.
             // code copied from parse_macro_use_or_failure... abstraction!
@@ -1321,7 +1328,7 @@ impl<'a> Parser<'a> {
             }
 
             let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
-            (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
+            (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
 
@@ -1334,13 +1341,12 @@ impl<'a> Parser<'a> {
                 // definition...
                 p.parse_arg_general(false)
             })?;
-
             generics.where_clause = self.parse_where_clause()?;
+
             let sig = ast::MethodSig {
                 unsafety,
                 constness,
                 decl: d,
-                generics,
                 abi,
             };
 
@@ -1363,13 +1369,14 @@ impl<'a> Parser<'a> {
                     return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`", token_str)));
                 }
             };
-            (ident, ast::TraitItemKind::Method(sig, body))
+            (ident, ast::TraitItemKind::Method(sig, body), generics)
         };
 
         Ok(TraitItem {
             id: ast::DUMMY_NODE_ID,
             ident: name,
             attrs,
+            generics,
             node,
             span: lo.to(self.prev_span),
             tokens: None,
@@ -1428,7 +1435,7 @@ impl<'a> Parser<'a> {
                     TyKind::Path(None, ref path) if maybe_bounds => {
                         self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
                     }
-                    TyKind::TraitObject(ref bounds)
+                    TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
                             if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
                         let path = match bounds[0] {
                             TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
@@ -1472,27 +1479,6 @@ impl<'a> Parser<'a> {
         } else if self.eat(&token::Underscore) {
             // A type to be inferred `_`
             TyKind::Infer
-        } else if self.eat_lt() {
-            // Qualified path
-            let (qself, path) = self.parse_qpath(PathStyle::Type)?;
-            TyKind::Path(Some(qself), path)
-        } else if self.token.is_path_start() {
-            // Simple path
-            let path = self.parse_path(PathStyle::Type)?;
-            if self.eat(&token::Not) {
-                // Macro invocation in type position
-                let (_, tts) = self.expect_delimited_token_tree()?;
-                TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
-            } else {
-                // Just a type path or bound list (trait object type) starting with a trait.
-                //   `Type`
-                //   `Trait1 + Trait2 + 'a`
-                if allow_plus && self.check(&token::BinOp(token::Plus)) {
-                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
-                } else {
-                    TyKind::Path(None, path)
-                }
-            }
         } else if self.token_is_bare_fn_keyword() {
             // Function pointer type
             self.parse_ty_bare_fn(Vec::new())?
@@ -1512,10 +1498,37 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(keywords::Impl) {
             // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
             TyKind::ImplTrait(self.parse_ty_param_bounds()?)
+        } else if self.check_keyword(keywords::Dyn) &&
+                  self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
+            // FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511).
+            self.bump(); // `dyn`
+            TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn)
         } else if self.check(&token::Question) ||
-                  self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){
+                  self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
             // Bound list (trait object type)
-            TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?)
+            TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
+                                TraitObjectSyntax::None)
+        } else if self.eat_lt() {
+            // Qualified path
+            let (qself, path) = self.parse_qpath(PathStyle::Type)?;
+            TyKind::Path(Some(qself), path)
+        } else if self.token.is_path_start() {
+            // Simple path
+            let path = self.parse_path(PathStyle::Type)?;
+            if self.eat(&token::Not) {
+                // Macro invocation in type position
+                let (_, tts) = self.expect_delimited_token_tree()?;
+                TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
+            } else {
+                // Just a type path or bound list (trait object type) starting with a trait.
+                //   `Type`
+                //   `Trait1 + Trait2 + 'a`
+                if allow_plus && self.check(&token::BinOp(token::Plus)) {
+                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+                } else {
+                    TyKind::Path(None, path)
+                }
+            }
         } else {
             let msg = format!("expected type, found {}", self.this_token_descr());
             return Err(self.fatal(&msg));
@@ -1538,7 +1551,7 @@ impl<'a> Parser<'a> {
             self.bump(); // `+`
             bounds.append(&mut self.parse_ty_param_bounds()?);
         }
-        Ok(TyKind::TraitObject(bounds))
+        Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
 
     fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
@@ -2314,6 +2327,7 @@ impl<'a> Parser<'a> {
 
         while self.token != token::CloseDelim(token::Brace) {
             if self.eat(&token::DotDot) {
+                let exp_span = self.prev_span;
                 match self.parse_expr() {
                     Ok(e) => {
                         base = Some(e);
@@ -2323,6 +2337,16 @@ impl<'a> Parser<'a> {
                         self.recover_stmt();
                     }
                 }
+                if self.token == token::Comma {
+                    let mut err = self.sess.span_diagnostic.mut_span_err(
+                        exp_span.to(self.prev_span),
+                        "cannot use a comma after the base struct",
+                    );
+                    err.span_suggestion_short(self.span, "remove this comma", "".to_owned());
+                    err.note("the base struct must always be the last field");
+                    err.emit();
+                    self.recover_stmt();
+                }
                 break;
             }
 
@@ -2890,17 +2914,30 @@ impl<'a> Parser<'a> {
 
                 match self.parse_path(PathStyle::Expr) {
                     Ok(path) => {
+                        let (op_noun, op_verb) = match self.token {
+                            token::Lt => ("comparison", "comparing"),
+                            token::BinOp(token::Shl) => ("shift", "shifting"),
+                            _ => {
+                                // We can end up here even without `<` being the next token, for
+                                // example because `parse_ty_no_plus` returns `Err` on keywords,
+                                // but `parse_path` returns `Ok` on them due to error recovery.
+                                // Return original error and parser state.
+                                mem::replace(self, parser_snapshot_after_type);
+                                return Err(type_err);
+                            }
+                        };
+
                         // Successfully parsed the type path leaving a `<` yet to parse.
                         type_err.cancel();
 
                         // Report non-fatal diagnostics, keep `x as usize` as an expression
                         // in AST and continue parsing.
                         let msg = format!("`<` is interpreted as a start of generic \
-                                           arguments for `{}`, not a comparison", path);
+                                           arguments for `{}`, not a {}", path, op_noun);
                         let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
                         err.span_label(self.look_ahead_span(1).to(parser_snapshot_after_type.span),
                                        "interpreted as generic arguments");
-                        err.span_label(self.span, "not interpreted as comparison");
+                        err.span_label(self.span, format!("not interpreted as {}", op_noun));
 
                         let expr = mk_expr(self, P(Ty {
                             span: path.span,
@@ -2911,7 +2948,7 @@ impl<'a> Parser<'a> {
                         let expr_str = self.sess.codemap().span_to_snippet(expr.span)
                                                 .unwrap_or(pprust::expr_to_string(&expr));
                         err.span_suggestion(expr.span,
-                                            "try comparing the casted value",
+                                            &format!("try {} the casted value", op_verb),
                                             format!("({})", expr_str));
                         err.emit();
 
@@ -2947,6 +2984,7 @@ impl<'a> Parser<'a> {
                 {                                  //     Foo<Bar<Baz<Qux, ()>>>
                     err.help(
                         "use `::<...>` instead of `<...>` if you meant to specify type arguments");
+                    err.help("or use `(...)` if you meant to specify fn arguments");
                 }
                 err.emit();
             }
@@ -3671,12 +3709,17 @@ impl<'a> Parser<'a> {
             None
         };
         let init = self.parse_initializer()?;
+        let hi = if self.token == token::Semi {
+            self.span
+        } else {
+            self.prev_span
+        };
         Ok(P(ast::Local {
             ty,
             pat,
             init,
             id: ast::DUMMY_NODE_ID,
-            span: lo.to(self.prev_span),
+            span: lo.to(hi),
             attrs,
         }))
     }
@@ -4045,11 +4088,11 @@ impl<'a> Parser<'a> {
                     node: StmtKind::Item(i),
                 },
                 None => {
-                    let unused_attrs = |attrs: &[_], s: &mut Self| {
+                    let unused_attrs = |attrs: &[Attribute], s: &mut Self| {
                         if !attrs.is_empty() {
                             if s.prev_token_kind == PrevTokenKind::DocComment {
                                 s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit();
-                            } else {
+                            } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
                                 s.span_err(s.span, "expected statement after outer attribute");
                             }
                         }
@@ -4226,6 +4269,7 @@ impl<'a> Parser<'a> {
     fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
         let mut bounds = Vec::new();
         loop {
+            // This needs to be syncronized with `Token::can_begin_bound`.
             let is_bound_start = self.check_path() || self.check_lifetime() ||
                                  self.check(&token::Question) ||
                                  self.check_keyword(keywords::For) ||
@@ -4857,12 +4901,12 @@ impl<'a> Parser<'a> {
         let lo = self.span;
         let vis = self.parse_visibility(false)?;
         let defaultness = self.parse_defaultness()?;
-        let (name, node) = if self.eat_keyword(keywords::Type) {
+        let (name, node, generics) = if self.eat_keyword(keywords::Type) {
             let name = self.parse_ident()?;
             self.expect(&token::Eq)?;
             let typ = self.parse_ty()?;
             self.expect(&token::Semi)?;
-            (name, ast::ImplItemKind::Type(typ))
+            (name, ast::ImplItemKind::Type(typ), ast::Generics::default())
         } else if self.is_const_item() {
             self.expect_keyword(keywords::Const)?;
             let name = self.parse_ident()?;
@@ -4871,11 +4915,11 @@ impl<'a> Parser<'a> {
             self.expect(&token::Eq)?;
             let expr = self.parse_expr()?;
             self.expect(&token::Semi)?;
-            (name, ast::ImplItemKind::Const(typ, expr))
+            (name, ast::ImplItemKind::Const(typ, expr), ast::Generics::default())
         } else {
-            let (name, inner_attrs, node) = self.parse_impl_method(&vis, at_end)?;
+            let (name, inner_attrs, generics, node) = self.parse_impl_method(&vis, at_end)?;
             attrs.extend(inner_attrs);
-            (name, node)
+            (name, node, generics)
         };
 
         Ok(ImplItem {
@@ -4885,6 +4929,7 @@ impl<'a> Parser<'a> {
             vis,
             defaultness,
             attrs,
+            generics,
             node,
             tokens: None,
         })
@@ -4942,7 +4987,8 @@ impl<'a> Parser<'a> {
 
     /// Parse a method or a macro invocation in a trait impl.
     fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool)
-                         -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
+                         -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::Generics,
+                             ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
         if self.token.is_path_start() {
             // Method macro.
@@ -4969,7 +5015,8 @@ impl<'a> Parser<'a> {
             }
 
             let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts });
-            Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
+            Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
+                ast::ImplItemKind::Macro(mac)))
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
@@ -4978,8 +5025,7 @@ impl<'a> Parser<'a> {
             generics.where_clause = self.parse_where_clause()?;
             *at_end = true;
             let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-            Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig {
-                generics,
+            Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig {
                 abi,
                 unsafety,
                 constness,
@@ -5281,6 +5327,10 @@ impl<'a> Parser<'a> {
     pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
         maybe_whole!(self, NtVis, |x| x);
 
+        if self.eat_keyword(keywords::Crate) {
+            return Ok(Visibility::Crate(self.prev_span, CrateSugar::JustCrate));
+        }
+
         if !self.eat_keyword(keywords::Pub) {
             return Ok(Visibility::Inherited)
         }
@@ -5294,7 +5344,7 @@ impl<'a> Parser<'a> {
                 // `pub(crate)`
                 self.bump(); // `(`
                 self.bump(); // `crate`
-                let vis = Visibility::Crate(self.prev_span);
+                let vis = Visibility::Crate(self.prev_span, CrateSugar::PubCrate);
                 self.expect(&token::CloseDelim(token::Paren))?; // `)`
                 return Ok(vis)
             } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) {
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 4888654fac9..20db87cfc82 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -258,6 +258,12 @@ impl Token {
         }
     }
 
+    /// Returns `true` if the token can appear at the start of a generic bound.
+    pub fn can_begin_bound(&self) -> bool {
+        self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
+        self == &Question || self == &OpenDelim(Paren)
+    }
+
     /// Returns `true` if the token is any literal
     pub fn is_lit(&self) -> bool {
         match *self {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 959dd4ef30f..656a51c6637 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1049,8 +1049,9 @@ impl<'a> State<'a> {
             ast::TyKind::Path(Some(ref qself), ref path) => {
                 self.print_qpath(path, qself, false)?
             }
-            ast::TyKind::TraitObject(ref bounds) => {
-                self.print_bounds("", &bounds[..])?;
+            ast::TyKind::TraitObject(ref bounds, syntax) => {
+                let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn " } else { "" };
+                self.print_bounds(prefix, &bounds[..])?;
             }
             ast::TyKind::ImplTrait(ref bounds) => {
                 self.print_bounds("impl ", &bounds[..])?;
@@ -1439,7 +1440,10 @@ impl<'a> State<'a> {
     pub fn print_visibility(&mut self, vis: &ast::Visibility) -> io::Result<()> {
         match *vis {
             ast::Visibility::Public => self.word_nbsp("pub"),
-            ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"),
+            ast::Visibility::Crate(_, sugar) => match sugar {
+                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
+                ast::CrateSugar::JustCrate => self.word_nbsp("crate")
+            }
             ast::Visibility::Restricted { ref path, .. } => {
                 let path = to_string(|s| s.print_path(path, false, 0, true));
                 if path == "self" || path == "super" {
@@ -1524,6 +1528,7 @@ impl<'a> State<'a> {
 
     pub fn print_method_sig(&mut self,
                             ident: ast::Ident,
+                            generics: &ast::Generics,
                             m: &ast::MethodSig,
                             vis: &ast::Visibility)
                             -> io::Result<()> {
@@ -1532,7 +1537,7 @@ impl<'a> State<'a> {
                       m.constness.node,
                       m.abi,
                       Some(ident),
-                      &m.generics,
+                      &generics,
                       vis)
     }
 
@@ -1552,7 +1557,7 @@ impl<'a> State<'a> {
                 if body.is_some() {
                     self.head("")?;
                 }
-                self.print_method_sig(ti.ident, sig, &ast::Visibility::Inherited)?;
+                self.print_method_sig(ti.ident, &ti.generics, sig, &ast::Visibility::Inherited)?;
                 if let Some(ref body) = *body {
                     self.nbsp()?;
                     self.print_block_with_attrs(body, &ti.attrs)?;
@@ -1591,7 +1596,7 @@ impl<'a> State<'a> {
             }
             ast::ImplItemKind::Method(ref sig, ref body) => {
                 self.head("")?;
-                self.print_method_sig(ii.ident, sig, &ii.vis)?;
+                self.print_method_sig(ii.ident, &ii.generics, sig, &ii.vis)?;
                 self.nbsp()?;
                 self.print_block_with_attrs(body, &ii.attrs)?;
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 05077d42a0b..078a63cba20 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -31,7 +31,7 @@ use codemap::Spanned;
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
     /// fn foo() or extern "Abi" fn foo()
-    ItemFn(Ident, &'a Generics, Unsafety, Spanned<Constness>, Abi, &'a Visibility, &'a Block),
+    ItemFn(Ident, Unsafety, Spanned<Constness>, Abi, &'a Visibility, &'a Block),
 
     /// fn foo(&self)
     Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block),
@@ -247,7 +247,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             visitor.visit_expr(expr);
         }
         ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
-            visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety,
+            visitor.visit_generics(generics);
+            visitor.visit_fn(FnKind::ItemFn(item.ident, unsafety,
                                             constness, abi, &item.vis, body),
                              declaration,
                              item.span,
@@ -348,7 +349,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             visitor.visit_ty(ty);
             visitor.visit_expr(expression)
         }
-        TyKind::TraitObject(ref bounds) |
+        TyKind::TraitObject(ref bounds, ..) |
         TyKind::ImplTrait(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
@@ -538,13 +539,11 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
     where V: Visitor<'a>,
 {
     match kind {
-        FnKind::ItemFn(_, generics, _, _, _, _, body) => {
-            visitor.visit_generics(generics);
+        FnKind::ItemFn(_, _, _, _, _, body) => {
             walk_fn_decl(visitor, declaration);
             visitor.visit_block(body);
         }
-        FnKind::Method(_, sig, _, body) => {
-            visitor.visit_generics(&sig.generics);
+        FnKind::Method(_, _, _, body) => {
             walk_fn_decl(visitor, declaration);
             visitor.visit_block(body);
         }
@@ -558,13 +557,13 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
 pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) {
     visitor.visit_ident(trait_item.span, trait_item.ident);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
+    visitor.visit_generics(&trait_item.generics);
     match trait_item.node {
         TraitItemKind::Const(ref ty, ref default) => {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_expr, default);
         }
         TraitItemKind::Method(ref sig, None) => {
-            visitor.visit_generics(&sig.generics);
             walk_fn_decl(visitor, &sig.decl);
         }
         TraitItemKind::Method(ref sig, Some(ref body)) => {
@@ -585,6 +584,7 @@ pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplIt
     visitor.visit_vis(&impl_item.vis);
     visitor.visit_ident(impl_item.span, impl_item.ident);
     walk_list!(visitor, visit_attribute, &impl_item.attrs);
+    visitor.visit_generics(&impl_item.generics);
     match impl_item.node {
         ImplItemKind::Const(ref ty, ref expr) => {
             visitor.visit_ty(ty);
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 5c1ca19d635..18897047538 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -506,6 +506,7 @@ impl<'a> TraitDef<'a> {
                 vis: ast::Visibility::Inherited,
                 defaultness: ast::Defaultness::Final,
                 attrs: Vec::new(),
+                generics: Generics::default(),
                 node: ast::ImplItemKind::Type(type_def.to_ty(cx, self.span, type_ident, generics)),
                 tokens: None,
             }
@@ -921,12 +922,12 @@ impl<'a> MethodDef<'a> {
         ast::ImplItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
+            generics: fn_generics,
             span: trait_.span,
             vis: ast::Visibility::Inherited,
             defaultness: ast::Defaultness::Final,
             ident: method_ident,
             node: ast::ImplItemKind::Method(ast::MethodSig {
-                                                generics: fn_generics,
                                                 abi,
                                                 unsafety,
                                                 constness:
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 2000db9703c..d30d79ece15 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -339,8 +339,11 @@ impl serialize::UseSpecializedDecodable for Span {
 }
 
 fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
-    write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}",
-           span.lo(), span.hi(), span.ctxt())
+    f.debug_struct("Span")
+        .field("lo", &span.lo())
+        .field("hi", &span.hi())
+        .field("ctxt", &span.ctxt())
+        .finish()
 }
 
 impl fmt::Debug for Span {
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 4d3db15ef29..872fc031cfb 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -309,10 +309,11 @@ declare_keywords! {
     (54, Yield,          "yield")
 
     // Weak keywords, have special meaning only in specific contexts.
-    (55, Default,        "default")
-    (56, StaticLifetime, "'static")
-    (57, Union,          "union")
-    (58, Catch,          "catch")
+    (55, Catch,          "catch")
+    (56, Default,        "default")
+    (57, Dyn,            "dyn")
+    (58, StaticLifetime, "'static")
+    (59, Union,          "union")
 }
 
 // If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 642eb285564..e8a1242c814 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -1554,16 +1554,14 @@ impl MetricMap {
 /// elimination.
 ///
 /// This function is a no-op, and does not even read from `dummy`.
-#[cfg(not(any(all(target_os = "nacl", target_arch = "le32"),
-              target_arch = "asmjs", target_arch = "wasm32")))]
+#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
 pub fn black_box<T>(dummy: T) -> T {
     // we need to "use" the argument in some way LLVM can't
     // introspect.
     unsafe { asm!("" : : "r"(&dummy)) }
     dummy
 }
-#[cfg(any(all(target_os = "nacl", target_arch = "le32"),
-          target_arch = "asmjs", target_arch = "wasm32"))]
+#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
 #[inline(never)]
 pub fn black_box<T>(dummy: T) -> T {
     dummy
diff --git a/src/llvm b/src/llvm
-Subproject c7a16bd57c2a9c643a52f0cebecdaf0b6a996da
+Subproject 83b72cedfd7800ffc983d2855a85c5d06a545aa
diff --git a/src/rustc/compiler_builtins_shim/Cargo.toml b/src/rustc/compiler_builtins_shim/Cargo.toml
index 886e239246d..608e5f5f36d 100644
--- a/src/rustc/compiler_builtins_shim/Cargo.toml
+++ b/src/rustc/compiler_builtins_shim/Cargo.toml
@@ -30,7 +30,7 @@ doctest = false
 core = { path = "../../libcore" }
 
 [build-dependencies]
-cc = "1.0"
+cc = "1.0.1"
 
 [features]
 c = []
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 2f966e5a1c5..b397ad1e98f 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -27,6 +27,12 @@
 
 #if LLVM_VERSION_GE(4, 0)
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
+#include "llvm/Transforms/IPO/FunctionImport.h"
+#include "llvm/Transforms/Utils/FunctionImportUtils.h"
+#include "llvm/LTO/LTO.h"
+#if LLVM_VERSION_LE(4, 0)
+#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#endif
 #endif
 
 #include "llvm-c/Transforms/PassManagerBuilder.h"
@@ -102,6 +108,19 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
   PMB->add(Pass);
 }
 
+extern "C"
+bool LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
+  LLVMPassManagerBuilderRef PMBR,
+  LLVMPassManagerRef PMR
+) {
+#if LLVM_VERSION_GE(4, 0)
+  unwrap(PMBR)->populateThinLTOPassManager(*unwrap(PMR));
+  return true;
+#else
+  return false;
+#endif
+}
+
 #ifdef LLVM_COMPONENT_X86
 #define SUBTARGET_X86 SUBTARGET(X86)
 #else
@@ -740,3 +759,500 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
   unwrap(M)->setPIELevel(PIELevel::Level::Large);
 #endif
 }
+
+extern "C" bool
+LLVMRustThinLTOAvailable() {
+#if LLVM_VERSION_GE(4, 0)
+  return true;
+#else
+  return false;
+#endif
+}
+
+#if LLVM_VERSION_GE(4, 0)
+
+// Here you'll find an implementation of ThinLTO as used by the Rust compiler
+// right now. This ThinLTO support is only enabled on "recent ish" versions of
+// LLVM, and otherwise it's just blanket rejected from other compilers.
+//
+// Most of this implementation is straight copied from LLVM. At the time of
+// this writing it wasn't *quite* suitable to reuse more code from upstream
+// for our purposes, but we should strive to upstream this support once it's
+// ready to go! I figure we may want a bit of testing locally first before
+// sending this upstream to LLVM. I hear though they're quite eager to receive
+// feedback like this!
+//
+// If you're reading this code and wondering "what in the world" or you're
+// working "good lord by LLVM upgrade is *still* failing due to these bindings"
+// then fear not! (ok maybe fear a little). All code here is mostly based
+// on `lib/LTO/ThinLTOCodeGenerator.cpp` in LLVM.
+//
+// You'll find that the general layout here roughly corresponds to the `run`
+// method in that file as well as `ProcessThinLTOModule`. Functions are
+// specifically commented below as well, but if you're updating this code
+// or otherwise trying to understand it, the LLVM source will be useful in
+// interpreting the mysteries within.
+//
+// Otherwise I'll apologize in advance, it probably requires a relatively
+// significant investment on your part to "truly understand" what's going on
+// here. Not saying I do myself, but it took me awhile staring at LLVM's source
+// and various online resources about ThinLTO to make heads or tails of all
+// this.
+
+extern "C" bool
+LLVMRustWriteThinBitcodeToFile(LLVMPassManagerRef PMR,
+                               LLVMModuleRef M,
+                               const char *BcFile) {
+  llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
+  std::error_code EC;
+  llvm::raw_fd_ostream bc(BcFile, EC, llvm::sys::fs::F_None);
+  if (EC) {
+    LLVMRustSetLastError(EC.message().c_str());
+    return false;
+  }
+  PM->add(createWriteThinLTOBitcodePass(bc));
+  PM->run(*unwrap(M));
+  delete PM;
+  return true;
+}
+
+// This is a shared data structure which *must* be threadsafe to share
+// read-only amongst threads. This also corresponds basically to the arguments
+// of the `ProcessThinLTOModule` function in the LLVM source.
+struct LLVMRustThinLTOData {
+  // The combined index that is the global analysis over all modules we're
+  // performing ThinLTO for. This is mostly managed by LLVM.
+  ModuleSummaryIndex Index;
+
+  // All modules we may look at, stored as in-memory serialized versions. This
+  // is later used when inlining to ensure we can extract any module to inline
+  // from.
+  StringMap<MemoryBufferRef> ModuleMap;
+
+  // A set that we manage of everything we *don't* want internalized. Note that
+  // this includes all transitive references right now as well, but it may not
+  // always!
+  DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
+
+  // Not 100% sure what these are, but they impact what's internalized and
+  // what's inlined across modules, I believe.
+  StringMap<FunctionImporter::ImportMapTy> ImportLists;
+  StringMap<FunctionImporter::ExportSetTy> ExportLists;
+  StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+};
+
+// Just an argument to the `LLVMRustCreateThinLTOData` function below.
+struct LLVMRustThinLTOModule {
+  const char *identifier;
+  const char *data;
+  size_t len;
+};
+
+// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`, not sure what it
+// does.
+static const GlobalValueSummary *
+getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) {
+  auto StrongDefForLinker = llvm::find_if(
+      GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
+        auto Linkage = Summary->linkage();
+        return !GlobalValue::isAvailableExternallyLinkage(Linkage) &&
+               !GlobalValue::isWeakForLinker(Linkage);
+      });
+  if (StrongDefForLinker != GVSummaryList.end())
+    return StrongDefForLinker->get();
+
+  auto FirstDefForLinker = llvm::find_if(
+      GVSummaryList, [](const std::unique_ptr<GlobalValueSummary> &Summary) {
+        auto Linkage = Summary->linkage();
+        return !GlobalValue::isAvailableExternallyLinkage(Linkage);
+      });
+  if (FirstDefForLinker == GVSummaryList.end())
+    return nullptr;
+  return FirstDefForLinker->get();
+}
+
+// This is a helper function we added that isn't present in LLVM's source.
+//
+// The way LTO works in Rust is that we typically have a number of symbols that
+// we know ahead of time need to be preserved. We want to ensure that ThinLTO
+// doesn't accidentally internalize any of these and otherwise is always
+// ready to keep them linking correctly.
+//
+// This function will recursively walk the `GUID` provided and all of its
+// references, as specified in the `Index`. In other words, we're taking a
+// `GUID` as input, adding it to `Preserved`, and then taking all `GUID`
+// items that the input references and recursing.
+static void
+addPreservedGUID(const ModuleSummaryIndex &Index,
+                 DenseSet<GlobalValue::GUID> &Preserved,
+                 GlobalValue::GUID GUID) {
+  if (Preserved.count(GUID))
+    return;
+  Preserved.insert(GUID);
+
+#if LLVM_VERSION_GE(5, 0)
+  auto Info = Index.getValueInfo(GUID);
+  if (!Info) {
+    return;
+  }
+  for (auto &Summary : Info.getSummaryList()) {
+    for (auto &Ref : Summary->refs()) {
+      addPreservedGUID(Index, Preserved, Ref.getGUID());
+    }
+
+    GlobalValueSummary *GVSummary = Summary.get();
+    if (isa<FunctionSummary>(GVSummary)) {
+      auto *FS = cast<FunctionSummary>(GVSummary);
+      for (auto &Call: FS->calls()) {
+        addPreservedGUID(Index, Preserved, Call.first.getGUID());
+      }
+      for (auto &GUID: FS->type_tests()) {
+        addPreservedGUID(Index, Preserved, GUID);
+      }
+    }
+    if (isa<AliasSummary>(GVSummary)) {
+      auto *AS = cast<AliasSummary>(GVSummary);
+      auto GUID = AS->getAliasee().getOriginalName();
+      addPreservedGUID(Index, Preserved, GUID);
+    }
+  }
+#else
+  auto SummaryList = Index.findGlobalValueSummaryList(GUID);
+  if (SummaryList == Index.end())
+    return;
+  for (auto &Summary : SummaryList->second) {
+    for (auto &Ref : Summary->refs()) {
+      if (Ref.isGUID()) {
+        addPreservedGUID(Index, Preserved, Ref.getGUID());
+      } else {
+        auto Value = Ref.getValue();
+        addPreservedGUID(Index, Preserved, Value->getGUID());
+      }
+    }
+
+    if (auto *FS = dyn_cast<FunctionSummary>(Summary.get())) {
+      for (auto &Call: FS->calls()) {
+        if (Call.first.isGUID()) {
+          addPreservedGUID(Index, Preserved, Call.first.getGUID());
+        } else {
+          auto Value = Call.first.getValue();
+          addPreservedGUID(Index, Preserved, Value->getGUID());
+        }
+      }
+      for (auto &GUID: FS->type_tests()) {
+        addPreservedGUID(Index, Preserved, GUID);
+      }
+    }
+    if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
+      auto GUID = AS->getAliasee().getOriginalName();
+      addPreservedGUID(Index, Preserved, GUID);
+    }
+  }
+#endif
+}
+
+// The main entry point for creating the global ThinLTO analysis. The structure
+// here is basically the same as before threads are spawned in the `run`
+// function of `lib/LTO/ThinLTOCodeGenerator.cpp`.
+extern "C" LLVMRustThinLTOData*
+LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
+                          int num_modules,
+                          const char **preserved_symbols,
+                          int num_symbols) {
+  auto Ret = llvm::make_unique<LLVMRustThinLTOData>();
+
+  // Load each module's summary and merge it into one combined index
+  for (int i = 0; i < num_modules; i++) {
+    auto module = &modules[i];
+    StringRef buffer(module->data, module->len);
+    MemoryBufferRef mem_buffer(buffer, module->identifier);
+
+    Ret->ModuleMap[module->identifier] = mem_buffer;
+
+#if LLVM_VERSION_GE(5, 0)
+    if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) {
+      LLVMRustSetLastError(toString(std::move(Err)).c_str());
+      return nullptr;
+    }
+#else
+    Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr =
+      object::ModuleSummaryIndexObjectFile::create(mem_buffer);
+    if (!ObjOrErr) {
+      LLVMRustSetLastError(toString(ObjOrErr.takeError()).c_str());
+      return nullptr;
+    }
+    auto Index = (*ObjOrErr)->takeIndex();
+    Ret->Index.mergeFrom(std::move(Index), i);
+#endif
+  }
+
+  // Collect for each module the list of function it defines (GUID -> Summary)
+  Ret->Index.collectDefinedGVSummariesPerModule(Ret->ModuleToDefinedGVSummaries);
+
+  // Convert the preserved symbols set from string to GUID, this is then needed
+  // for internalization. We use `addPreservedGUID` to include any transitively
+  // used symbol as well.
+  for (int i = 0; i < num_symbols; i++) {
+    addPreservedGUID(Ret->Index,
+                     Ret->GUIDPreservedSymbols,
+                     GlobalValue::getGUID(preserved_symbols[i]));
+  }
+
+  // Collect the import/export lists for all modules from the call-graph in the
+  // combined index
+  //
+  // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
+#if LLVM_VERSION_GE(5, 0)
+  computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+  ComputeCrossModuleImport(
+    Ret->Index,
+    Ret->ModuleToDefinedGVSummaries,
+    Ret->ImportLists,
+    Ret->ExportLists
+  );
+#else
+  auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+  ComputeCrossModuleImport(
+    Ret->Index,
+    Ret->ModuleToDefinedGVSummaries,
+    Ret->ImportLists,
+    Ret->ExportLists,
+    &DeadSymbols
+  );
+#endif
+
+  // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
+  // impacts the caching.
+  //
+  // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
+  StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
+  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
+  for (auto &I : Ret->Index) {
+#if LLVM_VERSION_GE(5, 0)
+    if (I.second.SummaryList.size() > 1)
+      PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second.SummaryList);
+#else
+    if (I.second.size() > 1)
+      PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second);
+#endif
+  }
+  auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
+    const auto &Prevailing = PrevailingCopy.find(GUID);
+    if (Prevailing == PrevailingCopy.end())
+      return true;
+    return Prevailing->second == S;
+  };
+  auto recordNewLinkage = [&](StringRef ModuleIdentifier,
+                              GlobalValue::GUID GUID,
+                              GlobalValue::LinkageTypes NewLinkage) {
+    ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
+  };
+  thinLTOResolveWeakForLinkerInIndex(Ret->Index, isPrevailing, recordNewLinkage);
+  auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
+    const auto &ExportList = Ret->ExportLists.find(ModuleIdentifier);
+    return (ExportList != Ret->ExportLists.end() &&
+      ExportList->second.count(GUID)) ||
+      Ret->GUIDPreservedSymbols.count(GUID);
+  };
+  thinLTOInternalizeAndPromoteInIndex(Ret->Index, isExported);
+
+  return Ret.release();
+}
+
+extern "C" void
+LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
+  delete Data;
+}
+
+// Below are the various passes that happen *per module* when doing ThinLTO.
+//
+// In other words, these are the functions that are all run concurrently
+// with one another, one per module. The passes here correspond to the analysis
+// passes in `lib/LTO/ThinLTOCodeGenerator.cpp`, currently found in the
+// `ProcessThinLTOModule` function. Here they're split up into separate steps
+// so rustc can save off the intermediate bytecode between each step.
+
+extern "C" bool
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  if (renameModuleForThinLTO(Mod, Data->Index)) {
+    LLVMRustSetLastError("renameModuleForThinLTO failed");
+    return false;
+  }
+  return true;
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
+  thinLTOResolveWeakForLinkerModule(Mod, DefinedGlobals);
+  return true;
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier());
+  thinLTOInternalizeModule(Mod, DefinedGlobals);
+  return true;
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  Module &Mod = *unwrap(M);
+  const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
+  auto Loader = [&](StringRef Identifier) {
+    const auto &Memory = Data->ModuleMap.lookup(Identifier);
+    auto &Context = Mod.getContext();
+    return getLazyBitcodeModule(Memory, Context, true, true);
+  };
+  FunctionImporter Importer(Data->Index, Loader);
+  Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
+  if (!Result) {
+    LLVMRustSetLastError(toString(Result.takeError()).c_str());
+    return false;
+  }
+  return true;
+}
+
+// This struct and various functions are sort of a hack right now, but the
+// problem is that we've got in-memory LLVM modules after we generate and
+// optimize all codegen-units for one compilation in rustc. To be compatible
+// with the LTO support above we need to serialize the modules plus their
+// ThinLTO summary into memory.
+//
+// This structure is basically an owned version of a serialize module, with
+// a ThinLTO summary attached.
+struct LLVMRustThinLTOBuffer {
+  std::string data;
+};
+
+extern "C" LLVMRustThinLTOBuffer*
+LLVMRustThinLTOBufferCreate(LLVMModuleRef M) {
+  auto Ret = llvm::make_unique<LLVMRustThinLTOBuffer>();
+  {
+    raw_string_ostream OS(Ret->data);
+    {
+      legacy::PassManager PM;
+      PM.add(createWriteThinLTOBitcodePass(OS));
+      PM.run(*unwrap(M));
+    }
+  }
+  return Ret.release();
+}
+
+extern "C" void
+LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) {
+  delete Buffer;
+}
+
+extern "C" const void*
+LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) {
+  return Buffer->data.data();
+}
+
+extern "C" size_t
+LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
+  return Buffer->data.length();
+}
+
+// This is what we used to parse upstream bitcode for actual ThinLTO
+// processing.  We'll call this once per module optimized through ThinLTO, and
+// it'll be called concurrently on many threads.
+extern "C" LLVMModuleRef
+LLVMRustParseBitcodeForThinLTO(LLVMContextRef Context,
+                               const char *data,
+                               size_t len,
+                               const char *identifier) {
+  StringRef Data(data, len);
+  MemoryBufferRef Buffer(Data, identifier);
+  unwrap(Context)->enableDebugTypeODRUniquing();
+  Expected<std::unique_ptr<Module>> SrcOrError =
+      parseBitcodeFile(Buffer, *unwrap(Context));
+  if (!SrcOrError) {
+    LLVMRustSetLastError(toString(SrcOrError.takeError()).c_str());
+    return nullptr;
+  }
+  return wrap(std::move(*SrcOrError).release());
+}
+
+#else
+
+extern "C" bool
+LLVMRustWriteThinBitcodeToFile(LLVMPassManagerRef PMR,
+                               LLVMModuleRef M,
+                               const char *BcFile) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+struct LLVMRustThinLTOData {
+};
+
+struct LLVMRustThinLTOModule {
+};
+
+extern "C" LLVMRustThinLTOData*
+LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
+                          int num_modules,
+                          const char **preserved_symbols,
+                          int num_symbols) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" bool
+LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" void
+LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+struct LLVMRustThinLTOBuffer {
+};
+
+extern "C" LLVMRustThinLTOBuffer*
+LLVMRustThinLTOBufferCreate(LLVMModuleRef M) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" void
+LLVMRustThinLTOBufferFree(LLVMRustThinLTOBuffer *Buffer) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" const void*
+LLVMRustThinLTOBufferPtr(const LLVMRustThinLTOBuffer *Buffer) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" size_t
+LLVMRustThinLTOBufferLen(const LLVMRustThinLTOBuffer *Buffer) {
+  llvm_unreachable("ThinLTO not available");
+}
+
+extern "C" LLVMModuleRef
+LLVMRustParseBitcodeForThinLTO(LLVMContextRef Context,
+                               const char *data,
+                               size_t len,
+                               const char *identifier) {
+  llvm_unreachable("ThinLTO not available");
+}
+#endif // LLVM_VERSION_GE(4, 0)
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index bc616f64881..20ea8d70302 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -57,7 +57,7 @@ static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
   llvm_unreachable("Invalid LLVMAtomicOrdering value!");
 }
 
-static char *LastError;
+static LLVM_THREAD_LOCAL char *LastError;
 
 extern "C" LLVMMemoryBufferRef
 LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
index d8e6028b799..b8033b88fb7 100644
--- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
+++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs
@@ -10,8 +10,9 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<drop_in_place_intrinsic::StructWithDtor[0]> @@ drop_in_place_intrinsic0[Internal]
 struct StructWithDtor(u32);
 
 impl Drop for StructWithDtor {
@@ -22,7 +23,7 @@ impl Drop for StructWithDtor {
 //~ TRANS_ITEM fn drop_in_place_intrinsic::main[0]
 fn main() {
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic0[Internal]
     let x = [StructWithDtor(0), StructWithDtor(1)];
 
     drop_slice_in_place(&x);
@@ -34,7 +35,7 @@ fn drop_slice_in_place(x: &[StructWithDtor]) {
         // This is the interesting thing in this test case: Normally we would
         // not have drop-glue for the unsized [StructWithDtor]. This has to be
         // generated though when the drop_in_place() intrinsic is used.
-        //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic.cgu-0[Internal]
+        //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic0[Internal]
         ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]);
     }
 }
diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs
index 06e02b10015..65936d12e31 100644
--- a/src/test/codegen-units/item-collection/generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs
@@ -10,6 +10,7 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
@@ -45,7 +46,7 @@ enum EnumNoDrop<T1, T2> {
 struct NonGenericNoDrop(i32);
 
 struct NonGenericWithDrop(i32);
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::NonGenericWithDrop[0]> @@ generic_drop_glue0[Internal]
 
 impl Drop for NonGenericWithDrop {
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
@@ -54,11 +55,11 @@ impl Drop for NonGenericWithDrop {
 
 //~ TRANS_ITEM fn generic_drop_glue::main[0]
 fn main() {
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<i8, char>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
     let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
     let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
 
@@ -67,17 +68,17 @@ fn main() {
 
     // This is supposed to generate drop-glue because it contains a field that
     // needs to be dropped.
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::StructNoDrop[0]<generic_drop_glue::NonGenericWithDrop[0], f64>> @@ generic_drop_glue0[Internal]
     let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<i32, i64>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<i32, i64>
     let _ = match EnumWithDrop::A::<i32, i64>(0) {
         EnumWithDrop::A(x) => x,
         EnumWithDrop::B(x) => x as i32
     };
 
-    //~TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue.cgu-0[Internal]
+    //~TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<generic_drop_glue::EnumWithDrop[0]<f64, f32>> @@ generic_drop_glue0[Internal]
     //~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<f64, f32>
     let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
         EnumWithDrop::A(x) => x,
diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
index 9c6bdb6624e..e32366d15c3 100644
--- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
+++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs
@@ -10,6 +10,7 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
@@ -31,13 +32,13 @@ impl<T> Trait for Struct<T> {
 fn main() {
     let s1 = Struct { _a: 0u32 };
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u32>> @@ instantiation_through_vtable0[Internal]
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u32>
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u32>
     let _ = &s1 as &Trait;
 
     let s1 = Struct { _a: 0u64 };
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<instantiation_through_vtable::Struct[0]<u64>> @@ instantiation_through_vtable0[Internal]
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u64>
     //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u64>
     let _ = &s1 as &Trait;
diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
index 5f70ff396dd..5765f230e8b 100644
--- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs
@@ -10,10 +10,11 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::StructWithDrop[0]> @@ non_generic_drop_glue0[Internal]
 struct StructWithDrop {
     x: i32
 }
@@ -27,7 +28,7 @@ struct StructNoDrop {
     x: i32
 }
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<non_generic_drop_glue::EnumWithDrop[0]> @@ non_generic_drop_glue0[Internal]
 enum EnumWithDrop {
     A(i32)
 }
diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
index e41cb34eec6..be560690e51 100644
--- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
@@ -10,14 +10,15 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Root[0]> @@ transitive_drop_glue0[Internal]
 struct Root(Intermediate);
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Intermediate[0]> @@ transitive_drop_glue0[Internal]
 struct Intermediate(Leaf);
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::Leaf[0]> @@ transitive_drop_glue0[Internal]
 struct Leaf;
 
 impl Drop for Leaf {
@@ -38,15 +39,15 @@ fn main() {
 
     let _ = Root(Intermediate(Leaf));
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<u32>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<u32>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<u32>> @@ transitive_drop_glue0[Internal]
     //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<u32>
     let _ = RootGen(IntermediateGen(LeafGen(0u32)));
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::RootGen[0]<i16>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::IntermediateGen[0]<i16>> @@ transitive_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<transitive_drop_glue::LeafGen[0]<i16>> @@ transitive_drop_glue0[Internal]
     //~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
     let _ = RootGen(IntermediateGen(LeafGen(0i16)));
 }
diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
index 39043cf87cb..ad1475a73f7 100644
--- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs
@@ -10,10 +10,11 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
-//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue.cgu-0[Internal]
+//~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<tuple_drop_glue::Dropped[0]> @@ tuple_drop_glue0[Internal]
 struct Dropped;
 
 impl Drop for Dropped {
@@ -23,10 +24,10 @@ impl Drop for Dropped {
 
 //~ TRANS_ITEM fn tuple_drop_glue::main[0]
 fn main() {
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue0[Internal]
     let x = (0u32, Dropped);
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue.cgu-0[Internal]
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue0[Internal]
     let x = (0i16, (Dropped, true));
 }
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index de7613741b2..d7e457cde8a 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -10,6 +10,7 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 #![feature(coerce_unsized)]
@@ -57,13 +58,13 @@ fn main()
 {
     // simple case
     let bool_sized = &true;
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<bool> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0]
     let _bool_unsized = bool_sized as &Trait;
 
     let char_sized = &'a';
 
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<char> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0]
     let _char_unsized = char_sized as &Trait;
 
@@ -73,13 +74,13 @@ fn main()
         _b: 2,
         _c: 3.0f64
     };
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<f64> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0]
     let _struct_unsized = struct_sized as &Struct<Trait>;
 
     // custom coercion
     let wrapper_sized = Wrapper(&0u32);
-    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing.cgu-0[Internal]
+    //~ TRANS_ITEM fn core::ptr[0]::drop_in_place[0]<u32> @@ unsizing0[Internal]
     //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0]
     let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
 }
diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs
index 4e6ae167024..29528644ed0 100644
--- a/src/test/codegen-units/partitioning/extern-drop-glue.rs
+++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs
@@ -13,6 +13,7 @@
 // We specify -Z incremental here because we want to test the partitioning for
 // incremental compilation
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/extern-drop-glue
+// compile-flags:-Zinline-in-all-cgus
 
 #![allow(dead_code)]
 #![crate_type="lib"]
diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs
index 20920c9ebe4..4bfd35b59bc 100644
--- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs
+++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs
@@ -12,6 +12,7 @@
 // We specify -Z incremental here because we want to test the partitioning for
 // incremental compilation
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/inlining-from-extern-crate
+// compile-flags:-Zinline-in-all-cgus
 
 #![crate_type="lib"]
 
diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs
index d2ce847e108..65e91343ccf 100644
--- a/src/test/codegen-units/partitioning/local-drop-glue.rs
+++ b/src/test/codegen-units/partitioning/local-drop-glue.rs
@@ -12,6 +12,7 @@
 // We specify -Z incremental here because we want to test the partitioning for
 // incremental compilation
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-drop-glue
+// compile-flags:-Zinline-in-all-cgus
 
 #![allow(dead_code)]
 #![crate_type="lib"]
diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs
new file mode 100644
index 00000000000..84464a627be
--- /dev/null
+++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs
@@ -0,0 +1,54 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// We specify -Z incremental here because we want to test the partitioning for
+// incremental compilation
+// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining-but-not-all
+// compile-flags:-Zinline-in-all-cgus=no
+
+#![allow(dead_code)]
+#![crate_type="lib"]
+
+mod inline {
+
+    //~ TRANS_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External]
+    #[inline]
+    pub fn inlined_function()
+    {
+
+    }
+}
+
+mod user1 {
+    use super::inline;
+
+    //~ TRANS_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[Internal]
+    fn foo() {
+        inline::inlined_function();
+    }
+}
+
+mod user2 {
+    use super::inline;
+
+    //~ TRANS_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[Internal]
+    fn bar() {
+        inline::inlined_function();
+    }
+}
+
+mod non_user {
+
+    //~ TRANS_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[Internal]
+    fn baz() {
+
+    }
+}
diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs
index a4d9e60d228..f3176191241 100644
--- a/src/test/codegen-units/partitioning/local-inlining.rs
+++ b/src/test/codegen-units/partitioning/local-inlining.rs
@@ -12,6 +12,7 @@
 // We specify -Z incremental here because we want to test the partitioning for
 // incremental compilation
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining
+// compile-flags:-Zinline-in-all-cgus
 
 #![allow(dead_code)]
 #![crate_type="lib"]
diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs
index 1beaa186d9e..bda76a8789f 100644
--- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs
+++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs
@@ -12,6 +12,7 @@
 // We specify -Z incremental here because we want to test the partitioning for
 // incremental compilation
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-transitive-inlining
+// compile-flags:-Zinline-in-all-cgus
 
 #![allow(dead_code)]
 #![crate_type="lib"]
diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs
index 74f2f843567..302f9312b57 100644
--- a/src/test/codegen-units/partitioning/vtable-through-const.rs
+++ b/src/test/codegen-units/partitioning/vtable-through-const.rs
@@ -13,6 +13,7 @@
 // We specify -Z incremental here because we want to test the partitioning for
 // incremental compilation
 // compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/vtable-through-const
+// compile-flags:-Zinline-in-all-cgus
 
 // This test case makes sure, that references made through constants are
 // recorded properly in the InliningMap.
diff --git a/src/test/codegen/abi-x86-interrupt.rs b/src/test/codegen/abi-x86-interrupt.rs
index 838cd4bf6d7..e0b37cb2f32 100644
--- a/src/test/codegen/abi-x86-interrupt.rs
+++ b/src/test/codegen/abi-x86-interrupt.rs
@@ -14,7 +14,6 @@
 
 // ignore-arm
 // ignore-aarch64
-// min-llvm-version 3.8
 
 // compile-flags: -C no-prepopulate-passes
 
diff --git a/src/test/codegen/auxiliary/nounwind.rs b/src/test/codegen/auxiliary/nounwind.rs
new file mode 100644
index 00000000000..5e40e8ede15
--- /dev/null
+++ b/src/test/codegen/auxiliary/nounwind.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_mangle]
+pub fn bar() {
+}
diff --git a/src/test/codegen/float_math.rs b/src/test/codegen/float_math.rs
index bc458d45446..6a6d6f90b2e 100644
--- a/src/test/codegen/float_math.rs
+++ b/src/test/codegen/float_math.rs
@@ -19,7 +19,7 @@ use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast};
 #[no_mangle]
 pub fn add(x: f32, y: f32) -> f32 {
 // CHECK: fadd float
-// CHECK-NOT fast
+// CHECK-NOT: fast
     x + y
 }
 
diff --git a/src/test/codegen/issue-37945.rs b/src/test/codegen/issue-37945.rs
index e7c91f30918..df02426badc 100644
--- a/src/test/codegen/issue-37945.rs
+++ b/src/test/codegen/issue-37945.rs
@@ -13,6 +13,7 @@
 // ignore-x86
 // ignore-arm
 // ignore-emscripten
+// ignore-gnux32
 // ignore 32-bit platforms (LLVM has a bug with them)
 
 // See issue #37945.
diff --git a/src/test/codegen/mainsubprogram.rs b/src/test/codegen/mainsubprogram.rs
index 657f4b662f7..f0508bc90f2 100644
--- a/src/test/codegen/mainsubprogram.rs
+++ b/src/test/codegen/mainsubprogram.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// The minimum LLVM version is set to 3.8, but really this test
-// depends on a patch that is was committed to upstream LLVM before
-// 4.0; and also backported to the Rust LLVM fork.
+// This test depends on a patch that was committed to upstream LLVM
+// before 4.0, formerly backported to the Rust LLVM fork.
 
 // ignore-tidy-linelength
 // ignore-windows
 // ignore-macos
-// min-llvm-version 3.8
+// min-llvm-version 4.0
 
 // compile-flags: -g -C no-prepopulate-passes
 
diff --git a/src/test/codegen/mainsubprogramstart.rs b/src/test/codegen/mainsubprogramstart.rs
index cd34a1670dc..8325318f9af 100644
--- a/src/test/codegen/mainsubprogramstart.rs
+++ b/src/test/codegen/mainsubprogramstart.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// The minimum LLVM version is set to 3.8, but really this test
-// depends on a patch that is was committed to upstream LLVM before
-// 4.0; and also backported to the Rust LLVM fork.
+// This test depends on a patch that was committed to upstream LLVM
+// before 4.0, formerly backported to the Rust LLVM fork.
 
 // ignore-tidy-linelength
 // ignore-windows
 // ignore-macos
-// min-llvm-version 3.8
+// min-llvm-version 4.0
 
 // compile-flags: -g -C no-prepopulate-passes
 
diff --git a/src/test/codegen/nounwind.rs b/src/test/codegen/nounwind.rs
new file mode 100644
index 00000000000..9fea907d3c8
--- /dev/null
+++ b/src/test/codegen/nounwind.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:nounwind.rs
+// compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a
+// ignore-windows
+
+#![crate_type = "lib"]
+
+extern crate nounwind;
+
+#[no_mangle]
+pub fn foo() {
+    nounwind::bar();
+// CHECK: @foo() unnamed_addr #0
+// CHECK: @bar() unnamed_addr #0
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+}
+
diff --git a/src/test/codegen/panic-abort-windows.rs b/src/test/codegen/panic-abort-windows.rs
index 2ab15277084..15688bdc2a1 100644
--- a/src/test/codegen/panic-abort-windows.rs
+++ b/src/test/codegen/panic-abort-windows.rs
@@ -28,7 +28,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK: Function Attrs: uwtable
+// CHECK: Function Attrs: nounwind uwtable
 // CHECK-NEXT: define void @normal_uwtable()
 #[no_mangle]
 pub fn normal_uwtable() {
diff --git a/src/test/compile-fail/borrowck/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck/borrowck-assign-comp.rs
index e63de3a3bed..548436c3ed8 100644
--- a/src/test/compile-fail/borrowck/borrowck-assign-comp.rs
+++ b/src/test/compile-fail/borrowck/borrowck-assign-comp.rs
@@ -22,7 +22,7 @@ fn a() {
     // immutable.  Otherwise the type of &_q.x (&isize) would be wrong.
     p.x = 5; //[ast]~ ERROR cannot assign to `p.x`
              //[mir]~^ ERROR cannot assign to `p.x` because it is borrowed (Ast)
-             //[mir]~| ERROR cannot assign to `p.0` because it is borrowed (Mir)
+             //[mir]~| ERROR cannot assign to `p.x` because it is borrowed (Mir)
     q.x;
 }
 
@@ -47,7 +47,7 @@ fn d() {
     let q = &p.y;
     p.y = 5; //[ast]~ ERROR cannot assign to `p.y`
              //[mir]~^ ERROR cannot assign to `p.y` because it is borrowed (Ast)
-             //[mir]~| ERROR cannot assign to `p.1` because it is borrowed (Mir)
+             //[mir]~| ERROR cannot assign to `p.y` because it is borrowed (Mir)
     *q;
 }
 
diff --git a/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs
index 6c003ec2d48..0b6b9bf7d48 100644
--- a/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs
+++ b/src/test/compile-fail/borrowck/borrowck-closures-mut-and-imm.rs
@@ -82,7 +82,7 @@ fn g() {
     let c1 = || get(&*x.f);
     *x.f = 5; //[ast]~ ERROR cannot assign to `*x.f`
               //[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed (Ast)
-              //[mir]~| ERROR cannot assign to `(*(*x).0)` because it is borrowed (Mir)
+              //[mir]~| ERROR cannot assign to `(*x.f)` because it is borrowed (Mir)
 }
 
 fn h() {
diff --git a/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
new file mode 100644
index 00000000000..cff913b17be
--- /dev/null
+++ b/src/test/compile-fail/borrowck/borrowck-describe-lvalue.rs
@@ -0,0 +1,330 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+#![feature(slice_patterns)]
+#![feature(advanced_slice_patterns)]
+
+pub struct Foo {
+  x: u32
+}
+
+pub struct Bar(u32);
+
+pub enum Baz {
+    X(u32)
+}
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+impl Foo {
+  fn x(&mut self) -> &mut u32 { &mut self.x }
+}
+
+impl Bar {
+    fn x(&mut self) -> &mut u32 { &mut self.0 }
+}
+
+impl Baz {
+    fn x(&mut self) -> &mut u32 {
+        match *self {
+            Baz::X(ref mut value) => value
+        }
+    }
+}
+
+static mut sfoo : Foo = Foo{x: 23 };
+static mut sbar : Bar = Bar(23);
+static mut stuple : (i32, i32) = (24, 25);
+static mut senum : Baz = Baz::X(26);
+static mut sunion : U = U { a: 0 };
+
+fn main() {
+    // Local and field from struct
+    {
+        let mut f = Foo { x: 22 };
+        let _x = f.x();
+        f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `f.x` because it was mutably borrowed (Mir)
+    }
+    // Local and field from tuple-struct
+    {
+        let mut g = Bar(22);
+        let _0 = g.x();
+        g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `g.0` because it was mutably borrowed (Mir)
+    }
+    // Local and field from tuple
+    {
+        let mut h = (22, 23);
+        let _0 = &mut h.0;
+        h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `h.0` because it was mutably borrowed (Mir)
+    }
+    // Local and field from enum
+    {
+        let mut e = Baz::X(2);
+        let _e0 = e.x();
+        match e {
+            Baz::X(value) => value
+            //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
+            //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed (Ast)
+            //[mir]~| ERROR cannot use `e.0` because it was mutably borrowed (Mir)
+        };
+    }
+    // Local and field from union
+    unsafe {
+        let mut u = U { b: 0 };
+        let _ra = &mut u.a;
+        u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir)
+    }
+    // Static and field from struct
+    unsafe {
+        let _x = sfoo.x();
+        sfoo.x; //[mir]~ ERROR cannot use `sfoo.x` because it was mutably borrowed (Mir)
+    }
+    // Static and field from tuple-struct
+    unsafe {
+        let _0 = sbar.x();
+        sbar.0; //[mir]~ ERROR cannot use `sbar.0` because it was mutably borrowed (Mir)
+    }
+    // Static and field from tuple
+    unsafe {
+        let _0 = &mut stuple.0;
+        stuple.0; //[mir]~ ERROR cannot use `stuple.0` because it was mutably borrowed (Mir)
+    }
+    // Static and field from enum
+    unsafe {
+        let _e0 = senum.x();
+        match senum {
+            Baz::X(value) => value
+            //[mir]~^ ERROR cannot use `senum.0` because it was mutably borrowed (Mir)
+        };
+    }
+    // Static and field from union
+    unsafe {
+        let _ra = &mut sunion.a;
+        sunion.a; //[mir]~ ERROR cannot use `sunion.a` because it was mutably borrowed (Mir)
+    }
+    // Deref and field from struct
+    {
+        let mut f = Box::new(Foo { x: 22 });
+        let _x = f.x();
+        f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `f.x` because it was mutably borrowed (Mir)
+    }
+    // Deref and field from tuple-struct
+    {
+        let mut g = Box::new(Bar(22));
+        let _0 = g.x();
+        g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `g.0` because it was mutably borrowed (Mir)
+    }
+    // Deref and field from tuple
+    {
+        let mut h = Box::new((22, 23));
+        let _0 = &mut h.0;
+        h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `h.0` because it was mutably borrowed (Mir)
+    }
+    // Deref and field from enum
+    {
+        let mut e = Box::new(Baz::X(3));
+        let _e0 = e.x();
+        match *e {
+            Baz::X(value) => value
+            //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
+            //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed (Ast)
+            //[mir]~| ERROR cannot use `e.0` because it was mutably borrowed (Mir)
+        };
+    }
+    // Deref and field from union
+    unsafe {
+        let mut u = Box::new(U { b: 0 });
+        let _ra = &mut u.a;
+        u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
+             //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast)
+             //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir)
+    }
+    // Constant index
+    {
+        let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+        let _v = &mut v;
+        match v {
+            &[x, _, .., _, _] => println!("{}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+                            _ => panic!("other case"),
+        }
+        match v {
+            &[_, x, .., _, _] => println!("{}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+                            _ => panic!("other case"),
+        }
+        match v {
+            &[_, _, .., x, _] => println!("{}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+                            _ => panic!("other case"),
+        }
+        match v {
+            &[_, _, .., _, x] => println!("{}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+                            _ => panic!("other case"),
+        }
+    }
+    // Subslices
+    {
+        let mut v = &[1, 2, 3, 4, 5];
+        let _v = &mut v;
+        match v {
+            &[x..] => println!("{:?}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+            _ => panic!("other case"),
+        }
+        match v {
+            &[_, x..] => println!("{:?}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+            _ => panic!("other case"),
+        }
+        match v {
+            &[x.., _] => println!("{:?}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+            _ => panic!("other case"),
+        }
+        match v {
+            &[_, x.., _] => println!("{:?}", x),
+                //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
+                //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed (Ast)
+                //[mir]~| ERROR cannot use `v[..]` because it was mutably borrowed (Mir)
+            _ => panic!("other case"),
+        }
+    }
+    // Downcasted field
+    {
+        enum E<X> { A(X), B { x: X } }
+
+        let mut e = E::A(3);
+        let _e = &mut e;
+        match e {
+            E::A(ref ax) =>
+                //[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable
+                //[mir]~^^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable (Ast)
+                //[mir]~| ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable (Mir)
+                //[mir]~| ERROR cannot use `e` because it was mutably borrowed (Mir)
+                println!("e.ax: {:?}", ax),
+            E::B { x: ref bx } =>
+                //[ast]~^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable
+                //[mir]~^^ ERROR cannot borrow `e.x` as immutable because `e` is also borrowed as mutable (Ast)
+                //[mir]~| ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable (Mir)
+                println!("e.bx: {:?}", bx),
+        }
+    }
+    // Field in field
+    {
+        struct F { x: u32, y: u32 };
+        struct S { x: F, y: (u32, u32), };
+        let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) };
+        let _s = &mut s;
+        match s {
+            S  { y: (ref y0, _), .. } =>
+                //[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable
+                //[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable (Ast)
+                //[mir]~| ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable (Mir)
+                println!("y0: {:?}", y0),
+            _ => panic!("other case"),
+        }
+        match s {
+            S  { x: F { y: ref x0, .. }, .. } =>
+                //[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable
+                //[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable (Ast)
+                //[mir]~| ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable (Mir)
+                println!("x0: {:?}", x0),
+            _ => panic!("other case"),
+        }
+    }
+    // Field of ref
+    {
+        struct Block<'a> {
+            current: &'a u8,
+            unrelated: &'a u8,
+        };
+
+        fn bump<'a>(mut block: &mut Block<'a>) {
+            let x = &mut block;
+            let p: &'a u8 = &*block.current;
+            //[mir]~^ ERROR cannot borrow `(*block.current)` as immutable because it is also borrowed as mutable (Mir)
+            // No errors in AST because of issue rust#38899
+        }
+    }
+    // Field of ptr
+    {
+        struct Block2 {
+            current: *const u8,
+            unrelated: *const u8,
+        }
+
+        unsafe fn bump2(mut block: *mut Block2) {
+            let x = &mut block;
+            let p : *const u8 = &*(*block).current;
+            //[mir]~^ ERROR cannot borrow `(*block.current)` as immutable because it is also borrowed as mutable (Mir)
+            // No errors in AST because of issue rust#38899
+        }
+    }
+    // Field of index
+    {
+        struct F {x: u32, y: u32};
+        let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
+        let _v = &mut v;
+        v[0].y;
+        //[ast]~^ ERROR cannot use `v[..].y` because it was mutably borrowed
+        //[mir]~^^ ERROR cannot use `v[..].y` because it was mutably borrowed (Ast)
+        //[mir]~| ERROR cannot use `v[..].y` because it was mutably borrowed (Mir)
+        //[mir]~| ERROR cannot use `(*v)` because it was mutably borrowed (Mir)
+    }
+    // Field of constant index
+    {
+        struct F {x: u32, y: u32};
+        let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
+        let _v = &mut v;
+        match v {
+            &[_, F {x: ref xf, ..}] => println!("{}", xf),
+            //[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable (Mir)
+            // No errors in AST
+            _ => panic!("other case")
+        }
+    }
+}
diff --git a/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs b/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs
index 3098807f272..fcdcf198c28 100644
--- a/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs
+++ b/src/test/compile-fail/borrowck/borrowck-fn-in-const-a.rs
@@ -8,12 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Check that we check fns appearing in constant declarations.
 // Issue #22382.
 
 const MOVE: fn(&String) -> String = {
     fn broken(x: &String) -> String {
-        return *x //~ ERROR cannot move
+        return *x //[ast]~ ERROR cannot move out of borrowed content [E0507]
+                  //[mir]~^ ERROR (Ast) [E0507]
+                  //[mir]~| ERROR (Mir) [E0507]
     }
     broken
 };
diff --git a/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs b/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs
index 569ddb80c2f..017318b6b21 100644
--- a/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs
+++ b/src/test/compile-fail/borrowck/borrowck-init-in-fru.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 #[derive(Clone)]
 struct point {
     x: isize,
@@ -16,6 +19,9 @@ struct point {
 
 fn main() {
     let mut origin: point;
-    origin = point {x: 10,.. origin}; //~ ERROR use of possibly uninitialized variable: `origin.y`
+    origin = point {x: 10,.. origin};
+    //[ast]~^ ERROR use of possibly uninitialized variable: `origin.y` [E0381]
+    //[mir]~^^ ERROR (Ast) [E0381]
+    //[mir]~|  ERROR (Mir) [E0381]
     origin.clone();
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs
new file mode 100644
index 00000000000..1d21f40fcca
--- /dev/null
+++ b/src/test/compile-fail/borrowck/borrowck-match-already-borrowed.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+fn main() {
+    let mut x = 1;
+    let _x = &mut x;
+    let _ = match x {
+        x => x + 1, //[ast]~ ERROR E0503
+                    //[mir]~^ ERROR (Mir) [E0503]
+                    //[mir]~| ERROR (Ast) [E0503]
+        y => y + 2, //[ast]~ ERROR [E0503]
+                    //[mir]~^ ERROR (Mir) [E0503]
+                    //[mir]~| ERROR (Ast) [E0503]
+    };
+}
diff --git a/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs b/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs
index ec505faf885..99b5ef794c2 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-in-irrefut-pat.rs
@@ -8,19 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 fn with<F>(f: F) where F: FnOnce(&String) {}
 
 fn arg_item(&_x: &String) {}
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 
 fn arg_closure() {
     with(|&_x| ())
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 }
 
 fn let_pat() {
     let &_x = &"hi".to_string();
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 }
 
 pub fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
index bf4c7474136..c7e1ea1b758 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs
@@ -8,9 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 use std::rc::Rc;
 
 pub fn main() {
     let _x = Rc::new(vec![1, 2]).into_iter();
-    //~^ ERROR cannot move out of borrowed content
+    //[ast]~^ ERROR cannot move out of borrowed content [E0507]
+    //[mir]~^^ ERROR (Ast) [E0507]
+    //[mir]~|  ERROR (Mir) [E0507]
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs
index 8b83b945fd1..9e8021fd108 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-static-item.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Ensure that moves out of static items is forbidden
 
 struct Foo {
@@ -22,5 +25,7 @@ fn test(f: Foo) {
 }
 
 fn main() {
-    test(BAR); //~ ERROR cannot move out of static item
+    test(BAR); //[ast]~ ERROR cannot move out of static item [E0507]
+               //[mir]~^ ERROR (Ast) [E0507]
+               //[mir]~| ERROR (Mir) [E0507]
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
index 16302d276ce..982f31b1341 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 struct S {f:String}
 impl Drop for S {
     fn drop(&mut self) { println!("{}", self.f); }
@@ -16,17 +19,23 @@ impl Drop for S {
 fn move_in_match() {
     match (S {f:"foo".to_string()}) {
         S {f:_s} => {}
-        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
+        //[mir]~^^ ERROR (Ast) [E0509]
+        //[mir]~|  ERROR (Mir) [E0509]
     }
 }
 
 fn move_in_let() {
     let S {f:_s} = S {f:"foo".to_string()};
-    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+    //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn move_in_fn_arg(S {f:_s}: S) {
-    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
+    //[ast]~^ ERROR cannot move out of type `S`, which implements the `Drop` trait [E0509]
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
index c364788a9cc..4a1828c6958 100644
--- a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Issue 4691: Ensure that functional-struct-update can only copy, not
 // move, when the struct implements Drop.
 
@@ -20,12 +23,16 @@ impl Drop for T { fn drop(&mut self) { } }
 
 fn f(s0:S) {
     let _s2 = S{a: 2, ..s0};
-    //~^ error: cannot move out of type `S`, which implements the `Drop` trait
+    //[ast]~^ error: cannot move out of type `S`, which implements the `Drop` trait
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn g(s0:T) {
     let _s2 = T{a: 2, ..s0};
-    //~^ error: cannot move out of type `T`, which implements the `Drop` trait
+    //[ast]~^ error: cannot move out of type `T`, which implements the `Drop` trait
+    //[mir]~^^ ERROR (Ast) [E0509]
+    //[mir]~|  ERROR (Mir) [E0509]
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/borrowck/borrowck-unary-move.rs b/src/test/compile-fail/borrowck/borrowck-unary-move.rs
index 5b5c5f4da91..6cab5a8bf60 100644
--- a/src/test/compile-fail/borrowck/borrowck-unary-move.rs
+++ b/src/test/compile-fail/borrowck/borrowck-unary-move.rs
@@ -8,10 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-linelength
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
 
 fn foo(x: Box<isize>) -> isize {
     let y = &*x;
-    free(x); //~ ERROR cannot move out of `x` because it is borrowed
+    free(x); //[ast]~ ERROR cannot move out of `x` because it is borrowed
+    //[mir]~^ ERROR cannot move out of `x` because it is borrowed (Ast)
+    //[mir]~| ERROR cannot move out of `x` because it is borrowed (Mir)
     *y
 }
 
diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs
new file mode 100644
index 00000000000..957086f6af1
--- /dev/null
+++ b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs
@@ -0,0 +1,49 @@
+// 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.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+// Check that do not allow access to fields of uninitialized or moved
+// structs.
+
+#[derive(Default)]
+struct Point {
+    x: isize,
+    y: isize,
+}
+
+#[derive(Default)]
+struct Line {
+    origin: Point,
+    middle: Point,
+    target: Point,
+}
+
+impl Line { fn consume(self) { } }
+
+fn main() {
+    let mut a: Point;
+    let _ = a.x + 1; //[ast]~ ERROR use of possibly uninitialized variable: `a.x`
+                     //[mir]~^ ERROR       [E0381]
+                     //[mir]~| ERROR (Mir) [E0381]
+
+    let mut line1 = Line::default();
+    let _moved = line1.origin;
+    let _ = line1.origin.x + 1; //[ast]~ ERROR use of collaterally moved value: `line1.origin.x`
+                                //[mir]~^       [E0382]
+                                //[mir]~| (Mir) [E0381]
+
+    let mut line2 = Line::default();
+    let _moved = (line2.origin, line2.middle);
+    line2.consume(); //[ast]~ ERROR use of partially moved value: `line2` [E0382]
+                     //[mir]~^       [E0382]
+                     //[mir]~| (Mir) [E0381]
+}
diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs b/src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs
new file mode 100644
index 00000000000..71f8693b210
--- /dev/null
+++ b/src/test/compile-fail/borrowck/borrowck-uninit-ref-chain.rs
@@ -0,0 +1,60 @@
+// 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.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
+struct S<X, Y> {
+    x: X,
+    y: Y,
+}
+
+fn main() {
+    let x: &&Box<i32>;
+    let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
+                   //[mir]~^ (Ast) [E0381]
+                   //[mir]~| (Mir) [E0381]
+
+    let x: &&S<i32, i32>;
+    let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
+                   //[mir]~^ (Ast) [E0381]
+                   //[mir]~| (Mir) [E0381]
+
+    let x: &&i32;
+    let _y = &**x; //[ast]~ ERROR use of possibly uninitialized variable: `**x` [E0381]
+                   //[mir]~^ (Ast) [E0381]
+                   //[mir]~| (Mir) [E0381]
+
+
+    let mut a: S<i32, i32>;
+    a.x = 0;
+    let _b = &a.x; //[ast]~ ERROR use of possibly uninitialized variable: `a.x` [E0381]
+                   //[mir]~^ ERROR (Ast) [E0381]
+                   // (deliberately *not* an error under MIR-borrowck)
+
+    let mut a: S<&&i32, &&i32>;
+    a.x = &&0;
+    let _b = &**a.x; //[ast]~ ERROR use of possibly uninitialized variable: `**a.x` [E0381]
+                     //[mir]~^ ERROR (Ast) [E0381]
+                     // (deliberately *not* an error under MIR-borrowck)
+
+
+    let mut a: S<i32, i32>;
+    a.x = 0;
+    let _b = &a.y; //[ast]~ ERROR use of possibly uninitialized variable: `a.y` [E0381]
+                   //[mir]~^ ERROR (Ast) [E0381]
+                   //[mir]~| ERROR (Mir) [E0381]
+
+    let mut a: S<&&i32, &&i32>;
+    a.x = &&0;
+    let _b = &**a.y; //[ast]~ ERROR use of possibly uninitialized variable: `**a.y` [E0381]
+                     //[mir]~^ ERROR (Ast) [E0381]
+                     //[mir]~| ERROR (Mir) [E0381]
+}
diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
index 73d323ea82c..0655d2914ee 100644
--- a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
+++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
@@ -34,13 +34,13 @@ fn main() {
             let ra = &u.a;
             let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
                                 //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable (Ast)
-                                //[mir]~| ERROR cannot borrow `u.0` as mutable because it is also borrowed as immutable (Mir)
+                                //[mir]~| ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable (Mir)
         }
         {
             let ra = &u.a;
             u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
                      //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed (Ast)
-                     //[mir]~| ERROR cannot assign to `u.0` because it is borrowed (Mir)
+                     //[mir]~| ERROR cannot assign to `u.a` because it is borrowed (Mir)
         }
         // Imm borrow, other field
         {
@@ -68,25 +68,25 @@ fn main() {
             let rma = &mut u.a;
             let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
                          //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable (Ast)
-                         //[mir]~| ERROR cannot borrow `u.0` as immutable because it is also borrowed as mutable (Mir)
+                         //[mir]~| ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable (Mir)
         }
         {
             let ra = &mut u.a;
             let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
                          //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed (Ast)
-                         //[mir]~| ERROR cannot use `u.0` because it was mutably borrowed (Mir)
+                         //[mir]~| ERROR cannot use `u.a` because it was mutably borrowed (Mir)
         }
         {
             let rma = &mut u.a;
             let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
                                  //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time (Ast)
-                                 //[mir]~| ERROR cannot borrow `u.0` as mutable more than once at a time (Mir)
+                                 //[mir]~| ERROR cannot borrow `u.a` as mutable more than once at a time (Mir)
         }
         {
             let rma = &mut u.a;
             u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
                      //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed (Ast)
-                     //[mir]~| ERROR cannot assign to `u.0` because it is borrowed (Mir)
+                     //[mir]~| ERROR cannot assign to `u.a` because it is borrowed (Mir)
         }
         // Mut borrow, other field
         {
diff --git a/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs b/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs
index 7291bcd2ce1..2b567ebd2db 100644
--- a/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs
+++ b/src/test/compile-fail/borrowck/borrowck-use-in-index-lvalue.rs
@@ -8,12 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 fn test() {
     let w: &mut [isize];
-    w[5] = 0; //~ ERROR use of possibly uninitialized variable: `*w`
+    w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
+              //[mir]~^ ERROR (Ast) [E0381]
+              //[mir]~| ERROR (Mir) [E0381]
 
     let mut w: &mut [isize];
-    w[5] = 0; //~ ERROR use of possibly uninitialized variable: `*w`
+    w[5] = 0; //[ast]~ ERROR use of possibly uninitialized variable: `*w` [E0381]
+              //[mir]~^ ERROR (Ast) [E0381]
+              //[mir]~| ERROR (Mir) [E0381]
 }
 
 fn main() { test(); }
diff --git a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
index 796b455f5c7..a48d09b195a 100644
--- a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
+++ b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Variation on `borrowck-use-uninitialized-in-cast` in which we do a
 // trait cast from an uninitialized source. Issue #20791.
 
@@ -16,5 +19,7 @@ impl Foo for i32 { }
 
 fn main() {
     let x: &i32;
-    let y = x as *const Foo; //~ ERROR use of possibly uninitialized variable: `*x`
+    let y = x as *const Foo; //[ast]~ ERROR use of possibly uninitialized variable: `*x`
+                             //[mir]~^ ERROR (Ast) [E0381]
+                             //[mir]~| ERROR (Mir) [E0381]
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs
index 3f429bbd4b6..bdd90a3ce1e 100644
--- a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs
+++ b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs
@@ -8,11 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Check that we detect unused values that are cast to other things.
 // The problem was specified to casting to `*`, as creating unsafe
 // pointers was not being fully checked. Issue #20791.
 
 fn main() {
     let x: &i32;
-    let y = x as *const i32; //~ ERROR use of possibly uninitialized variable: `*x`
+    let y = x as *const i32; //[ast]~ ERROR use of possibly uninitialized variable: `*x` [E0381]
+                             //[mir]~^ ERROR (Ast) [E0381]
+                             //[mir]~| ERROR (Mir) [E0381]
 }
diff --git a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
index 3c1980e5b36..7f3120cc83e 100644
--- a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
+++ b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z emit-end-regions -Z borrowck-mir
+
 // Regression test for #38520. Check that moves of `Foo` are not
 // permitted as `Foo` is not copy (even in a static/const
 // initializer).
@@ -21,8 +24,12 @@ const fn get(x: Foo) -> usize {
 }
 
 const X: Foo = Foo(22);
-static Y: usize = get(*&X); //~ ERROR E0507
-const Z: usize = get(*&X); //~ ERROR E0507
+static Y: usize = get(*&X); //[ast]~ ERROR E0507
+                            //[mir]~^ ERROR (Ast) [E0507]
+                            //[mir]~| ERROR (Mir) [E0507]
+const Z: usize = get(*&X); //[ast]~ ERROR E0507
+                           //[mir]~^ ERROR (Ast) [E0507]
+                           //[mir]~| ERROR (Mir) [E0507]
 
 fn main() {
 }
diff --git a/src/test/compile-fail/dyn-trait-compatibility.rs b/src/test/compile-fail/dyn-trait-compatibility.rs
new file mode 100644
index 00000000000..a7cfda504c7
--- /dev/null
+++ b/src/test/compile-fail/dyn-trait-compatibility.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.
+
+type A0 = dyn;
+//~^ ERROR cannot find type `dyn` in this scope
+type A1 = dyn::dyn;
+//~^ ERROR Use of undeclared type or module `dyn`
+type A2 = dyn<dyn, dyn>;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+type A3 = dyn<<dyn as dyn>::dyn>;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR Use of undeclared type or module `dyn`
+type A4 = dyn(dyn, dyn) -> dyn;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-crate_visibility_modifier.rs b/src/test/compile-fail/feature-gate-crate_visibility_modifier.rs
new file mode 100644
index 00000000000..a2937d6de31
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-crate_visibility_modifier.rs
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+crate struct Bender { //~ ERROR `crate` visibility modifier is experimental
+    earth: bool,
+    fire: bool,
+    air: bool,
+    water: bool,
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-dyn-trait.rs b/src/test/compile-fail/feature-gate-dyn-trait.rs
new file mode 100644
index 00000000000..4b3803d019b
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-dyn-trait.rs
@@ -0,0 +1,14 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Trait {}
+type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index 06b87206669..ab2fe02bb14 100644
--- a/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -424,7 +424,7 @@ mod no_mangle {
     mod inner { #![no_mangle="3500"] }
 
     #[no_mangle = "3500"] fn f() { }
-    //~^ WARN function f is marked #[no_mangle], but not exported
+    //~^ WARN function is marked #[no_mangle], but not exported
 
     #[no_mangle = "3500"] struct S;
 
diff --git a/src/test/compile-fail/hygiene/impl_items.rs b/src/test/compile-fail/hygiene/impl_items.rs
index 445aa62f236..cdba559445d 100644
--- a/src/test/compile-fail/hygiene/impl_items.rs
+++ b/src/test/compile-fail/hygiene/impl_items.rs
@@ -19,7 +19,7 @@ mod foo {
     }
 
     pub macro m() {
-        let _: () = S.f(); //~ ERROR type `fn(&foo::S) {foo::S::f}` is private
+        let _: () = S.f(); //~ ERROR type `for<'r> fn(&'r foo::S) {foo::S::f}` is private
     }
 }
 
diff --git a/src/test/compile-fail/index-help.rs b/src/test/compile-fail/index-help.rs
new file mode 100644
index 00000000000..2d37fc79250
--- /dev/null
+++ b/src/test/compile-fail/index-help.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.
+
+fn main() {
+    let x = vec![1];
+    x[0i32]; //~ ERROR E0277
+             //~| NOTE vector indices are of type `usize` or ranges of `usize`
+}
diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs
index 276d7f7c9ed..85d91bb2db2 100644
--- a/src/test/compile-fail/issue-12997-2.rs
+++ b/src/test/compile-fail/issue-12997-2.rs
@@ -15,6 +15,6 @@
 #[bench]
 fn bar(x: isize) { }
 //~^ ERROR mismatched types
-//~| expected type `fn(&mut __test::test::Bencher)`
+//~| expected type `for<'r> fn(&'r mut __test::test::Bencher)`
 //~| found type `fn(isize) {bar}`
 //~| expected mutable reference, found isize
diff --git a/src/test/compile-fail/issue-30355.rs b/src/test/compile-fail/issue-30355.rs
new file mode 100644
index 00000000000..ee19d040318
--- /dev/null
+++ b/src/test/compile-fail/issue-30355.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.
+
+pub struct X([u8]);
+
+pub static Y: &'static X = {
+    const Y: &'static [u8] = b"";
+    &X(*Y)
+    //~^ ERROR cannot move out
+    //~^^ ERROR cannot move a
+    //~^^^ ERROR cannot move a
+};
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-33241.rs b/src/test/compile-fail/issue-33241.rs
new file mode 100644
index 00000000000..6a411b4c59c
--- /dev/null
+++ b/src/test/compile-fail/issue-33241.rs
@@ -0,0 +1,23 @@
+// 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.
+
+#![feature(rustc_attrs)]
+
+use std::fmt;
+
+// CoerceUnsized is not implemented for tuples. You can still create
+// an unsized tuple by transmuting a trait object.
+fn any<T>() -> T { unreachable!() }
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+    let t: &(u8, fmt::Debug) = any();
+    println!("{:?}", &t.1);
+}
diff --git a/src/test/compile-fail/issue-37887.rs b/src/test/compile-fail/issue-37887.rs
new file mode 100644
index 00000000000..f120bbbfc9f
--- /dev/null
+++ b/src/test/compile-fail/issue-37887.rs
@@ -0,0 +1,14 @@
+// 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 main() {
+    extern crate libc; //~ ERROR use of unstable
+    use libc::*; //~ ERROR unresolved import
+}
diff --git a/src/test/compile-fail/issue-44239.rs b/src/test/compile-fail/issue-44239.rs
new file mode 100644
index 00000000000..131c6526642
--- /dev/null
+++ b/src/test/compile-fail/issue-44239.rs
@@ -0,0 +1,19 @@
+// 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 main() {
+    let n = 0;
+
+    struct Foo;
+    impl Foo {
+        const N: usize = n;
+        //~^ ERROR attempt to use a non-constant value
+    }
+}
diff --git a/src/test/compile-fail/issue-44578.rs b/src/test/compile-fail/issue-44578.rs
new file mode 100644
index 00000000000..a6ae21c3b54
--- /dev/null
+++ b/src/test/compile-fail/issue-44578.rs
@@ -0,0 +1,34 @@
+// 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.
+
+trait Foo {
+    const AMT: usize;
+}
+
+enum Bar<A, B> {
+    First(A),
+    Second(B),
+}
+
+impl<A: Foo, B: Foo> Foo for Bar<A, B> {
+    const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; //~ ERROR constant evaluation
+}
+
+impl Foo for u8 {
+    const AMT: usize = 1;
+}
+
+impl Foo for u16 {
+    const AMT: usize = 2;
+}
+
+fn main() {
+    println!("{}", <Bar<u16, u8> as Foo>::AMT);
+}
diff --git a/src/test/compile-fail/lint-unexported-no-mangle.rs b/src/test/compile-fail/lint-unexported-no-mangle.rs
index 216fcf93535..cd64dfa7a47 100644
--- a/src/test/compile-fail/lint-unexported-no-mangle.rs
+++ b/src/test/compile-fail/lint-unexported-no-mangle.rs
@@ -10,9 +10,8 @@
 
 // compile-flags:-F private_no_mangle_fns -F no_mangle_const_items -F private_no_mangle_statics
 
-// FIXME(#19495) no_mangle'ing main ICE's.
 #[no_mangle]
-fn foo() { //~ ERROR function foo is marked #[no_mangle], but not exported
+fn foo() { //~ ERROR function is marked #[no_mangle], but not exported
 }
 
 #[allow(dead_code)]
@@ -31,7 +30,7 @@ pub static BAR: u64 = 1;
 
 #[allow(dead_code)]
 #[no_mangle]
-static PRIVATE_BAR: u64 = 1; //~ ERROR static PRIVATE_BAR is marked #[no_mangle], but not exported
+static PRIVATE_BAR: u64 = 1; //~ ERROR static is marked #[no_mangle], but not exported
 
 
 fn main() {
diff --git a/src/test/compile-fail/macro-expanded-include/test.rs b/src/test/compile-fail/macro-expanded-include/test.rs
index bcc2c10653f..4afb61ab76c 100644
--- a/src/test/compile-fail/macro-expanded-include/test.rs
+++ b/src/test/compile-fail/macro-expanded-include/test.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no asm! support
 
 #![feature(asm, rustc_attrs)]
 #![allow(unused)]
diff --git a/src/test/compile-fail/outlives-associated-types.rs b/src/test/compile-fail/outlives-associated-types.rs
new file mode 100644
index 00000000000..778394c9fc8
--- /dev/null
+++ b/src/test/compile-fail/outlives-associated-types.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the outlives computation runs for now...
+
+#![feature(rustc_attrs)]
+
+//todo add all the test cases
+// https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference
+
+#[rustc_outlives]
+struct Direct<'a, T> { //~ ERROR 19:1: 21:2: [] [E0640]
+    field: &'a T
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs b/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs
index 82d14ddb502..c4ab96c8456 100644
--- a/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs
+++ b/src/test/compile-fail/privacy/restricted/auxiliary/pub_restricted.rs
@@ -8,14 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(crate_visibility_modifier)]
+
 pub(crate) struct Crate;
+
 #[derive(Default)]
 pub struct Universe {
     pub x: i32,
-    pub(crate) y: i32
+    pub(crate) y: i32,
+    crate z: i32,
 }
 
 impl Universe {
     pub fn f(&self) {}
     pub(crate) fn g(&self) {}
+    crate fn h(&self) {}
 }
diff --git a/src/test/compile-fail/privacy/restricted/private-in-public.rs b/src/test/compile-fail/privacy/restricted/private-in-public.rs
index 0fdfbaa84bb..4d3f5377797 100644
--- a/src/test/compile-fail/privacy/restricted/private-in-public.rs
+++ b/src/test/compile-fail/privacy/restricted/private-in-public.rs
@@ -8,12 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(crate_visibility_modifier)]
+
 mod foo {
     struct Priv;
     mod bar {
         use foo::Priv;
         pub(super) fn f(_: Priv) {}
         pub(crate) fn g(_: Priv) {} //~ ERROR E0446
+        crate fn h(_: Priv) {} //~ ERROR E0446
     }
 }
 
diff --git a/src/test/compile-fail/privacy/restricted/test.rs b/src/test/compile-fail/privacy/restricted/test.rs
index 2e065ac051b..7f076ebf287 100644
--- a/src/test/compile-fail/privacy/restricted/test.rs
+++ b/src/test/compile-fail/privacy/restricted/test.rs
@@ -50,8 +50,10 @@ fn main() {
     let u = Universe::default();
     let _ = u.x;
     let _ = u.y; //~ ERROR private
+    let _ = u.z; //~ ERROR private
     u.f();
     u.g(); //~ ERROR private
+    u.h(); //~ ERROR private
 }
 
 mod pathological {
diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs
index fdd9166ef29..c0ba38b2402 100644
--- a/src/test/compile-fail/private-inferred-type-3.rs
+++ b/src/test/compile-fail/private-inferred-type-3.rs
@@ -15,7 +15,7 @@
 // error-pattern:type `fn() {<u8 as ext::PrivTrait>::method}` is private
 // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct::{{constructor}}}` is pr
 // error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
-// error-pattern:type `fn(&ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private
+// error-pattern:type `for<'r> fn(&'r ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private
 
 #![feature(decl_macro)]
 
diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs
index 973d467b112..95e3732d613 100644
--- a/src/test/compile-fail/private-inferred-type.rs
+++ b/src/test/compile-fail/private-inferred-type.rs
@@ -56,7 +56,7 @@ mod m {
         PubTupleStruct;
         //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct::{{constructor}}}` is privat
         Pub(0u8).priv_method();
-        //~^ ERROR type `fn(&m::Pub<u8>) {<m::Pub<u8>>::priv_method}` is private
+        //~^ ERROR type `for<'r> fn(&'r m::Pub<u8>) {<m::Pub<u8>>::priv_method}` is private
     }
 
     trait Trait {}
diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs
index ac7dd022c7c..6be65a5e359 100644
--- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs
+++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs
@@ -58,8 +58,8 @@ fn supply_G() {
     want_G(bar);
     want_G(baz);
     //~^ ERROR mismatched types
-    //~| expected type `fn(&'cx S) -> &'static S`
-    //~| found type `fn(&S) -> &S {baz}`
+    //~| expected type `for<'cx> fn(&'cx S) -> &'static S`
+    //~| found type `for<'r> fn(&'r S) -> &'r S {baz}`
     //~| expected concrete lifetime, found bound lifetime parameter 'cx
 }
 
diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs
index cabe0fd48ed..6cd43916731 100644
--- a/src/test/compile-fail/trait-bounds-not-on-struct.rs
+++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs
@@ -8,9 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(dyn_trait)]
 
 struct Foo;
 
 fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
 
+type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
+
 fn main() { }
diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs
index 9596f0287bc..2a28c895b79 100644
--- a/src/test/debuginfo/pretty-std.rs
+++ b/src/test/debuginfo/pretty-std.rs
@@ -44,6 +44,10 @@
 // gdb-command: print some_string
 // gdb-check:$8 = Some = {"IAMA optional string!"}
 
+// gdb-command: set print length 5
+// gdb-command: print some_string
+// gdb-check:$8 = Some = {"IAMA "...}
+
 
 // === LLDB TESTS ==================================================================================
 
diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs
index 647ff5dedf3..0090c2aeef9 100644
--- a/src/test/incremental/hashes/call_expressions.rs
+++ b/src/test/incremental/hashes/call_expressions.rs
@@ -36,10 +36,8 @@ pub fn change_callee_function() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn change_callee_function() {
@@ -55,10 +53,8 @@ pub fn change_argument_function() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn change_argument_function() {
@@ -100,10 +96,8 @@ pub fn change_callee_method() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn change_callee_method() {
@@ -121,10 +115,8 @@ pub fn change_argument_method() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn change_argument_method() {
@@ -142,10 +134,8 @@ pub fn change_ufcs_callee_method() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn change_ufcs_callee_method() {
@@ -163,10 +153,8 @@ pub fn change_argument_method_ufcs() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn change_argument_method_ufcs() {
@@ -184,12 +172,12 @@ pub fn change_to_ufcs() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+// One might think this would be expanded in the HirBody/Mir, but it actually
+// results in slightly different Hir/Mir.
 pub fn change_to_ufcs() {
     let s = Struct;
     Struct::method1(&s, 'x', true);
@@ -208,10 +196,8 @@ mod change_ufcs_callee_indirectly {
     #[cfg(not(cfail1))]
     use super::Struct2 as Struct;
 
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_ufcs_callee_indirectly() {
diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs
index 28e85c94b66..35641e978b7 100644
--- a/src/test/incremental/hashes/consts.rs
+++ b/src/test/incremental/hashes/consts.rs
@@ -30,8 +30,8 @@
 const CONST_VISIBILITY: u8 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub const CONST_VISIBILITY: u8 = 0;
@@ -42,8 +42,8 @@ pub const CONST_VISIBILITY: u8 = 0;
 const CONST_CHANGE_TYPE_1: i32 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_TYPE_1: u32 = 0;
@@ -54,8 +54,8 @@ const CONST_CHANGE_TYPE_1: u32 = 0;
 const CONST_CHANGE_TYPE_2: Option<u32> = None;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_TYPE_2: Option<u64> = None;
@@ -66,11 +66,8 @@ const CONST_CHANGE_TYPE_2: Option<u64> = None;
 const CONST_CHANGE_VALUE_1: i16 = 1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_1: i16 = 2;
 
@@ -80,10 +77,8 @@ const CONST_CHANGE_VALUE_1: i16 = 2;
 const CONST_CHANGE_VALUE_2: i16 = 1 + 1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
@@ -93,10 +88,8 @@ const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
 const CONST_CHANGE_VALUE_3: i16 = 2 + 3;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
@@ -106,10 +99,8 @@ const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
 const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
@@ -126,14 +117,14 @@ mod const_change_type_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as Type;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     const CONST_CHANGE_TYPE_INDIRECTLY_2: Option<Type> = None;
diff --git a/src/test/incremental/hashes/enum_constructors.rs b/src/test/incremental/hashes/enum_constructors.rs
index 7f991b30fc4..f826d47c3e5 100644
--- a/src/test/incremental/hashes/enum_constructors.rs
+++ b/src/test/incremental/hashes/enum_constructors.rs
@@ -45,10 +45,8 @@ fn change_field_value_struct_like() -> Enum {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_field_value_struct_like() -> Enum {
@@ -72,12 +70,12 @@ fn change_field_order_struct_like() -> Enum {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+// FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it
+// would if it were not all constants
 fn change_field_order_struct_like() -> Enum {
     Enum::Struct {
         y: 4,
@@ -113,10 +111,8 @@ fn change_constructor_path_struct_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_path_struct_like() {
@@ -140,10 +136,8 @@ fn change_constructor_variant_struct_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_variant_struct_like() {
@@ -162,10 +156,12 @@ mod change_constructor_path_indirectly_struct_like {
     #[cfg(not(cfail1))]
     use super::Enum2 as TheEnum;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,\
+                TypeckTables"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> TheEnum {
@@ -186,10 +182,8 @@ mod change_constructor_variant_indirectly_struct_like {
     #[cfg(not(cfail1))]
     use super::Enum2::Struct2 as Variant;
 
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> Enum2 {
@@ -209,10 +203,8 @@ fn change_field_value_tuple_like() -> Enum {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_field_value_tuple_like() -> Enum {
@@ -228,10 +220,11 @@ fn change_constructor_path_tuple_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(
+    cfg="cfail2",
+    except="HirBody,MirOptimized,MirValidated,TypeckTables"
+)]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_path_tuple_like() {
@@ -247,10 +240,11 @@ fn change_constructor_variant_tuple_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(
+    cfg="cfail2",
+    except="HirBody,MirOptimized,MirValidated,TypeckTables"
+)]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_variant_tuple_like() {
@@ -265,10 +259,12 @@ mod change_constructor_path_indirectly_tuple_like {
     #[cfg(not(cfail1))]
     use super::Enum2 as TheEnum;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,\
+                TypeckTables"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> TheEnum {
@@ -286,10 +282,8 @@ mod change_constructor_variant_indirectly_tuple_like {
     #[cfg(not(cfail1))]
     use super::Enum2::Tuple2 as Variant;
 
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> Enum2 {
@@ -317,11 +311,8 @@ fn change_constructor_path_c_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
-#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_path_c_like() {
     let _ = Clike2::B;
@@ -336,10 +327,8 @@ fn change_constructor_variant_c_like() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_variant_c_like() {
@@ -354,10 +343,12 @@ mod change_constructor_path_indirectly_c_like {
     #[cfg(not(cfail1))]
     use super::Clike2 as TheEnum;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,\
+                TypeckTables"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> TheEnum {
@@ -375,10 +366,8 @@ mod change_constructor_variant_indirectly_c_like {
     #[cfg(not(cfail1))]
     use super::Clike::B as Variant;
 
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> Clike {
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index 8f84266d5a4..22393fad3d0 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -37,8 +37,8 @@
 enum EnumVisibility { A }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub enum EnumVisibility {
@@ -57,8 +57,8 @@ enum EnumChangeNameCStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeNameCStyleVariant {
@@ -79,8 +79,8 @@ enum EnumChangeNameTupleStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeNameTupleStyleVariant {
@@ -98,8 +98,8 @@ enum EnumChangeNameStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeNameStructStyleVariant {
@@ -117,10 +117,8 @@ enum EnumChangeValueCStyleVariant0 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant0 {
@@ -141,10 +139,8 @@ enum EnumChangeValueCStyleVariant1 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant1 {
@@ -161,8 +157,8 @@ enum EnumAddCStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumAddCStyleVariant {
@@ -180,8 +176,8 @@ enum EnumRemoveCStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumRemoveCStyleVariant {
@@ -197,8 +193,8 @@ enum EnumAddTupleStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumAddTupleStyleVariant {
@@ -216,8 +212,8 @@ enum EnumRemoveTupleStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumRemoveTupleStyleVariant {
@@ -233,8 +229,8 @@ enum EnumAddStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumAddStructStyleVariant {
@@ -252,8 +248,8 @@ enum EnumRemoveStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumRemoveStructStyleVariant {
@@ -269,8 +265,8 @@ enum EnumChangeFieldTypeTupleStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeFieldTypeTupleStyleVariant {
@@ -290,8 +286,8 @@ enum EnumChangeFieldTypeStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeFieldTypeStructStyleVariant {
@@ -313,8 +309,8 @@ enum EnumChangeFieldNameStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeFieldNameStructStyleVariant {
@@ -330,8 +326,8 @@ enum EnumChangeOrderTupleStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeOrderTupleStyleVariant {
@@ -353,8 +349,8 @@ enum EnumChangeFieldOrderStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeFieldOrderStructStyleVariant {
@@ -370,8 +366,8 @@ enum EnumAddFieldTupleStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumAddFieldTupleStyleVariant {
@@ -387,8 +383,8 @@ enum EnumAddFieldStructStyleVariant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumAddFieldStructStyleVariant {
@@ -405,8 +401,8 @@ enum EnumAddMustUse {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[must_use]
@@ -425,8 +421,8 @@ enum EnumAddReprC {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[repr(C)]
@@ -444,11 +440,10 @@ enum EnumChangeNameOfTypeParameter<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumChangeNameOfTypeParameter<T> {
     Variant1(T),
 }
@@ -463,11 +458,10 @@ enum EnumAddTypeParameter<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddTypeParameter<S, T> {
     Variant1(S),
     Variant2(T),
@@ -482,11 +476,10 @@ enum EnumChangeNameOfLifetimeParameter<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2", except="PredicatesOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumChangeNameOfLifetimeParameter<'b> {
     Variant1(&'b u32),
 }
@@ -501,11 +494,10 @@ enum EnumAddLifetimeParameter<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2", except="PredicatesOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddLifetimeParameter<'a, 'b> {
     Variant1(&'a u32),
     Variant2(&'b u32),
@@ -521,11 +513,10 @@ enum EnumAddLifetimeParameterBound<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2", except="GenericsOfItem,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
     Variant1(&'a u32),
     Variant2(&'b u32),
@@ -539,11 +530,10 @@ enum EnumAddLifetimeBoundToParameter<'a, T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2", except="TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
     Variant1(T),
     Variant2(&'a u32),
@@ -558,11 +548,10 @@ enum EnumAddTraitBound<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddTraitBound<T: Sync> {
     Variant1(T),
 }
@@ -577,11 +566,10 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2", except="GenericsOfItem,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
     Variant1(&'a u32),
     Variant2(&'b u32),
@@ -597,11 +585,10 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2", except="TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
     Variant1(T),
     Variant2(&'a u32),
@@ -616,11 +603,10 @@ enum EnumAddTraitBoundWhere<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
-#[repr(C)]
 enum EnumAddTraitBoundWhere<T> where T: Sync {
     Variant1(T),
 }
@@ -635,8 +621,8 @@ enum EnumSwapUsageTypeParameters<A, B> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumSwapUsageTypeParameters<A, B> {
@@ -666,8 +652,8 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumSwapUsageLifetimeParameters<'a, 'b> {
@@ -701,8 +687,8 @@ mod change_field_type_indirectly_tuple_style {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as FieldType;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     enum TupleStyle {
@@ -725,8 +711,8 @@ mod change_field_type_indirectly_struct_style {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as FieldType;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     enum StructStyle {
@@ -754,8 +740,8 @@ mod change_trait_bound_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     enum Enum<T: Trait> {
@@ -772,8 +758,8 @@ mod change_trait_bound_indirectly_where {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     enum Enum<T> where T: Trait {
diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs
index 1d26e6c07d1..ec5e088088c 100644
--- a/src/test/incremental/hashes/extern_mods.rs
+++ b/src/test/incremental/hashes/extern_mods.rs
@@ -34,8 +34,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -51,8 +51,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -70,8 +70,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -89,8 +89,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -108,8 +108,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -127,8 +127,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -146,8 +146,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -165,8 +165,8 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern "rust-call" {
@@ -184,8 +184,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -203,8 +203,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 extern {
@@ -222,8 +222,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[link_args = "-foo -bar -baz"]
@@ -241,8 +241,8 @@ extern {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[link(name = "bar")]
@@ -260,8 +260,8 @@ mod indirectly_change_parameter_type {
     #[cfg(not(cfail1))]
     use super::c_i64 as c_int;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     extern {
@@ -280,8 +280,8 @@ mod indirectly_change_return_type {
     #[cfg(not(cfail1))]
     use super::c_i64 as c_int;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     extern {
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index daddc0c9f54..9351a4b05f1 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -34,12 +34,12 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,AssociatedItemDefIds")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn method_name2() { }
 }
@@ -53,15 +53,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn method_body() {
@@ -80,15 +78,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     #[inline]
@@ -105,13 +101,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="AssociatedItems,Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn method_privacy() { }
@@ -124,13 +120,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(cfg="cfail2", except="TypeOfItem,PredicatesOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn method_selfness(&self) { }
@@ -143,13 +139,16 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="Hir,HirBody,FnSignature,TypeckTables,MirOptimized,MirValidated"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn method_selfmutness(&mut self) { }
@@ -164,18 +163,18 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,AssociatedItemDefIds")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_method_to_impl1(&self) { }
 
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_method_to_impl2(&self) { }
 }
@@ -189,13 +188,16 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="Hir,HirBody,FnSignature,TypeckTables,MirOptimized,MirValidated"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_method_parameter(&self, _: i32) { }
@@ -210,15 +212,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_method_parameter_name(&self, b: i64) { }
@@ -233,13 +233,15 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="Hir,HirBody,FnSignature,MirOptimized,MirValidated,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_method_return_type(&self) -> u8 { 0 }
@@ -254,13 +256,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     #[inline]
@@ -276,15 +278,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
@@ -299,13 +299,16 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="Hir,HirBody,FnSignature,TypeckTables,MirOptimized,MirValidated"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub unsafe fn make_method_unsafe(&self) { }
@@ -320,13 +323,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,FnSignature,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub extern fn make_method_extern(&self) { }
@@ -341,13 +344,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,FnSignature,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub extern "system" fn change_method_calling_convention(&self) { }
@@ -362,13 +365,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_parameter_to_method<'a>(&self) { }
@@ -383,13 +386,16 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem,TypeckTables",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_type_parameter_to_method<T>(&self) { }
@@ -404,13 +410,16 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem,TypeckTables"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { }
@@ -425,13 +434,14 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,\
+                                        TypeOfItem,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { }
@@ -446,13 +456,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_trait_bound_to_type_param_of_method<T: Clone>(&self) { }
@@ -467,13 +477,13 @@ impl Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     #[no_mangle]
@@ -491,13 +501,16 @@ impl Bar<u32> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,GenericsOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl<T> Bar<T> {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="GenericsOfItem,FnSignature,TypeckTables,TypeOfItem,MirOptimized,MirValidated"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_type_parameter_to_impl(&self) { }
@@ -512,13 +525,13 @@ impl Bar<u32> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl Bar<u64> {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="FnSignature,MirOptimized,MirValidated,TypeckTables")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn change_impl_self_type(&self) { }
@@ -533,13 +546,13 @@ impl<T> Bar<T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl<T: 'static> Bar<T> {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_bound_to_impl_parameter(&self) { }
@@ -554,13 +567,13 @@ impl<T> Bar<T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 impl<T: Clone> Bar<T> {
-    #[rustc_clean(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_clean(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_trait_bound_to_impl_parameter(&self) { }
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 9e532548e11..d46fbd36760 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -38,6 +38,20 @@ pub fn change_name() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_clean(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_name() {
     let _y = 2u64;
 }
@@ -57,6 +71,20 @@ pub fn add_type() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_clean(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_clean(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn add_type() {
     let _x: u32 = 2u32;
 }
@@ -76,6 +104,20 @@ pub fn change_type() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_type() {
     let _x: u8 = 2;
 }
@@ -95,6 +137,20 @@ pub fn change_mutability_of_reference_type() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_clean(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_mutability_of_reference_type() {
     let _x: &mut u64;
 }
@@ -114,6 +170,20 @@ pub fn change_mutability_of_slot() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_mutability_of_slot() {
     let _x: u64 = 0;
 }
@@ -133,6 +203,20 @@ pub fn change_simple_binding_to_pattern() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_simple_binding_to_pattern() {
     let (_a, _b) = (0u8, 'x');
 }
@@ -152,6 +236,20 @@ pub fn change_name_in_pattern() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_clean(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_name_in_pattern() {
     let (_a, _c) = (1u8, 'y');
 }
@@ -171,6 +269,20 @@ pub fn add_ref_in_pattern() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn add_ref_in_pattern() {
     let (ref _a, _b) = (1u8, 'y');
 }
@@ -190,6 +302,12 @@ pub fn add_amp_in_pattern() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
 pub fn add_amp_in_pattern() {
     let (&_a, _b) = (&1u8, 'y');
 }
@@ -209,6 +327,20 @@ pub fn change_mutability_of_binding_in_pattern() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_mutability_of_binding_in_pattern() {
     let (mut _a, _b) = (99u8, 'q');
 }
@@ -228,6 +360,20 @@ pub fn add_initializer() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_dirty(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn add_initializer() {
     let _x: i16 = 3i16;
 }
@@ -247,6 +393,20 @@ pub fn change_initializer() {
 #[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
+#[rustc_dirty(label="MirValidated", cfg="cfail2")]
+#[rustc_clean(label="MirValidated", cfg="cfail3")]
+#[rustc_dirty(label="MirOptimized", cfg="cfail2")]
+#[rustc_clean(label="MirOptimized", cfg="cfail3")]
+#[rustc_clean(label="TypeckTables", cfg="cfail2")]
+#[rustc_clean(label="TypeckTables", cfg="cfail3")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail2")]
+#[rustc_clean(label="TypeOfItem", cfg="cfail3")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail2")]
+#[rustc_clean(label="GenericsOfItem", cfg="cfail3")]
+#[rustc_clean(label="FnSignature", cfg="cfail2")]
+#[rustc_clean(label="FnSignature", cfg="cfail3")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail2")]
+#[rustc_clean(label="PredicatesOfItem", cfg="cfail3")]
 pub fn change_initializer() {
     let _x = 5u16;
 }
diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs
index 7c6da3ba9fe..4ff80ead89d 100644
--- a/src/test/incremental/hashes/statics.rs
+++ b/src/test/incremental/hashes/statics.rs
@@ -32,8 +32,8 @@
 static STATIC_VISIBILITY: u8 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub static STATIC_VISIBILITY: u8 = 0;
@@ -44,8 +44,8 @@ pub static STATIC_VISIBILITY: u8 = 0;
 static STATIC_MUTABILITY: u8 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static mut STATIC_MUTABILITY: u8 = 0;
@@ -56,8 +56,8 @@ static mut STATIC_MUTABILITY: u8 = 0;
 static STATIC_LINKAGE: u8 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[linkage="weak_odr"]
@@ -69,8 +69,8 @@ static STATIC_LINKAGE: u8 = 0;
 static STATIC_NO_MANGLE: u8 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[no_mangle]
@@ -82,8 +82,8 @@ static STATIC_NO_MANGLE: u8 = 0;
 static STATIC_THREAD_LOCAL: u8 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[thread_local]
@@ -95,8 +95,8 @@ static STATIC_THREAD_LOCAL: u8 = 0;
 static STATIC_CHANGE_TYPE_1: i16 = 0;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_TYPE_1: u64 = 0;
@@ -107,8 +107,8 @@ static STATIC_CHANGE_TYPE_1: u64 = 0;
 static STATIC_CHANGE_TYPE_2: Option<i8> = None;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_TYPE_2: Option<u16> = None;
@@ -119,10 +119,8 @@ static STATIC_CHANGE_TYPE_2: Option<u16> = None;
 static STATIC_CHANGE_VALUE_1: i16 = 1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_1: i16 = 2;
@@ -133,10 +131,8 @@ static STATIC_CHANGE_VALUE_1: i16 = 2;
 static STATIC_CHANGE_VALUE_2: i16 = 1 + 1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
@@ -146,10 +142,8 @@ static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
 static STATIC_CHANGE_VALUE_3: i16 = 2 + 3;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
@@ -159,10 +153,8 @@ static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
 static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
@@ -179,14 +171,14 @@ mod static_change_type_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as Type;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option<Type> = None;
diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs
index 0e23d953baf..231e29b79c4 100644
--- a/src/test/incremental/hashes/struct_constructors.rs
+++ b/src/test/incremental/hashes/struct_constructors.rs
@@ -42,10 +42,8 @@ fn change_field_value_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_field_value_regular_struct() -> RegularStruct {
@@ -69,10 +67,8 @@ fn change_field_order_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_field_order_regular_struct() -> RegularStruct {
@@ -101,10 +97,8 @@ fn add_field_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn add_field_regular_struct() -> RegularStruct {
@@ -140,10 +134,8 @@ fn change_field_label_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_field_label_regular_struct() -> RegularStruct {
@@ -179,10 +171,8 @@ fn change_constructor_path_regular_struct() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_path_regular_struct() {
@@ -202,10 +192,11 @@ mod change_constructor_path_indirectly_regular_struct {
     #[cfg(not(cfail1))]
     use super::RegularStruct2 as Struct;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,TypeckTables"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> Struct {
@@ -228,10 +219,8 @@ fn change_field_value_tuple_struct() -> TupleStruct {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_field_value_tuple_struct() -> TupleStruct {
@@ -249,10 +238,8 @@ fn change_constructor_path_tuple_struct() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_dirty(label="HirBody", cfg="cfail2")]
-#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="HirBody,MirOptimized,MirValidated,TypeckTables")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 fn change_constructor_path_tuple_struct() {
@@ -268,10 +255,11 @@ mod change_constructor_path_indirectly_tuple_struct {
     #[cfg(not(cfail1))]
     use super::TupleStruct2 as Struct;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_dirty(label="HirBody", cfg="cfail2")]
-    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="FnSignature,Hir,HirBody,MirOptimized,MirValidated,TypeckTables"
+    )]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn function() -> Struct {
diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs
index 35fb583cd4e..b0a93eea523 100644
--- a/src/test/incremental/hashes/type_defs.rs
+++ b/src/test/incremental/hashes/type_defs.rs
@@ -35,8 +35,8 @@
 type ChangePrimitiveType = i32;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangePrimitiveType = i64;
 
@@ -47,8 +47,8 @@ type ChangePrimitiveType = i64;
 type ChangeMutability = &'static i32;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangeMutability = &'static mut i32;
 
@@ -59,8 +59,8 @@ type ChangeMutability = &'static mut i32;
 type ChangeLifetime<'a> = (&'static i32, &'a i32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangeLifetime<'a> = (&'a i32, &'a i32);
 
@@ -74,8 +74,8 @@ struct Struct2;
 type ChangeTypeStruct = Struct1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangeTypeStruct = Struct2;
 
@@ -86,8 +86,8 @@ type ChangeTypeStruct = Struct2;
 type ChangeTypeTuple = (u32, u64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangeTypeTuple = (u32, i64);
 
@@ -107,8 +107,8 @@ enum Enum2 {
 type ChangeTypeEnum = Enum1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangeTypeEnum = Enum2;
 
@@ -119,8 +119,8 @@ type ChangeTypeEnum = Enum2;
 type AddTupleField = (i32, i64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddTupleField = (i32, i64, i16);
 
@@ -131,8 +131,8 @@ type AddTupleField = (i32, i64, i16);
 type ChangeNestedTupleField = (i32, (i64, i16));
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type ChangeNestedTupleField = (i32, (i64, i8));
 
@@ -143,8 +143,8 @@ type ChangeNestedTupleField = (i32, (i64, i8));
 type AddTypeParam<T1> = (T1, T1);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddTypeParam<T1, T2> = (T1, T2);
 
@@ -155,8 +155,8 @@ type AddTypeParam<T1, T2> = (T1, T2);
 type AddTypeParamBound<T1> = (T1, u32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddTypeParamBound<T1: Clone> = (T1, u32);
 
@@ -167,8 +167,8 @@ type AddTypeParamBound<T1: Clone> = (T1, u32);
 type AddTypeParamBoundWhereClause<T1> where T1: Clone = (T1, u32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddTypeParamBoundWhereClause<T1> where T1: Clone+Copy = (T1, u32);
 
@@ -179,8 +179,8 @@ type AddTypeParamBoundWhereClause<T1> where T1: Clone+Copy = (T1, u32);
 type AddLifetimeParam<'a> = (&'a u32, &'a u32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32);
 
@@ -191,8 +191,8 @@ type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32);
 type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32);
 
@@ -205,8 +205,8 @@ where 'b: 'a
     = (&'a u32, &'b u32, &'c u32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
-#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+#[rustc_clean(cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 type AddLifetimeParamBoundWhereClause<'a, 'b, 'c>
 where 'b: 'a,
@@ -225,8 +225,8 @@ mod change_trait_bound_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     type ChangeTraitBoundIndirectly<T: Trait> = (T, u32);
@@ -241,8 +241,8 @@ mod change_trait_bound_indirectly_in_where_clause {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
-    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[rustc_clean(cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     type ChangeTraitBoundIndirectly<T> where T : Trait = (T, u32);
diff --git a/src/test/compile-fail/incr_comp_with_macro_export.rs b/src/test/incremental/macro_export.rs
index eafef172303..914632e96ba 100644
--- a/src/test/compile-fail/incr_comp_with_macro_export.rs
+++ b/src/test/incremental/macro_export.rs
@@ -8,10 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Zincremental=tmp/cfail-tests/incr_comp_with_macro_export
+// revisions: cfail1 cfail2 cfail3
 // must-compile-successfully
 
-
 // This test case makes sure that we can compile with incremental compilation
 // enabled when there are macros exported from this crate. (See #37756)
 
diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md
index d999ff97551..b00b35aa29f 100644
--- a/src/test/mir-opt/README.md
+++ b/src/test/mir-opt/README.md
@@ -7,13 +7,13 @@ The test format is:
 // END RUST SOURCE
 // START $file_name_of_some_mir_dump_0
 //  $expected_line_0
-// ...
+// (lines or elision)
 // $expected_line_N
 // END $file_name_of_some_mir_dump_0
-// ...
+// (lines or elision)
 // START $file_name_of_some_mir_dump_N
 //  $expected_line_0
-// ...
+// (lines or elision)
 // $expected_line_N
 // END $file_name_of_some_mir_dump_N
 ```
@@ -22,10 +22,15 @@ All the test information is in comments so the test is runnable.
 
 For each $file_name, compiletest expects [$expected_line_0, ...,
 $expected_line_N] to appear in the dumped MIR in order.  Currently it allows
-other non-matched lines before, after and in-between. Note that this includes
-lines that end basic blocks or begin new ones; it is good practice
-in your tests to include the terminator for each of your basic blocks as an
-internal sanity check guarding against a test like:
+other non-matched lines before and after, but not between $expected_lines,
+should you want to skip lines, you must include an elision comment, of the form
+(as a regex) `//\s*...\s*`. The lines will be skipped lazily, that is, if there
+are two identical lines in the output that match the line after the elision
+comment, the first one wil be matched.
+
+Examples:
+
+The following blocks will not match the one after it.
 
 ```
 bb0: {
@@ -35,8 +40,6 @@ bb0: {
 }
 ```
 
-that will inadvertantly pattern-matching against:
-
 ```
 bb0: {
     StorageLive(_1);
@@ -49,6 +52,18 @@ bb1: {
 }
 ```
 
+But this will match the one above,
+
+```
+bb0: {
+    StorageLive(_1);
+    _1 = const true;
+    ...
+    StorageDead(_1);
+    ...
+}
+```
+
 Lines match ignoring whitespace, and the prefix "//" is removed.
 
 It also currently strips trailing comments -- partly because the full file path
diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs
index 4015930ef76..5c3b418e950 100644
--- a/src/test/mir-opt/box_expr.rs
+++ b/src/test/mir-opt/box_expr.rs
@@ -30,7 +30,10 @@ impl Drop for S {
 // END RUST SOURCE
 // START rustc.node4.ElaborateDrops.before.mir
 //     let mut _0: ();
-//     let _1: std::boxed::Box<S>;
+//     scope 1 {
+//         let _1: std::boxed::Box<S>;
+//     }
+//     ...
 //     let mut _2: std::boxed::Box<S>;
 //     let mut _3: ();
 //     let mut _4: std::boxed::Box<S>;
diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs
index 26b042d0343..0b0d2f45f1c 100644
--- a/src/test/mir-opt/copy_propagation.rs
+++ b/src/test/mir-opt/copy_propagation.rs
@@ -18,17 +18,23 @@ fn main() { }
 // END RUST SOURCE
 // START rustc.node4.CopyPropagation.before.mir
 //  bb0: {
+//      ...
 //      _2 = _1;
+//      ...
 //      _4 = _2;
 //      _3 = _4;
+//      ...
 //      _5 = _3;
 //      _0 = _5;
+//      ...
 //      return;
 //  }
 // END rustc.node4.CopyPropagation.before.mir
 // START rustc.node4.CopyPropagation.after.mir
 //  bb0: {
+//      ...
 //      _0 = _1;
+//      ...
 //      return;
 //  }
 // END rustc.node4.CopyPropagation.after.mir
diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs
index 81dd1932894..ce2b13ecda7 100644
--- a/src/test/mir-opt/deaggregator_test.rs
+++ b/src/test/mir-opt/deaggregator_test.rs
@@ -23,19 +23,25 @@ fn main() {}
 // END RUST SOURCE
 // START rustc.node13.Deaggregator.before.mir
 // bb0: {
+//     ...
 //     _2 = _1;
+//     ...
 //     _3 = _2;
 //     _0 = Baz { x: _3, y: const 0f32, z: const false };
+//     ...
 //     return;
 // }
 // END rustc.node13.Deaggregator.before.mir
 // START rustc.node13.Deaggregator.after.mir
 // bb0: {
+//     ...
 //     _2 = _1;
+//     ...
 //     _3 = _2;
 //     (_0.0: usize) = _3;
 //     (_0.1: f32) = const 0f32;
 //     (_0.2: bool) = const false;
+//     ...
 //     return;
 // }
 // END rustc.node13.Deaggregator.after.mir
diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs
index 25fa0e90835..d77dcb62781 100644
--- a/src/test/mir-opt/deaggregator_test_enum.rs
+++ b/src/test/mir-opt/deaggregator_test_enum.rs
@@ -28,18 +28,26 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node10.Deaggregator.before.mir
 // bb0: {
+//     StorageLive(_2);
 //     _2 = _1;
+//     StorageLive(_3);
 //     _3 = _2;
 //     _0 = Baz::Foo { x: _3 };
+//     StorageDead(_3);
+//     StorageDead(_2);
 //     return;
 // }
 // END rustc.node10.Deaggregator.before.mir
 // START rustc.node10.Deaggregator.after.mir
 // bb0: {
+//     StorageLive(_2);
 //     _2 = _1;
+//     StorageLive(_3);
 //     _3 = _2;
 //     ((_0 as Foo).0: usize) = _3;
 //     discriminant(_0) = 1;
+//     StorageDead(_3);
+//     StorageDead(_2);
 //     return;
 // }
 // END rustc.node10.Deaggregator.after.mir
diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs
index 02d496b2901..e65830bddc4 100644
--- a/src/test/mir-opt/deaggregator_test_enum_2.rs
+++ b/src/test/mir-opt/deaggregator_test_enum_2.rs
@@ -28,29 +28,35 @@ fn main() {}
 // END RUST SOURCE
 // START rustc.node12.Deaggregator.before.mir
 //  bb1: {
+//      StorageLive(_6);
 //      _6 = _4;
 //      _0 = Foo::A(_6,);
+//      StorageDead(_6);
 //      goto -> bb3;
 //  }
-//
 //  bb2: {
+//      StorageLive(_7);
 //      _7 = _4;
 //      _0 = Foo::B(_7,);
+//      StorageDead(_7);
 //      goto -> bb3;
 //  }
 // END rustc.node12.Deaggregator.before.mir
 // START rustc.node12.Deaggregator.after.mir
 //  bb1: {
+//      StorageLive(_6);
 //      _6 = _4;
 //      ((_0 as A).0: i32) = _6;
 //      discriminant(_0) = 0;
+//      StorageDead(_6);
 //      goto -> bb3;
 //  }
-//
 //  bb2: {
+//      StorageLive(_7);
 //      _7 = _4;
 //      ((_0 as B).0: i32) = _7;
 //      discriminant(_0) = 1;
+//      StorageDead(_7);
 //      goto -> bb3;
 //  }
 // END rustc.node12.Deaggregator.after.mir
diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs
index a180a69be55..ed68d3bf5f7 100644
--- a/src/test/mir-opt/deaggregator_test_multiple.rs
+++ b/src/test/mir-opt/deaggregator_test_multiple.rs
@@ -24,25 +24,35 @@ fn main() { }
 // END RUST SOURCE
 // START rustc.node10.Deaggregator.before.mir
 // bb0: {
+//     ...
 //     _2 = _1;
+//     ...
 //     _4 = _2;
 //     _3 = Foo::A(_4,);
+//     ...
 //     _6 = _2;
 //     _5 = Foo::A(_6,);
+//     ...
 //     _0 = [_3, _5];
+//     ...
 //     return;
 // }
 // END rustc.node10.Deaggregator.before.mir
 // START rustc.node10.Deaggregator.after.mir
 // bb0: {
+//     ...
 //     _2 = _1;
+//     ...
 //     _4 = _2;
 //     ((_3 as A).0: i32) = _4;
 //     discriminant(_3) = 0;
+//     ...
 //     _6 = _2;
 //     ((_5 as A).0: i32) = _6;
 //     discriminant(_5) = 0;
+//     ...
 //     _0 = [_3, _5];
+//     ...
 //     return;
 // }
 // END rustc.node10.Deaggregator.after.mir
diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs
index 1941d1bc7be..a0edcc82fe1 100644
--- a/src/test/mir-opt/end_region_1.rs
+++ b/src/test/mir-opt/end_region_1.rs
@@ -21,9 +21,11 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
+//     ...
 //     let _1: i32;
+//     ...
 //     let _2: &'10_1rs i32;
-//
+//     ...
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = const 3i32;
diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs
index d8dd4aeadf4..69042fecc7d 100644
--- a/src/test/mir-opt/end_region_2.rs
+++ b/src/test/mir-opt/end_region_2.rs
@@ -26,11 +26,16 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
+//     ...
 //     let _2: bool;
+//     ...
 //     let _3: &'23_1rs bool;
+//     ...
 //     let _7: &'23_3rs bool;
+//     ...
 //     let mut _4: ();
 //     let mut _5: bool;
+//     ...
 //     bb0: {
 //         goto -> bb1;
 //     }
@@ -52,6 +57,7 @@ fn main() {
 //         return;
 //     }
 //     bb3: {
+//         _4 = ();
 //         StorageDead(_5);
 //         StorageLive(_7);
 //         _7 = &'23_3rs _2;
diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs
index e404af838ce..da423163e84 100644
--- a/src/test/mir-opt/end_region_3.rs
+++ b/src/test/mir-opt/end_region_3.rs
@@ -27,13 +27,17 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
+//     ...
 //     let mut _1: bool;
+//     ...
 //     let _3: &'26_1rs bool;
+//     ...
 //     let _7: &'26_3rs bool;
+//     ...
 //     let mut _2: ();
 //     let mut _4: ();
 //     let mut _5: bool;
-//
+//     let mut _6: !;
 //     bb0: {
 //         StorageLive(_1);
 //         goto -> bb1;
diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs
index d51c627d14b..2087485b913 100644
--- a/src/test/mir-opt/end_region_4.rs
+++ b/src/test/mir-opt/end_region_4.rs
@@ -31,10 +31,15 @@ fn foo(i: i32) {
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
+//     ...
 //     let _1: D;
+//     ...
 //     let _2: i32;
+//     ...
 //     let _3: &'26_2rs i32;
+//     ...
 //     let _6: &'26_4rs i32;
+//     ...
 //     let mut _4: ();
 //     let mut _5: i32;
 //     bb0: {
diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs
index 6299ec3815c..4663b71bd7c 100644
--- a/src/test/mir-opt/end_region_5.rs
+++ b/src/test/mir-opt/end_region_5.rs
@@ -28,8 +28,11 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END RUST SOURCE
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 // fn main() -> () {
+//     ...
 //     let mut _0: ();
+//     ...
 //     let _1: D;
+//     ...
 //     let mut _2: ();
 //     let mut _3: [closure@NodeId(18) d:&'14s D];
 //     let mut _4: &'14s D;
diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs
index 13ab3e4f2dd..7d2868ee4ba 100644
--- a/src/test/mir-opt/end_region_6.rs
+++ b/src/test/mir-opt/end_region_6.rs
@@ -29,7 +29,9 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 // fn main() -> () {
 //     let mut _0: ();
+//     ...
 //     let _1: D;
+//     ...
 //     let mut _2: ();
 //     let mut _3: [closure@NodeId(22) d:&'19s D];
 //     let mut _4: &'19s D;
@@ -65,9 +67,10 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // START rustc.node22.SimplifyCfg-qualify-consts.after.mir
 // fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 {
 //     let mut _0: i32;
+//     ...
 //     let _2: &'15_0rs D;
+//     ...
 //     let mut _3: i32;
-//
 //     bb0: {
 //         StorageLive(_2);
 //         _2 = &'15_0rs (*(_1.0: &'19s D));
diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs
index 826d3749167..0156c1be7ed 100644
--- a/src/test/mir-opt/end_region_7.rs
+++ b/src/test/mir-opt/end_region_7.rs
@@ -29,11 +29,12 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 // fn main() -> () {
 //     let mut _0: ();
+//     ...
 //     let _1: D;
+//     ...
 //     let mut _2: ();
 //     let mut _3: [closure@NodeId(22) d:D];
 //     let mut _4: D;
-//
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
@@ -74,9 +75,10 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // START rustc.node22.SimplifyCfg-qualify-consts.after.mir
 // fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 {
 //     let mut _0: i32;
+//     ...
 //     let _2: &'15_0rs D;
+//     ...
 //     let mut _3: i32;
-//
 //     bb0: {
 //         StorageLive(_2);
 //         _2 = &'15_0rs (_1.0: D);
diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs
index 6438484fcfa..6e8cf4204ee 100644
--- a/src/test/mir-opt/end_region_8.rs
+++ b/src/test/mir-opt/end_region_8.rs
@@ -30,8 +30,11 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 // fn main() -> () {
 //    let mut _0: ();
+//    ...
 //    let _1: D;
+//    ...
 //    let _2: &'21_1rs D;
+//    ...
 //    let mut _3: ();
 //    let mut _4: [closure@NodeId(22) r:&'21_1rs D];
 //    let mut _5: &'21_1rs D;
diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs
index 59d5d934391..fd23d813452 100644
--- a/src/test/mir-opt/end_region_9.rs
+++ b/src/test/mir-opt/end_region_9.rs
@@ -40,15 +40,18 @@ fn main() {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 // fn main() -> () {
 //     let mut _0: ();
+//     ...
 //     let mut _1: bool;
+//     ...
 //     let _2: i32;
+//     ...
 //     let mut _4: &'33_0rs i32;
+//     ...
 //     let mut _3: ();
 //     let mut _5: !;
 //     let mut _6: ();
 //     let mut _7: bool;
 //     let mut _8: !;
-//
 //     bb0: {
 //        StorageLive(_1);
 //        _1 = const false;
@@ -63,7 +66,6 @@ fn main() {
 //        _7 = _1;
 //        switchInt(_7) -> [0u8: bb3, otherwise: bb2];
 //    }
-//
 //    bb2: {
 //        _0 = ();
 //        StorageDead(_7);
@@ -73,7 +75,6 @@ fn main() {
 //        StorageDead(_1);
 //        return;
 //    }
-//
 //    bb3: {
 //        _4 = &'33_0rs _2;
 //        _6 = ();
diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs
index 8f9dd79cd75..f70f6519275 100644
--- a/src/test/mir-opt/end_region_cyclic.rs
+++ b/src/test/mir-opt/end_region_cyclic.rs
@@ -45,6 +45,7 @@ fn query() -> bool { true }
 //     scope 1 {
 //         let _2: S<'35_0rs>;
 //     }
+//     ...
 //     let mut _1: ();
 //     let mut _3: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>;
 //     let mut _4: std::option::Option<&'35_0rs S<'35_0rs>>;
diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs
index 3a8b5c449c2..384201b7c12 100644
--- a/src/test/mir-opt/issue-41110.rs
+++ b/src/test/mir-opt/issue-41110.rs
@@ -35,22 +35,26 @@ impl S {
 // END RUST SOURCE
 // START rustc.node4.ElaborateDrops.after.mir
 //    let mut _0: ();
-//    let _1: ();
+//    scope 1 {
+//        let _1: ();
+//    }
+//    ...
 //    let mut _2: S;
 //    let mut _3: S;
 //    let mut _4: S;
 //    let mut _5: bool;
-//
 //    bb0: {
 // END rustc.node4.ElaborateDrops.after.mir
 // START rustc.node13.ElaborateDrops.after.mir
 //    let mut _0: ();
+//    ...
 //    let _1: S;
+//    ...
 //    let mut _2: S;
+//    ...
 //    let mut _3: ();
 //    let mut _4: S;
 //    let mut _5: S;
 //    let mut _6: bool;
-//
 //    bb0: {
 // END rustc.node13.ElaborateDrops.after.mir
diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs
index 9fb725a980e..370ab599eca 100644
--- a/src/test/mir-opt/storage_live_dead_in_statics.rs
+++ b/src/test/mir-opt/storage_live_dead_in_statics.rs
@@ -45,56 +45,156 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.node4.mir_map.0.mir
+//    let mut _0: &'static Foo;
+//    let mut _1: &'static Foo;
+//    let mut _2: Foo;
+//    let mut _3: &'static [(u32, u32)];
+//    let mut _4: &'static [(u32, u32); 42];
+//    let mut _5: &'static [(u32, u32); 42];
+//    let mut _6: [(u32, u32); 42];
+//    let mut _7: (u32, u32);
+//    let mut _8: (u32, u32);
+//    let mut _9: (u32, u32);
+//    let mut _10: (u32, u32);
+//    let mut _11: (u32, u32);
+//    let mut _12: (u32, u32);
+//    let mut _13: (u32, u32);
+//    let mut _14: (u32, u32);
+//    let mut _15: (u32, u32);
+//    let mut _16: (u32, u32);
+//    let mut _17: (u32, u32);
+//    let mut _18: (u32, u32);
+//    let mut _19: (u32, u32);
+//    let mut _20: (u32, u32);
+//    let mut _21: (u32, u32);
+//    let mut _22: (u32, u32);
+//    let mut _23: (u32, u32);
+//    let mut _24: (u32, u32);
+//    let mut _25: (u32, u32);
+//    let mut _26: (u32, u32);
+//    let mut _27: (u32, u32);
+//    let mut _28: (u32, u32);
+//    let mut _29: (u32, u32);
+//    let mut _30: (u32, u32);
+//    let mut _31: (u32, u32);
+//    let mut _32: (u32, u32);
+//    let mut _33: (u32, u32);
+//    let mut _34: (u32, u32);
+//    let mut _35: (u32, u32);
+//    let mut _36: (u32, u32);
+//    let mut _37: (u32, u32);
+//    let mut _38: (u32, u32);
+//    let mut _39: (u32, u32);
+//    let mut _40: (u32, u32);
+//    let mut _41: (u32, u32);
+//    let mut _42: (u32, u32);
+//    let mut _43: (u32, u32);
+//    let mut _44: (u32, u32);
+//    let mut _45: (u32, u32);
+//    let mut _46: (u32, u32);
+//    let mut _47: (u32, u32);
+//    let mut _48: (u32, u32);
 //    bb0: {
-//        _7 = (const 0u32, const 1u32);   // scope 0 at src/test/mir-opt/basic_assignment.rs:29:9: 29:15
-//        _8 = (const 0u32, const 2u32);   // scope 0 at src/test/mir-opt/basic_assignment.rs:29:17: 29:23
-//        _9 = (const 0u32, const 3u32);   // scope 0 at src/test/mir-opt/basic_assignment.rs:29:25: 29:31
-//        _10 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:30:9: 30:15
-//        _11 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:30:17: 30:23
-//        _12 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:30:25: 30:31
-//        _13 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:31:9: 31:15
-//        _14 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:31:17: 31:23
-//        _15 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:31:25: 31:31
-//        _16 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:32:9: 32:15
-//        _17 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:32:17: 32:23
-//        _18 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:32:25: 32:31
-//        _19 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:33:9: 33:15
-//        _20 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:33:17: 33:23
-//        _21 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:33:25: 33:31
-//        _22 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:34:9: 34:15
-//        _23 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:34:17: 34:23
-//        _24 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:34:25: 34:31
-//        _25 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:35:9: 35:15
-//        _26 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:35:17: 35:23
-//        _27 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:35:25: 35:31
-//        _28 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:36:9: 36:15
-//        _29 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:36:17: 36:23
-//        _30 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:36:25: 36:31
-//        _31 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:37:9: 37:15
-//        _32 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:37:17: 37:23
-//        _33 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:37:25: 37:31
-//        _34 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:38:9: 38:15
-//        _35 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:38:17: 38:23
-//        _36 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:38:25: 38:31
-//        _37 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:39:9: 39:15
-//        _38 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:39:17: 39:23
-//        _39 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:39:25: 39:31
-//        _40 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:40:9: 40:15
-//        _41 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:40:17: 40:23
-//        _42 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:40:25: 40:31
-//        _43 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:41:9: 41:15
-//        _44 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:41:17: 41:23
-//        _45 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:41:25: 41:31
-//        _46 = (const 0u32, const 1u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:42:9: 42:15
-//        _47 = (const 0u32, const 2u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:42:17: 42:23
-//        _48 = (const 0u32, const 3u32);  // scope 0 at src/test/mir-opt/basic_assignment.rs:42:25: 42:31
-//        _6 = [_7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48]; // scope 0 at src/test/mir-opt/basic_assignment.rs:28:12: 43:6
-//        _5 = &_6;                        // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6
-//        _4 = &(*_5);                     // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6
-//        _3 = _4 as &'static [(u32, u32)] (Unsize); // scope 0 at src/test/mir-opt/basic_assignment.rs:28:11: 43:6
-//        _2 = Foo { tup: const "hi", data: _3 }; // scope 0 at src/test/mir-opt/basic_assignment.rs:26:29: 44:2
-//        _1 = &_2;                        // scope 0 at src/test/mir-opt/basic_assignment.rs:26:28: 44:2
-//        _0 = &(*_1);                     // scope 0 at src/test/mir-opt/basic_assignment.rs:26:28: 44:2
-//        return;                          // scope 0 at src/test/mir-opt/basic_assignment.rs:26:1: 44:3
+//        StorageLive(_1);
+//        StorageLive(_2);
+//        StorageLive(_3);
+//        StorageLive(_4);
+//        StorageLive(_5);
+//        StorageLive(_6);
+//        StorageLive(_7);
+//        _7 = (const 0u32, const 1u32);
+//        StorageLive(_8);
+//        _8 = (const 0u32, const 2u32);
+//        StorageLive(_9);
+//        _9 = (const 0u32, const 3u32);
+//        StorageLive(_10);
+//        _10 = (const 0u32, const 1u32);
+//        StorageLive(_11);
+//        _11 = (const 0u32, const 2u32);
+//        StorageLive(_12);
+//        _12 = (const 0u32, const 3u32);
+//        StorageLive(_13);
+//        _13 = (const 0u32, const 1u32);
+//        StorageLive(_14);
+//        _14 = (const 0u32, const 2u32);
+//        StorageLive(_15);
+//        _15 = (const 0u32, const 3u32);
+//        StorageLive(_16);
+//        _16 = (const 0u32, const 1u32);
+//        StorageLive(_17);
+//        _17 = (const 0u32, const 2u32);
+//        StorageLive(_18);
+//        _18 = (const 0u32, const 3u32);
+//        StorageLive(_19);
+//        _19 = (const 0u32, const 1u32);
+//        StorageLive(_20);
+//        _20 = (const 0u32, const 2u32);
+//        StorageLive(_21);
+//        _21 = (const 0u32, const 3u32);
+//        StorageLive(_22);
+//        _22 = (const 0u32, const 1u32);
+//        StorageLive(_23);
+//        _23 = (const 0u32, const 2u32);
+//        StorageLive(_24);
+//        _24 = (const 0u32, const 3u32);
+//        StorageLive(_25);
+//        _25 = (const 0u32, const 1u32);
+//        StorageLive(_26);
+//        _26 = (const 0u32, const 2u32);
+//        StorageLive(_27);
+//        _27 = (const 0u32, const 3u32);
+//        StorageLive(_28);
+//        _28 = (const 0u32, const 1u32);
+//        StorageLive(_29);
+//        _29 = (const 0u32, const 2u32);
+//        StorageLive(_30);
+//        _30 = (const 0u32, const 3u32);
+//        StorageLive(_31);
+//        _31 = (const 0u32, const 1u32);
+//        StorageLive(_32);
+//        _32 = (const 0u32, const 2u32);
+//        StorageLive(_33);
+//        _33 = (const 0u32, const 3u32);
+//        StorageLive(_34);
+//        _34 = (const 0u32, const 1u32);
+//        StorageLive(_35);
+//        _35 = (const 0u32, const 2u32);
+//        StorageLive(_36);
+//        _36 = (const 0u32, const 3u32);
+//        StorageLive(_37);
+//        _37 = (const 0u32, const 1u32);
+//        StorageLive(_38);
+//        _38 = (const 0u32, const 2u32);
+//        StorageLive(_39);
+//        _39 = (const 0u32, const 3u32);
+//        StorageLive(_40);
+//        _40 = (const 0u32, const 1u32);
+//        StorageLive(_41);
+//        _41 = (const 0u32, const 2u32);
+//        StorageLive(_42);
+//        _42 = (const 0u32, const 3u32);
+//        StorageLive(_43);
+//        _43 = (const 0u32, const 1u32);
+//        StorageLive(_44);
+//        _44 = (const 0u32, const 2u32);
+//        StorageLive(_45);
+//        _45 = (const 0u32, const 3u32);
+//        StorageLive(_46);
+//        _46 = (const 0u32, const 1u32);
+//        StorageLive(_47);
+//        _47 = (const 0u32, const 2u32);
+//        StorageLive(_48);
+//        _48 = (const 0u32, const 3u32);
+//        _6 = [_7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48];
+//        _5 = &_6;
+//        _4 = &(*_5);
+//        _3 = _4 as &'static [(u32, u32)] (Unsize);
+//        _2 = Foo { tup: const "hi", data: _3 };
+//        _1 = &_2;
+//        _0 = &(*_1);
+//        StorageDead(_1);
+//        StorageDead(_5);
+//        return;
 //    }
+//}
 // END rustc.node4.mir_map.0.mir
diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs
index 3fbd1a36f2f..7dbcf82af34 100644
--- a/src/test/mir-opt/storage_ranges.rs
+++ b/src/test/mir-opt/storage_ranges.rs
@@ -38,5 +38,6 @@ fn main() {
 //         _0 = ();
 //         StorageDead(_6);
 //         StorageDead(_1);
+//         return;
 //      }
 // END rustc.node4.TypeckMir.before.mir
diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs
index ec044225b83..22788d7a898 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -30,13 +30,16 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node12.EraseRegions.after.mir
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[e36f]::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[e36f]::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
+//         ...
 //         return;
 //     }
 // END rustc.node12.EraseRegions.after.mir
 // START rustc.node23.EraseRegions.after.mir
 // fn main() -> () {
+//     ...
 //     bb0: {
+//         ...
 //         Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [_1: i32]);
 //         _6 = &ReErased mut _1;
 //         Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(10)))]);
@@ -50,14 +53,16 @@ fn main() {
 //     bb1: {
 //         Validate(Acquire, [_2: ()]);
 //         EndRegion(ReScope(Node(ItemLocalId(10))));
+//         ...
 //         return;
 //     }
 // }
 // END rustc.node23.EraseRegions.after.mir
 // START rustc.node50.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
+//     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:11) => validate_1/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:11) => validate_1/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs
index 37ebd720d52..aacf5a5ed0f 100644
--- a/src/test/mir-opt/validate_2.rs
+++ b/src/test/mir-opt/validate_2.rs
@@ -18,10 +18,18 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.EraseRegions.after.mir
 // fn main() -> () {
+//     ...
 //     bb1: {
+//         Validate(Acquire, [_2: std::boxed::Box<[i32; 3]>]);
 //         Validate(Release, [_2: std::boxed::Box<[i32; 3]>]);
 //         _1 = _2 as std::boxed::Box<[i32]> (Unsize);
 //         Validate(Acquire, [_1: std::boxed::Box<[i32]>]);
+//         StorageDead(_2);
+//         StorageDead(_3);
+//         _0 = ();
+//         Validate(Release, [_1: std::boxed::Box<[i32]>]);
+//         drop(_1) -> bb2;
 //     }
+//     ...
 // }
 // END rustc.node4.EraseRegions.after.mir
diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs
index 116e35b2d6f..d7d3e023c9e 100644
--- a/src/test/mir-opt/validate_3.rs
+++ b/src/test/mir-opt/validate_3.rs
@@ -30,8 +30,17 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node16.EraseRegions.after.mir
 // fn main() -> () {
+//     ...
 //     let mut _5: &ReErased i32;
 //     bb0: {
+//         StorageLive(_1);
+//         _1 = Test { x: const 0i32 };
+//         StorageLive(_2);
+//         Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))), [_1: Test]);
+//         _2 = &ReErased _1;
+//         Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]);
+//         StorageLive(_4);
+//         StorageLive(_5);
 //         Validate(Suspend(ReScope(Node(ItemLocalId(17)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]);
 //         _5 = &ReErased ((*_2).0: i32);
 //         Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(17))) (imm)]);
@@ -42,8 +51,14 @@ fn main() {
 //         _3 = const foo(_4) -> bb1;
 //     }
 //     bb1: {
+//         Validate(Acquire, [_3: ()]);
 //         EndRegion(ReScope(Node(ItemLocalId(17))));
+//         StorageDead(_4);
+//         StorageDead(_5);
+//         _0 = ();
 //         EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })));
+//         StorageDead(_2);
+//         StorageDead(_1);
 //         return;
 //     }
 // }
diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs
index 571ed425402..d2852cf5226 100644
--- a/src/test/mir-opt/validate_4.rs
+++ b/src/test/mir-opt/validate_4.rs
@@ -38,18 +38,21 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node4.EraseRegions.after.mir
 // fn write_42(_1: *mut i32) -> bool {
+//     ...
 //     bb0: {
 //         Validate(Acquire, [_1: *mut i32]);
 //         Validate(Release, [_1: *mut i32]);
+//         ...
 //         return;
 //     }
 // }
 // END rustc.node4.EraseRegions.after.mir
 // START rustc.node22.EraseRegions.after.mir
 // fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
+//     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[e36f]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[e36f]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         (*_3) = const 23i32;
@@ -60,24 +63,30 @@ fn main() {
 // END rustc.node22.EraseRegions.after.mir
 // START rustc.node31.EraseRegions.after.mir
 // fn test(_1: &ReErased mut i32) -> () {
+//     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[e36f]::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[e36f]::test[0] }, BrAnon(0)) mut i32]);
+//         ...
 //         _3 = const write_42(_4) -> bb1;
 //     }
 //     bb1: {
 //         Validate(Acquire, [_3: bool]);
 //         Validate(Release, [_3: bool]);
+//         ...
 //     }
 // }
 // END rustc.node31.EraseRegions.after.mir
 // START rustc.node60.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
+//     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:10) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
+//         ...
 //         _0 = const write_42(_4) -> bb1;
 //     }
+//     ...
 // }
 // END rustc.node60.EraseRegions.after.mir
diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs
index ff0c781d1e3..98c553d6b35 100644
--- a/src/test/mir-opt/validate_5.rs
+++ b/src/test/mir-opt/validate_5.rs
@@ -35,17 +35,21 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node17.EraseRegions.after.mir
 // fn test(_1: &ReErased mut i32) -> () {
+//     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_5/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_5[e36f]::test[0] }, BrAnon(0)) mut i32]);
+//         ...
 //         Validate(Release, [_3: bool, _4: *mut i32]);
 //         _3 = const write_42(_4) -> bb1;
 //     }
+//     ...
 // }
 // END rustc.node17.EraseRegions.after.mir
 // START rustc.node46.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
+//     ...
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_5/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:9) => validate_5/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
@@ -59,5 +63,6 @@ fn main() {
 //         Validate(Release, [_0: bool, _4: *mut i32]);
 //         _0 = const write_42(_4) -> bb1;
 //     }
+//     ...
 // }
 // END rustc.node46.EraseRegions.after.mir
diff --git a/src/test/parse-fail/issue-20711-2.rs b/src/test/parse-fail/issue-20711-2.rs
index a489864e3f7..3a330d8bee2 100644
--- a/src/test/parse-fail/issue-20711-2.rs
+++ b/src/test/parse-fail/issue-20711-2.rs
@@ -16,6 +16,6 @@ impl Foo {
     fn foo() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
+} //~ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
 
 fn main() {}
diff --git a/src/test/parse-fail/issue-20711.rs b/src/test/parse-fail/issue-20711.rs
index d9789d55a6f..cd79fa8be7c 100644
--- a/src/test/parse-fail/issue-20711.rs
+++ b/src/test/parse-fail/issue-20711.rs
@@ -14,6 +14,6 @@ struct Foo;
 
 impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
+} //~ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
 
 fn main() {}
diff --git a/src/test/parse-fail/removed-syntax-static-fn.rs b/src/test/parse-fail/removed-syntax-static-fn.rs
index b4c25a75c90..3b783aa79e2 100644
--- a/src/test/parse-fail/removed-syntax-static-fn.rs
+++ b/src/test/parse-fail/removed-syntax-static-fn.rs
@@ -15,4 +15,4 @@ struct S;
 impl S {
     static fn f() {}
 }
-//~^^ ERROR expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`
+//~^^ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`
diff --git a/src/test/parse-fail/require-parens-for-chained-comparison.rs b/src/test/parse-fail/require-parens-for-chained-comparison.rs
index 7e76dbd31f0..1ee6996ce9c 100644
--- a/src/test/parse-fail/require-parens-for-chained-comparison.rs
+++ b/src/test/parse-fail/require-parens-for-chained-comparison.rs
@@ -21,5 +21,6 @@ fn main() {
 
     f<X>();
     //~^ ERROR: chained comparison operators require parentheses
-    //~^^ HELP: use `::<...>` instead of `<...>`
+    //~| HELP: use `::<...>` instead of `<...>`
+    //~| HELP: or use `(...)`
 }
diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs
index a44c0c3f32f..3e8c140eb19 100644
--- a/src/test/parse-fail/trait-object-bad-parens.rs
+++ b/src/test/parse-fail/trait-object-bad-parens.rs
@@ -17,4 +17,6 @@ fn main() {
     //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)`
     let _: Box<(Copy +) + Copy>;
     //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)`
+    let _: Box<(dyn Copy) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn  Copy)`
 }
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 14a499644df..02b8425d88b 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -40,31 +40,31 @@ pub fn bar() ({
 
 
                   ((::fmt::format as
-                       fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1
-                                                                                                   as
-                                                                                                   fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test"
-                                                                                                                                                                                                                  as
-                                                                                                                                                                                                                  &'static str)]
-                                                                                                                                                                                                                as
-                                                                                                                                                                                                                [&str; 1])
-                                                                                                                                                                                                              as
-                                                                                                                                                                                                              &[&str; 1]),
-                                                                                                                                                                                                          (&(match (()
-                                                                                                                                                                                                                       as
-                                                                                                                                                                                                                       ())
-                                                                                                                                                                                                                 {
-                                                                                                                                                                                                                 ()
-                                                                                                                                                                                                                 =>
-                                                                                                                                                                                                                 ([]
-                                                                                                                                                                                                                     as
-                                                                                                                                                                                                                     [std::fmt::ArgumentV1<'_>; 0]),
-                                                                                                                                                                                                             }
-                                                                                                                                                                                                                as
-                                                                                                                                                                                                                [std::fmt::ArgumentV1<'_>; 0])
-                                                                                                                                                                                                              as
-                                                                                                                                                                                                              &[std::fmt::ArgumentV1<'_>; 0]))
-                                                                                                  as
-                                                                                                  std::fmt::Arguments<'_>))
+                       for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1
+                                                                                                           as
+                                                                                                           fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test"
+                                                                                                                                                                                                                          as
+                                                                                                                                                                                                                          &'static str)]
+                                                                                                                                                                                                                        as
+                                                                                                                                                                                                                        [&str; 1])
+                                                                                                                                                                                                                      as
+                                                                                                                                                                                                                      &[&str; 1]),
+                                                                                                                                                                                                                  (&(match (()
+                                                                                                                                                                                                                               as
+                                                                                                                                                                                                                               ())
+                                                                                                                                                                                                                         {
+                                                                                                                                                                                                                         ()
+                                                                                                                                                                                                                         =>
+                                                                                                                                                                                                                         ([]
+                                                                                                                                                                                                                             as
+                                                                                                                                                                                                                             [std::fmt::ArgumentV1<'_>; 0]),
+                                                                                                                                                                                                                     }
+                                                                                                                                                                                                                        as
+                                                                                                                                                                                                                        [std::fmt::ArgumentV1<'_>; 0])
+                                                                                                                                                                                                                      as
+                                                                                                                                                                                                                      &[std::fmt::ArgumentV1<'_>; 0]))
+                                                                                                          as
+                                                                                                          std::fmt::Arguments<'_>))
                       as std::string::String);
               } as ())
 pub type Foo = [i32; (3 as usize)];
diff --git a/src/test/run-fail/mir_drop_panics.rs b/src/test/run-fail/mir_drop_panics.rs
index 98311525ad0..51191dd7087 100644
--- a/src/test/run-fail/mir_drop_panics.rs
+++ b/src/test/run-fail/mir_drop_panics.rs
@@ -10,7 +10,6 @@
 
 // error-pattern:panic 1
 // error-pattern:drop 2
-use std::io::{self, Write};
 
 struct Droppable(u32);
 impl Drop for Droppable {
@@ -18,7 +17,7 @@ impl Drop for Droppable {
         if self.0 == 1 {
             panic!("panic 1");
         } else {
-            write!(io::stderr(), "drop {}", self.0);
+            eprint!("drop {}", self.0);
         }
     }
 }
diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs
index 6cf2851d93d..69f934272b7 100644
--- a/src/test/run-fail/mir_dynamic_drops_1.rs
+++ b/src/test/run-fail/mir_dynamic_drops_1.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 // error-pattern:drop 1
 // error-pattern:drop 2
-use std::io::{self, Write};
 
 
 /// Structure which will not allow to be dropped twice.
@@ -17,10 +16,10 @@ struct Droppable<'a>(&'a mut bool, u32);
 impl<'a> Drop for Droppable<'a> {
     fn drop(&mut self) {
         if *self.0 {
-            writeln!(io::stderr(), "{} dropped twice", self.1);
+            eprintln!("{} dropped twice", self.1);
             ::std::process::exit(1);
         }
-        writeln!(io::stderr(), "drop {}", self.1);
+        eprintln!("drop {}", self.1);
         *self.0 = true;
     }
 }
diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs
index 7a90298e422..d2fe50401ab 100644
--- a/src/test/run-fail/mir_dynamic_drops_2.rs
+++ b/src/test/run-fail/mir_dynamic_drops_2.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 // error-pattern:drop 1
-use std::io::{self, Write};
 
 
 /// Structure which will not allow to be dropped twice.
@@ -17,10 +16,10 @@ struct Droppable<'a>(&'a mut bool, u32);
 impl<'a> Drop for Droppable<'a> {
     fn drop(&mut self) {
         if *self.0 {
-            writeln!(io::stderr(), "{} dropped twice", self.1);
+            eprintln!("{} dropped twice", self.1);
             ::std::process::exit(1);
         }
-        writeln!(io::stderr(), "drop {}", self.1);
+        eprintln!("drop {}", self.1);
         *self.0 = true;
     }
 }
diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs
index 79ecbbb35bc..ecc35ee9b24 100644
--- a/src/test/run-fail/mir_dynamic_drops_3.rs
+++ b/src/test/run-fail/mir_dynamic_drops_3.rs
@@ -12,7 +12,6 @@
 // error-pattern:drop 3
 // error-pattern:drop 2
 // error-pattern:drop 1
-use std::io::{self, Write};
 
 
 /// Structure which will not allow to be dropped twice.
@@ -20,10 +19,10 @@ struct Droppable<'a>(&'a mut bool, u32);
 impl<'a> Drop for Droppable<'a> {
     fn drop(&mut self) {
         if *self.0 {
-            writeln!(io::stderr(), "{} dropped twice", self.1);
+            eprintln!("{} dropped twice", self.1);
             ::std::process::exit(1);
         }
-        writeln!(io::stderr(), "drop {}", self.1);
+        eprintln!("drop {}", self.1);
         *self.0 = true;
     }
 }
diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs
index 7a7526c5fc1..9c851eb7346 100644
--- a/src/test/run-fail/mir_trans_calls_converging_drops.rs
+++ b/src/test/run-fail/mir_trans_calls_converging_drops.rs
@@ -12,17 +12,15 @@
 // error-pattern:0 dropped
 // error-pattern:exit
 
-use std::io::{self, Write};
-
 struct Droppable(u8);
 impl Drop for Droppable {
     fn drop(&mut self) {
-        write!(io::stderr(), "{} dropped\n", self.0);
+        eprintln!("{} dropped", self.0);
     }
 }
 
 fn converging_fn() {
-    write!(io::stderr(), "converging_fn called\n");
+    eprintln!("converging_fn called");
 }
 
 fn mir(d: Droppable) {
diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs
index 1301630cc85..6f105211556 100644
--- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs
+++ b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs
@@ -12,18 +12,16 @@
 // error-pattern:dropped
 // error-pattern:exit
 
-use std::io::{self, Write};
-
 struct Droppable;
 impl Drop for Droppable {
     fn drop(&mut self) {
-        write!(io::stderr(), "dropped\n");
+        eprintln!("dropped");
     }
 }
 
 // return value of this function is copied into the return slot
 fn complex() -> u64 {
-    write!(io::stderr(), "complex called\n");
+    eprintln!("complex called");
     42
 }
 
diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs
index c1918704929..f8fbe8f79cc 100644
--- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs
+++ b/src/test/run-fail/mir_trans_calls_diverging_drops.rs
@@ -11,12 +11,10 @@
 // error-pattern:diverging_fn called
 // error-pattern:0 dropped
 
-use std::io::{self, Write};
-
 struct Droppable(u8);
 impl Drop for Droppable {
     fn drop(&mut self) {
-        write!(io::stderr(), "{} dropped", self.0);
+        eprintln!("{} dropped", self.0);
     }
 }
 
diff --git a/src/test/run-fail/panic-set-handler.rs b/src/test/run-fail/panic-set-handler.rs
index b589544ae15..68f1c4ed0bc 100644
--- a/src/test/run-fail/panic-set-handler.rs
+++ b/src/test/run-fail/panic-set-handler.rs
@@ -13,11 +13,10 @@
 #![feature(panic_handler)]
 
 use std::panic;
-use std::io::{self, Write};
 
 fn main() {
     panic::set_hook(Box::new(|i| {
-        write!(io::stderr(), "greetings from the panic handler");
+        eprint!("greetings from the panic handler");
     }));
     panic!("foobar");
 }
diff --git a/src/test/run-fail/panic-set-unset-handler.rs b/src/test/run-fail/panic-set-unset-handler.rs
index 6741c2d9c2c..072139a8c9b 100644
--- a/src/test/run-fail/panic-set-unset-handler.rs
+++ b/src/test/run-fail/panic-set-unset-handler.rs
@@ -13,11 +13,10 @@
 #![feature(panic_handler)]
 
 use std::panic;
-use std::io::{self, Write};
 
 fn main() {
     panic::set_hook(Box::new(|i| {
-        write!(io::stderr(), "greetings from the panic handler");
+        eprint!("greetings from the panic handler");
     }));
     panic::take_hook();
     panic!("foobar");
diff --git a/src/test/run-make/archive-duplicate-names/Makefile b/src/test/run-make/archive-duplicate-names/Makefile
index 5202e6dea54..93711c41d79 100644
--- a/src/test/run-make/archive-duplicate-names/Makefile
+++ b/src/test/run-make/archive-duplicate-names/Makefile
@@ -5,7 +5,7 @@ all:
 	mkdir $(TMPDIR)/b
 	$(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c)
 	$(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c)
-	ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o
+	$(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o
 	$(RUSTC) foo.rs
 	$(RUSTC) bar.rs
 	$(call RUN,bar)
diff --git a/src/test/run-make/compiler-rt-works-on-mingw/Makefile b/src/test/run-make/compiler-rt-works-on-mingw/Makefile
index 4ec54f73e67..06d1bb6698e 100644
--- a/src/test/run-make/compiler-rt-works-on-mingw/Makefile
+++ b/src/test/run-make/compiler-rt-works-on-mingw/Makefile
@@ -3,8 +3,8 @@
 ifneq (,$(findstring MINGW,$(UNAME)))
 ifndef IS_MSVC
 all:
-	g++ foo.cpp -c -o $(TMPDIR)/foo.o
-	ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o
+	$(CXX) foo.cpp -c -o $(TMPDIR)/foo.o
+	$(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o
 	$(RUSTC) foo.rs -lfoo -lstdc++
 	$(call RUN,foo)
 else
diff --git a/src/test/run-make/extra-filename-with-temp-outputs/Makefile b/src/test/run-make/extra-filename-with-temp-outputs/Makefile
index d33c18a6f3c..13ca397eaf2 100644
--- a/src/test/run-make/extra-filename-with-temp-outputs/Makefile
+++ b/src/test/run-make/extra-filename-with-temp-outputs/Makefile
@@ -2,5 +2,5 @@
 
 all:
 	$(RUSTC) -C extra-filename=bar foo.rs -C save-temps
-	rm $(TMPDIR)/foobar.0.o
+	rm $(TMPDIR)/foobar.foo0.rust-cgu.o
 	rm $(TMPDIR)/$(call BIN,foobar)
diff --git a/src/test/run-make/inline-always-many-cgu/Makefile b/src/test/run-make/inline-always-many-cgu/Makefile
new file mode 100644
index 00000000000..edf88a6327c
--- /dev/null
+++ b/src/test/run-make/inline-always-many-cgu/Makefile
@@ -0,0 +1,8 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2
+	if grep -w call $(TMPDIR)/*.ll; then \
+		echo "found call instruction when one wasn't expected"; \
+		exit 1; \
+	fi
diff --git a/src/test/run-make/inline-always-many-cgu/foo.rs b/src/test/run-make/inline-always-many-cgu/foo.rs
new file mode 100644
index 00000000000..539dcdfa9b3
--- /dev/null
+++ b/src/test/run-make/inline-always-many-cgu/foo.rs
@@ -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.
+
+#![crate_type = "lib"]
+
+pub mod a {
+    #[inline(always)]
+    pub fn foo() {
+    }
+
+    pub fn bar() {
+    }
+}
+
+#[no_mangle]
+pub fn bar() {
+    a::foo();
+}
diff --git a/src/test/run-make/invalid-library/Makefile b/src/test/run-make/invalid-library/Makefile
index 0dbe655b77d..5c9cc993509 100644
--- a/src/test/run-make/invalid-library/Makefile
+++ b/src/test/run-make/invalid-library/Makefile
@@ -2,5 +2,5 @@
 
 all:
 	touch $(TMPDIR)/rust.metadata.bin
-	ar crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin
+	$(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin
 	$(RUSTC) foo.rs 2>&1 | grep "can't find crate for"
diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs
index 461df49b468..4db027aaeef 100644
--- a/src/test/run-make/issue-19371/foo.rs
+++ b/src/test/run-make/issue-19371/foo.rs
@@ -18,7 +18,6 @@ extern crate rustc_errors;
 extern crate rustc_trans;
 extern crate syntax;
 
-use rustc::dep_graph::DepGraph;
 use rustc::session::{build_session, Session};
 use rustc::session::config::{basic_options, build_configuration, Input,
                              OutputType, OutputTypes};
@@ -56,6 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
     let mut opts = basic_options();
     opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
     opts.maybe_sysroot = Some(sysroot);
+    if let Ok(linker) = std::env::var("RUSTC_LINKER") {
+        opts.cg.linker = Some(linker);
+    }
 
     let descriptions = Registry::new(&rustc::DIAGNOSTICS);
     let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
@@ -67,8 +69,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
 
 fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
     let (sess, cstore) = basic_sess(sysroot);
-    let cfg = build_configuration(&sess, HashSet::new());
     let control = CompileController::basic();
     let input = Input::Str { name: anon_src(), input: code };
-    compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control);
+    let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control);
 }
diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/issue-22131/Makefile
index 64af91b487b..cb4f1462733 100644
--- a/src/test/run-make/issue-22131/Makefile
+++ b/src/test/run-make/issue-22131/Makefile
@@ -2,6 +2,6 @@
 
 all: foo.rs
 	$(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs
-	$(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \
+	$(RUSTDOC) --test --cfg 'feature="bar"' \
 		-L $(TMPDIR) foo.rs |\
 		grep -q 'foo.rs - foo (line 11) ... ok'
diff --git a/src/test/run-make/rustdoc-output-path/Makefile b/src/test/run-make/rustdoc-output-path/Makefile
index 4e570718a62..8ce1c699526 100644
--- a/src/test/run-make/rustdoc-output-path/Makefile
+++ b/src/test/run-make/rustdoc-output-path/Makefile
@@ -1,4 +1,4 @@
 -include ../tools.mk
 
 all:
-	$(HOST_RPATH_ENV) '$(RUSTDOC)' -o "$(TMPDIR)/foo/bar/doc" foo.rs
+	$(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs
diff --git a/src/test/run-make/sepcomp-cci-copies/Makefile b/src/test/run-make/sepcomp-cci-copies/Makefile
index 189088219d5..ccd4e1b0e71 100644
--- a/src/test/run-make/sepcomp-cci-copies/Makefile
+++ b/src/test/run-make/sepcomp-cci-copies/Makefile
@@ -5,5 +5,6 @@
 
 all:
 	$(RUSTC) cci_lib.rs
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ .*cci_fn)" -eq "2" ]
+	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \
+		-Z inline-in-all-cgus
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*cci_fn)" -eq "2" ]
diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile
index 720dfff2c04..1d20d940000 100644
--- a/src/test/run-make/sepcomp-inlining/Makefile
+++ b/src/test/run-make/sepcomp-inlining/Makefile
@@ -7,8 +7,9 @@
 # in only one compilation unit.
 
 all:
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]
+	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 \
+		-Z inline-in-all-cgus
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ i32\ .*inlined)" -eq "0" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ]
diff --git a/src/test/run-make/sepcomp-separate/Makefile b/src/test/run-make/sepcomp-separate/Makefile
index a475bdfd74a..5b8bdb0fad8 100644
--- a/src/test/run-make/sepcomp-separate/Makefile
+++ b/src/test/run-make/sepcomp-separate/Makefile
@@ -6,4 +6,4 @@
 
 all:
 	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
-	[ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ .*magic_fn)" -eq "3" ]
+	[ "$$(cat "$(TMPDIR)"/foo.*.ll | grep -c define\ .*magic_fn)" -eq "3" ]
diff --git a/src/test/run-make/staticlib-blank-lib/Makefile b/src/test/run-make/staticlib-blank-lib/Makefile
index 5878eec66ba..92a278825c2 100644
--- a/src/test/run-make/staticlib-blank-lib/Makefile
+++ b/src/test/run-make/staticlib-blank-lib/Makefile
@@ -1,6 +1,6 @@
 -include ../tools.mk
 
 all:
-	ar crus $(TMPDIR)/libfoo.a foo.rs
-	ar d $(TMPDIR)/libfoo.a foo.rs
+	$(AR) crus $(TMPDIR)/libfoo.a foo.rs
+	$(AR) d $(TMPDIR)/libfoo.a foo.rs
 	$(RUSTC) foo.rs
diff --git a/src/test/run-make/target-specs/Makefile b/src/test/run-make/target-specs/Makefile
index 6b58ad7b6df..5ea96daa3ef 100644
--- a/src/test/run-make/target-specs/Makefile
+++ b/src/test/run-make/target-specs/Makefile
@@ -5,5 +5,5 @@ all:
 	$(RUSTC) foo.rs --target=my-invalid-platform.json 2>&1 | grep -q "Error loading target specification"
 	$(RUSTC) foo.rs --target=my-incomplete-platform.json 2>&1 | grep 'Field llvm-target'
 	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-awesome-platform --crate-type=lib --emit=asm
-	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=x86_64-unknown-linux-gnu --crate-type=lib --emit=asm
+	RUST_TARGET_PATH=. $(RUSTC) foo.rs --target=my-x86_64-unknown-linux-gnu-platform --crate-type=lib --emit=asm
 	$(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json -
diff --git a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json b/src/test/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json
index c1dd0cf4063..3ae01d72fcc 100644
--- a/src/test/run-make/target-specs/x86_64-unknown-linux-gnu.json
+++ b/src/test/run-make/target-specs/my-x86_64-unknown-linux-gnu-platform.json
@@ -1,6 +1,6 @@
 {
     "pre-link-args": ["-m64"],
-    "data-layout": "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128",
+    "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
     "linker-flavor": "gcc",
     "llvm-target": "x86_64-unknown-linux-gnu",
     "target-endian": "little",
diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk
index 27f235d54d4..c5d5626bf72 100644
--- a/src/test/run-make/tools.mk
+++ b/src/test/run-make/tools.mk
@@ -7,7 +7,13 @@ TARGET_RPATH_ENV = \
 
 RUSTC_ORIGINAL := $(RUSTC)
 BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)'
+BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)'
 RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS)
+RUSTDOC := $(BARE_RUSTDOC)
+ifdef RUSTC_LINKER
+RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER)
+RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options
+endif
 #CC := $(CC) -L $(TMPDIR)
 HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py
 
@@ -102,13 +108,13 @@ REMOVE_DYLIBS     = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1))
 REMOVE_RLIBS      = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))
 
 %.a: %.o
-	ar crus $@ $<
+	$(AR) crus $@ $<
 ifdef IS_MSVC
 %.lib: lib%.o
 	$(MSVC_LIB) -out:`cygpath -w $@` $<
 else
 %.lib: lib%.o
-	ar crus $@ $<
+	$(AR) crus $@ $<
 endif
 %.dylib: %.o
 	$(CC) -dynamiclib -Wl,-dylib -o $@ $<
diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
index 8ba38875eff..52a8652e65b 100644
--- a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // aux-build:attr-on-trait.rs
+// ignore-stage1
 
 #![feature(proc_macro)]
 
diff --git a/src/test/run-pass/asm-concat-src.rs b/src/test/run-pass/asm-concat-src.rs
index fb257bf7b50..0380ccbdea4 100644
--- a/src/test/run-pass/asm-concat-src.rs
+++ b/src/test/run-pass/asm-concat-src.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // pretty-expanded FIXME #23616
-// ignore-emscripten
+// ignore-emscripten no asm
 
 #![feature(asm)]
 
diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs
index f81352e1773..f9233026a1e 100644
--- a/src/test/run-pass/backtrace-debuginfo.rs
+++ b/src/test/run-pass/backtrace-debuginfo.rs
@@ -19,8 +19,6 @@
 // ignore-pretty issue #37195
 // ignore-emscripten spawning processes is not supported
 
-use std::io;
-use std::io::prelude::*;
 use std::env;
 
 #[path = "backtrace-debuginfo-aux.rs"] mod aux;
@@ -163,7 +161,7 @@ fn main() {
     let args: Vec<String> = env::args().collect();
     if args.len() >= 2 {
         let case = args[1].parse().unwrap();
-        writeln!(&mut io::stderr(), "test case {}", case).unwrap();
+        eprintln!("test case {}", case);
         outer(case, pos!());
         println!("done.");
     } else {
diff --git a/src/test/run-pass/command-before-exec.rs b/src/test/run-pass/command-before-exec.rs
index 5b83ce48e5d..9e782cca218 100644
--- a/src/test/run-pass/command-before-exec.rs
+++ b/src/test/run-pass/command-before-exec.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // ignore-windows - this is a unix-specific test
-// ignore-emscripten
+// ignore-emscripten no processes
 
 #![feature(process_exec, libc)]
 
diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs
index 5be9b97aac7..e378f55dffa 100644
--- a/src/test/run-pass/command-exec.rs
+++ b/src/test/run-pass/command-exec.rs
@@ -10,7 +10,8 @@
 
 // ignore-windows - this is a unix-specific test
 // ignore-pretty issue #37199
-// ignore-emscripten
+// ignore-emscripten no processes
+
 #![feature(process_exec)]
 
 use std::env;
diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs
index 22fbeb2d5d0..863f3cf30e9 100644
--- a/src/test/run-pass/core-run-destroy.rs
+++ b/src/test/run-pass/core-run-destroy.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // compile-flags:--test
-// ignore-emscripten
+// ignore-emscripten no processes
 
 // NB: These tests kill child processes. Valgrind sees these children as leaking
 // memory, which makes for some *confusing* logs. That's why these are here
diff --git a/src/test/run-pass/dyn-trait.rs b/src/test/run-pass/dyn-trait.rs
new file mode 100644
index 00000000000..91930852a57
--- /dev/null
+++ b/src/test/run-pass/dyn-trait.rs
@@ -0,0 +1,24 @@
+// 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.
+
+#![feature(dyn_trait)]
+
+use std::fmt::Display;
+
+static BYTE: u8 = 33;
+
+fn main() {
+    let x: &(dyn 'static + Display) = &BYTE;
+    let y: Box<dyn Display + 'static> = Box::new(BYTE);
+    let xstr = format!("{}", x);
+    let ystr = format!("{}", y);
+    assert_eq!(xstr, "33");
+    assert_eq!(ystr, "33");
+}
diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs
index 1aba47af1e9..483dbb356ce 100644
--- a/src/test/run-pass/dynamic-drop.rs
+++ b/src/test/run-pass/dynamic-drop.rs
@@ -8,9 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(untagged_unions)]
+#![feature(generators, generator_trait, untagged_unions)]
 
 use std::cell::{Cell, RefCell};
+use std::ops::Generator;
 use std::panic;
 use std::usize;
 
@@ -161,6 +162,32 @@ fn vec_simple(a: &Allocator) {
     let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
 }
 
+fn generator(a: &Allocator, run_count: usize) {
+    assert!(run_count < 4);
+
+    let mut gen = || {
+        (a.alloc(),
+         yield a.alloc(),
+         a.alloc(),
+         yield a.alloc()
+         );
+    };
+    for _ in 0..run_count {
+        gen.resume();
+    }
+}
+
+fn mixed_drop_and_nondrop(a: &Allocator) {
+    // check that destructor panics handle drop
+    // and non-drop blocks in the same scope correctly.
+    //
+    // Surprisingly enough, this used to not work.
+    let (x, y, z);
+    x = a.alloc();
+    y = 5;
+    z = a.alloc();
+}
+
 #[allow(unreachable_code)]
 fn vec_unreachable(a: &Allocator) {
     let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
@@ -228,5 +255,12 @@ fn main() {
     run_test(|a| field_assignment(a, false));
     run_test(|a| field_assignment(a, true));
 
+    run_test(|a| generator(a, 0));
+    run_test(|a| generator(a, 1));
+    run_test(|a| generator(a, 2));
+    run_test(|a| generator(a, 3));
+
+    run_test(|a| mixed_drop_and_nondrop(a));
+
     run_test_nopanic(|a| union1(a));
 }
diff --git a/src/test/run-pass/env-args-reverse-iterator.rs b/src/test/run-pass/env-args-reverse-iterator.rs
index 89af1db7c78..dddf1ae0546 100644
--- a/src/test/run-pass/env-args-reverse-iterator.rs
+++ b/src/test/run-pass/env-args-reverse-iterator.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::env::args;
 use std::process::Command;
diff --git a/src/test/run-pass/env-funky-keys.rs b/src/test/run-pass/env-funky-keys.rs
index 8b4a633d613..86ffaf1e24f 100644
--- a/src/test/run-pass/env-funky-keys.rs
+++ b/src/test/run-pass/env-funky-keys.rs
@@ -12,7 +12,7 @@
 
 // ignore-android
 // ignore-windows
-// ignore-emscripten
+// ignore-emscripten no execve
 // no-prefer-dynamic
 
 #![feature(libc)]
diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs
index bcb0c62d9fe..3693e86ba24 100644
--- a/src/test/run-pass/env-home-dir.rs
+++ b/src/test/run-pass/env-home-dir.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten env vars don't work?
 
 #![feature(path)]
 
diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs
index 2606c928680..f4ee3b6e9e8 100644
--- a/src/test/run-pass/extern-pass-empty.rs
+++ b/src/test/run-pass/extern-pass-empty.rs
@@ -12,7 +12,7 @@
 
 // pretty-expanded FIXME #23616
 // ignore-msvc
-// ignore-emscripten
+// ignore-emscripten emcc asserts on an empty struct as an argument
 
 #[repr(C)]
 struct TwoU8s {
diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs
index a1b7d42a196..f55876115c0 100644
--- a/src/test/run-pass/fds-are-cloexec.rs
+++ b/src/test/run-pass/fds-are-cloexec.rs
@@ -10,7 +10,7 @@
 
 // ignore-windows
 // ignore-android
-// ignore-emscripten
+// ignore-emscripten no processes
 // ignore-haiku
 
 #![feature(libc)]
diff --git a/src/test/run-pass/format-no-std.rs b/src/test/run-pass/format-no-std.rs
index 9e8a3218518..e23accfcc23 100644
--- a/src/test/run-pass/format-no-std.rs
+++ b/src/test/run-pass/format-no-std.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten missing rust_begin_unwind
+// ignore-emscripten no no_std executables
 
 #![feature(lang_items, start, alloc)]
 #![no_std]
diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs
index e9bdfbf28ea..8693964665d 100644
--- a/src/test/run-pass/generator/smoke.rs
+++ b/src/test/run-pass/generator/smoke.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no threads support
 // compile-flags: --test
 
 #![feature(generators, generator_trait)]
diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs
index 7c14d34b0ee..5369b138b0d 100644
--- a/src/test/run-pass/i128.rs
+++ b/src/test/run-pass/i128.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten i128 doesn't work
 
 #![feature(i128_type, test)]
 
diff --git a/src/test/run-pass/issue-10626.rs b/src/test/run-pass/issue-10626.rs
index b350bd1a4cc..e9d37817ee2 100644
--- a/src/test/run-pass/issue-10626.rs
+++ b/src/test/run-pass/issue-10626.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 // Make sure that if a process doesn't have its stdio/stderr descriptors set up
 // that we don't die in a large ball of fire
diff --git a/src/test/run-pass/issue-13304.rs b/src/test/run-pass/issue-13304.rs
index 5a743d7b547..9214d6b04bd 100644
--- a/src/test/run-pass/issue-13304.rs
+++ b/src/test/run-pass/issue-13304.rs
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
+
 #![feature(io, process_capture)]
 
 use std::env;
diff --git a/src/test/run-pass/issue-14456.rs b/src/test/run-pass/issue-14456.rs
index 513ab91489c..2edb45cc1c4 100644
--- a/src/test/run-pass/issue-14456.rs
+++ b/src/test/run-pass/issue-14456.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 #![feature(io, process_capture)]
 
diff --git a/src/test/run-pass/issue-14940.rs b/src/test/run-pass/issue-14940.rs
index ffe6b646794..588fa63cfdf 100644
--- a/src/test/run-pass/issue-14940.rs
+++ b/src/test/run-pass/issue-14940.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::env;
 use std::process::Command;
diff --git a/src/test/run-pass/issue-16272.rs b/src/test/run-pass/issue-16272.rs
index f86be2d7c99..cd02cbf3dad 100644
--- a/src/test/run-pass/issue-16272.rs
+++ b/src/test/run-pass/issue-16272.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/issue-20091.rs b/src/test/run-pass/issue-20091.rs
index 1ee47a69d0c..c8ba5dbd84c 100644
--- a/src/test/run-pass/issue-20091.rs
+++ b/src/test/run-pass/issue-20091.rs
@@ -8,7 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
+
 #![feature(std_misc, os)]
 
 #[cfg(unix)]
diff --git a/src/test/run-pass/issue-2190-1.rs b/src/test/run-pass/issue-2190-1.rs
index 39375703514..8cc23c883ed 100644
--- a/src/test/run-pass/issue-2190-1.rs
+++ b/src/test/run-pass/issue-2190-1.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // pretty-expanded FIXME #23616
-// ignore-emscripten
+// ignore-emscripten no threads
 
 use std::thread::Builder;
 
diff --git a/src/test/run-pass/issue-24313.rs b/src/test/run-pass/issue-24313.rs
index 9b2b474351d..ad385ee78e0 100644
--- a/src/test/run-pass/issue-24313.rs
+++ b/src/test/run-pass/issue-24313.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no threads
 
 use std::thread;
 use std::env;
diff --git a/src/test/run-pass/issue-28950.rs b/src/test/run-pass/issue-28950.rs
index a70c2b3ae1b..4e4530789c8 100644
--- a/src/test/run-pass/issue-28950.rs
+++ b/src/test/run-pass/issue-28950.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no threads
 // compile-flags: -O
 
 // Tests that the `vec!` macro does not overflow the stack when it is
diff --git a/src/test/run-pass/issue-29485.rs b/src/test/run-pass/issue-29485.rs
index 9252762d1bd..828b495d408 100644
--- a/src/test/run-pass/issue-29485.rs
+++ b/src/test/run-pass/issue-29485.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // aux-build:issue-29485.rs
-// ignore-emscripten
+// ignore-emscripten no threads
 
 #[feature(recover)]
 
diff --git a/src/test/run-pass/issue-29663.rs b/src/test/run-pass/issue-29663.rs
index cf925662fc3..9a77be049fe 100644
--- a/src/test/run-pass/issue-29663.rs
+++ b/src/test/run-pass/issue-29663.rs
@@ -10,8 +10,6 @@
 
 // write_volatile causes an LLVM assert with composite types
 
-// ignore-emscripten See #41299: probably a bad optimization
-
 #![feature(volatile)]
 use std::ptr::{read_volatile, write_volatile};
 
diff --git a/src/test/run-pass/issue-30490.rs b/src/test/run-pass/issue-30490.rs
index 7658abc00c5..4296107dd45 100644
--- a/src/test/run-pass/issue-30490.rs
+++ b/src/test/run-pass/issue-30490.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 // Previously libstd would set stdio descriptors of a child process
 // by `dup`ing the requested descriptors to inherit directly into the
diff --git a/src/test/run-pass/issue-33770.rs b/src/test/run-pass/issue-33770.rs
index 76728a0d354..38062700707 100644
--- a/src/test/run-pass/issue-33770.rs
+++ b/src/test/run-pass/issue-33770.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::process::{Command, Stdio};
 use std::env;
diff --git a/src/test/run-pass/issue-35600.rs b/src/test/run-pass/issue-35600.rs
new file mode 100644
index 00000000000..88358eff08d
--- /dev/null
+++ b/src/test/run-pass/issue-35600.rs
@@ -0,0 +1,24 @@
+// 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.
+
+trait Foo {
+    type bar;
+    fn bar();
+}
+
+impl Foo for () {
+    type bar = ();
+    fn bar() {}
+}
+
+fn main() {
+    let x: <() as Foo>::bar = ();
+    <()>::bar();
+}
diff --git a/src/test/run-pass/issue-36023.rs b/src/test/run-pass/issue-36023.rs
index 53a8a403b64..f6c03b384f2 100644
--- a/src/test/run-pass/issue-36023.rs
+++ b/src/test/run-pass/issue-36023.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// min-llvm-version 3.9
-
 use std::ops::Deref;
 
 fn main() {
diff --git a/src/test/run-pass/issue-40003.rs b/src/test/run-pass/issue-40003.rs
new file mode 100644
index 00000000000..103a365af0e
--- /dev/null
+++ b/src/test/run-pass/issue-40003.rs
@@ -0,0 +1,186 @@
+// 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 main() {
+    if false { test(); }
+}
+
+fn test() {
+    let rx = Err::<Vec<usize>, u32>(1).into_future();
+
+    rx.map(|l: Vec<usize>| stream::iter(l.into_iter().map(|i| Ok(i))))
+      .flatten_stream()
+      .chunks(50)
+      .buffer_unordered(5);
+}
+
+use future::{Future, IntoFuture};
+mod future {
+    use std::result;
+
+    use {stream, Stream};
+
+    pub trait Future {
+        type Item;
+        type Error;
+
+        fn map<F, U>(self, _: F) -> Map<Self, F>
+            where F: FnOnce(Self::Item) -> U,
+                  Self: Sized,
+        {
+            panic!()
+        }
+
+        fn flatten_stream(self) -> FlattenStream<Self>
+            where <Self as Future>::Item: stream::Stream<Error=Self::Error>,
+                  Self: Sized
+        {
+            panic!()
+        }
+    }
+
+    pub trait IntoFuture {
+        type Future: Future<Item=Self::Item, Error=Self::Error>;
+        type Item;
+        type Error;
+        fn into_future(self) -> Self::Future;
+    }
+
+    impl<F: Future> IntoFuture for F {
+        type Future = F;
+        type Item = F::Item;
+        type Error = F::Error;
+
+        fn into_future(self) -> F {
+            panic!()
+        }
+    }
+
+    impl<T, E> IntoFuture for result::Result<T, E> {
+        type Future = FutureResult<T, E>;
+        type Item = T;
+        type Error = E;
+
+        fn into_future(self) -> FutureResult<T, E> {
+            panic!()
+        }
+    }
+
+    pub struct Map<A, F> {
+        _a: (A, F),
+    }
+
+    impl<U, A, F> Future for Map<A, F>
+        where A: Future,
+              F: FnOnce(A::Item) -> U,
+    {
+        type Item = U;
+        type Error = A::Error;
+    }
+
+    pub struct FlattenStream<F> {
+        _f: F,
+    }
+
+    impl<F> Stream for FlattenStream<F>
+        where F: Future,
+              <F as Future>::Item: Stream<Error=F::Error>,
+    {
+        type Item = <F::Item as Stream>::Item;
+        type Error = <F::Item as Stream>::Error;
+    }
+
+    pub struct FutureResult<T, E> {
+        _inner: (T, E),
+    }
+
+    impl<T, E> Future for FutureResult<T, E> {
+        type Item = T;
+        type Error = E;
+    }
+}
+
+mod stream {
+    use IntoFuture;
+
+    pub trait Stream {
+        type Item;
+        type Error;
+
+        fn buffer_unordered(self, amt: usize) -> BufferUnordered<Self>
+            where Self::Item: IntoFuture<Error = <Self as Stream>::Error>,
+                  Self: Sized
+        {
+            new(self, amt)
+        }
+
+        fn chunks(self, _capacity: usize) -> Chunks<Self>
+            where Self: Sized
+        {
+            panic!()
+        }
+    }
+
+    pub struct IterStream<I> {
+        _iter: I,
+    }
+
+    pub fn iter<J, T, E>(_: J) -> IterStream<J::IntoIter>
+        where J: IntoIterator<Item=Result<T, E>>,
+    {
+        panic!()
+    }
+
+    impl<I, T, E> Stream for IterStream<I>
+        where I: Iterator<Item=Result<T, E>>,
+    {
+        type Item = T;
+        type Error = E;
+    }
+
+    pub struct Chunks<S> {
+        _stream: S
+    }
+
+    impl<S> Stream for Chunks<S>
+        where S: Stream
+    {
+        type Item = Result<Vec<<S as Stream>::Item>, u32>;
+        type Error = <S as Stream>::Error;
+    }
+
+    pub struct BufferUnordered<S> {
+        _stream: S,
+    }
+
+    enum Slot<T> {
+        Next(usize),
+        _Data { _a: T },
+    }
+
+    fn new<S>(_s: S, _amt: usize) -> BufferUnordered<S>
+        where S: Stream,
+              S::Item: IntoFuture<Error=<S as Stream>::Error>,
+    {
+        (0..0).map(|_| {
+            Slot::Next::<<S::Item as IntoFuture>::Future>(1)
+        }).collect::<Vec<_>>();
+        panic!()
+    }
+
+    impl<S> Stream for BufferUnordered<S>
+        where S: Stream,
+              S::Item: IntoFuture<Error=<S as Stream>::Error>,
+    {
+        type Item = <S::Item as IntoFuture>::Item;
+        type Error = <S as Stream>::Error;
+    }
+}
+use stream::Stream;
diff --git a/src/test/run-pass/issue-44247.rs b/src/test/run-pass/issue-44247.rs
new file mode 100644
index 00000000000..27b0aeaac55
--- /dev/null
+++ b/src/test/run-pass/issue-44247.rs
@@ -0,0 +1,27 @@
+// 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.
+
+trait T {
+    type X;
+    const X: Self::X;
+}
+fn foo<X: T>() {
+    let _: X::X = X::X;
+}
+
+trait S {
+    const X: Self::X;
+    type X;
+}
+fn bar<X: S>() {
+    let _: X::X = X::X;
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-44402.rs b/src/test/run-pass/issue-44402.rs
new file mode 100644
index 00000000000..244aa65a3d5
--- /dev/null
+++ b/src/test/run-pass/issue-44402.rs
@@ -0,0 +1,36 @@
+// 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.
+
+#![feature(never_type)]
+
+// Regression test for inhabitedness check. The old
+// cache used to cause us to incorrectly decide
+// that `test_b` was invalid.
+
+struct Foo {
+    field1: !,
+    field2: Option<&'static Bar>,
+}
+
+struct Bar {
+    field1: &'static Foo
+}
+
+fn test_a() {
+    let x: Option<Foo> = None;
+    match x { None => () }
+}
+
+fn test_b() {
+    let x: Option<Bar> = None;
+    match x { None => () }
+}
+
+fn main() { }
diff --git a/src/test/run-pass/issue-45124.rs b/src/test/run-pass/issue-45124.rs
new file mode 100644
index 00000000000..c65823e460b
--- /dev/null
+++ b/src/test/run-pass/issue-45124.rs
@@ -0,0 +1,24 @@
+// 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.
+
+#![feature(catch_expr)]
+
+fn main() {
+    let mut a = 0;
+    let () = {
+        let _: Result<(), ()> = do catch {
+            let _ = Err(())?;
+            return
+        };
+        a += 1;
+    };
+    a += 2;
+    assert_eq!(a, 3);
+}
diff --git a/src/test/run-pass/linkage1.rs b/src/test/run-pass/linkage1.rs
index 591610e88b1..f12a233f493 100644
--- a/src/test/run-pass/linkage1.rs
+++ b/src/test/run-pass/linkage1.rs
@@ -10,7 +10,7 @@
 
 // ignore-windows
 // ignore-macos
-// ignore-emscripten
+// ignore-emscripten doesn't support this linkage
 // aux-build:linkage1.rs
 
 #![feature(linkage)]
diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs
index d79f4b65b69..32145277252 100644
--- a/src/test/run-pass/macro-pub-matcher.rs
+++ b/src/test/run-pass/macro-pub-matcher.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 #![allow(dead_code, unused_imports)]
-#![feature(macro_vis_matcher)]
+#![feature(macro_vis_matcher, crate_visibility_modifier)]
 
 /**
 Ensure that `:vis` matches can be captured in existing positions, and passed
@@ -64,6 +64,18 @@ mod with_pub_restricted {
     vis_passthru! { pub(crate) use A as I; }
 }
 
+mod with_crate {
+    vis_passthru! { crate const A: i32 = 0; }
+    vis_passthru! { crate enum B {} }
+    vis_passthru! { crate extern "C" fn c() {} }
+    vis_passthru! { crate mod d {} }
+    vis_passthru! { crate static E: i32 = 0; }
+    vis_passthru! { crate struct F; }
+    vis_passthru! { crate trait G {} }
+    vis_passthru! { crate type H = i32; }
+    vis_passthru! { crate use A as I; }
+}
+
 mod garden {
     mod with_pub_restricted_path {
         vis_passthru! { pub(in garden) const A: i32 = 0; }
diff --git a/src/test/run-pass/multi-panic.rs b/src/test/run-pass/multi-panic.rs
index 86fe06b1765..c15b40d4dda 100644
--- a/src/test/run-pass/multi-panic.rs
+++ b/src/test/run-pass/multi-panic.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 fn check_for_no_backtrace(test: std::process::Output) {
     assert!(!test.status.success());
diff --git a/src/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs
index 85c63e184fe..7b6b711315a 100644
--- a/src/test/run-pass/no-stdio.rs
+++ b/src/test/run-pass/no-stdio.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 // ignore-android
 
 #![feature(libc)]
diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs
index 7e70c4a7ab3..485335a2d80 100644
--- a/src/test/run-pass/out-of-stack.rs
+++ b/src/test/run-pass/out-of-stack.rs
@@ -10,7 +10,7 @@
 
 // ignore-android: FIXME (#20004)
 // ignore-musl
-// ignore-emscripten
+// ignore-emscripten no processes
 
 #![feature(asm)]
 #![feature(libc)]
diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs
index d1e05e5a018..a4a0055785f 100644
--- a/src/test/run-pass/packed-struct-layout.rs
+++ b/src/test/run-pass/packed-struct-layout.rs
@@ -7,8 +7,6 @@
 // <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-emscripten Not sure what's happening here.
-
 
 use std::mem;
 
diff --git a/src/test/run-pass/packed-tuple-struct-layout.rs b/src/test/run-pass/packed-tuple-struct-layout.rs
index ee4eb86ed0d..18f7eff280a 100644
--- a/src/test/run-pass/packed-tuple-struct-layout.rs
+++ b/src/test/run-pass/packed-tuple-struct-layout.rs
@@ -7,8 +7,6 @@
 // <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-emscripten
-
 
 use std::mem;
 
diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
index ebbb00a4a9f..d1fdc8afa65 100644
--- a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
+++ b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
@@ -11,7 +11,7 @@
 // compile-flags:-C panic=abort
 // aux-build:exit-success-if-unwind.rs
 // no-prefer-dynamic
-// ignore-emscripten Function not implemented
+// ignore-emscripten no processes
 
 extern crate exit_success_if_unwind;
 
diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs
index 3ba3bd61c2e..bb541b29d7c 100644
--- a/src/test/run-pass/panic-runtime/abort.rs
+++ b/src/test/run-pass/panic-runtime/abort.rs
@@ -10,7 +10,7 @@
 
 // compile-flags:-C panic=abort
 // no-prefer-dynamic
-// ignore-emscripten Function not implemented.
+// ignore-emscripten no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/panic-runtime/lto-abort.rs b/src/test/run-pass/panic-runtime/lto-abort.rs
index e4cd4e809a4..59e9474aab2 100644
--- a/src/test/run-pass/panic-runtime/lto-abort.rs
+++ b/src/test/run-pass/panic-runtime/lto-abort.rs
@@ -10,7 +10,7 @@
 
 // compile-flags:-C lto -C panic=abort
 // no-prefer-dynamic
-// ignore-emscripten Function not implemented.
+// ignore-emscripten no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/panic-runtime/lto-unwind.rs b/src/test/run-pass/panic-runtime/lto-unwind.rs
index 768b88fd09e..6d28b8d12f6 100644
--- a/src/test/run-pass/panic-runtime/lto-unwind.rs
+++ b/src/test/run-pass/panic-runtime/lto-unwind.rs
@@ -10,7 +10,7 @@
 
 // compile-flags:-C lto -C panic=unwind
 // no-prefer-dynamic
-// ignore-emscripten Function not implemented.
+// ignore-emscripten no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/process-envs.rs b/src/test/run-pass/process-envs.rs
index b3785d898ba..1622517198a 100644
--- a/src/test/run-pass/process-envs.rs
+++ b/src/test/run-pass/process-envs.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/process-exit.rs b/src/test/run-pass/process-exit.rs
index a5d408448a0..5abc06b75e1 100644
--- a/src/test/run-pass/process-exit.rs
+++ b/src/test/run-pass/process-exit.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::env;
 use std::process::{self, Command, Stdio};
diff --git a/src/test/run-pass/process-remove-from-env.rs b/src/test/run-pass/process-remove-from-env.rs
index b7f296a65c2..7a9b431d570 100644
--- a/src/test/run-pass/process-remove-from-env.rs
+++ b/src/test/run-pass/process-remove-from-env.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/process-spawn-with-unicode-params.rs b/src/test/run-pass/process-spawn-with-unicode-params.rs
index 550c6d6ab67..7b854207263 100644
--- a/src/test/run-pass/process-spawn-with-unicode-params.rs
+++ b/src/test/run-pass/process-spawn-with-unicode-params.rs
@@ -16,7 +16,7 @@
 // non-ASCII characters.  The child process ensures all the strings are
 // intact.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::io::prelude::*;
 use std::io;
diff --git a/src/test/run-pass/process-status-inherits-stdin.rs b/src/test/run-pass/process-status-inherits-stdin.rs
index ff389bec899..5ea48a4ff33 100644
--- a/src/test/run-pass/process-status-inherits-stdin.rs
+++ b/src/test/run-pass/process-status-inherits-stdin.rs
@@ -7,7 +7,8 @@
 // <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-emscripten Function not implemented.
+
+// ignore-emscripten no processes
 
 use std::env;
 use std::io;
diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs
index f81c3f2e99d..6f696c1c9ce 100644
--- a/src/test/run-pass/running-with-no-runtime.rs
+++ b/src/test/run-pass/running-with-no-runtime.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten spawning processes is not supported
 
 #![feature(start)]
 
diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs
index 8a2bbc83c42..0f6832acec8 100644
--- a/src/test/run-pass/signal-exit-status.rs
+++ b/src/test/run-pass/signal-exit-status.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // ignore-windows
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::env;
 use std::process::Command;
diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs
index 5aa4faa1365..465feb4b779 100644
--- a/src/test/run-pass/sigpipe-should-be-ignored.rs
+++ b/src/test/run-pass/sigpipe-should-be-ignored.rs
@@ -11,7 +11,7 @@
 // Be sure that when a SIGPIPE would have been received that the entire process
 // doesn't die in a ball of fire, but rather it's gracefully handled.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::env;
 use std::io::prelude::*;
diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs
index ede2325b51c..ed2786edf3a 100644
--- a/src/test/run-pass/simd-intrinsic-generic-cast.rs
+++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs
@@ -7,7 +7,8 @@
 // <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-emscripten linking with emcc failed
+
+// ignore-emscripten FIXME(#45351) hits an LLVM assert
 
 #![feature(repr_simd, platform_intrinsics, concat_idents, test)]
 #![allow(non_camel_case_types)]
diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs
deleted file mode 100644
index bcbd3fd3786..00000000000
--- a/src/test/run-pass/smallest-hello-world.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013-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.
-
-// Smallest "hello world" with a libc runtime
-
-// ignore-windows
-// ignore-android
-
-#![feature(intrinsics, lang_items, start, no_core, alloc_system)]
-#![feature(global_allocator, allocator_api)]
-#![no_std]
-
-extern crate alloc_system;
-
-use alloc_system::System;
-
-#[global_allocator]
-static A: System = System;
-
-extern {
-    fn puts(s: *const u8);
-}
-
-#[no_mangle]
-#[lang = "eh_personality"] pub extern fn rust_eh_personality() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
-    unsafe {
-        puts("Hello!\0".as_ptr() as *const u8);
-    }
-    return 0
-}
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/allowed-cross-crate.rs
index 6b999f38358..6b999f38358 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs
+++ b/src/test/run-pass/specialization/defaultimpl/allowed-cross-crate.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs
index b99ba3d0f1c..b99ba3d0f1c 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs
+++ b/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs
index 71dd7c99009..71dd7c99009 100644
--- a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs
+++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs
index 9d0ea64fed4..9d0ea64fed4 100644
--- a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs
+++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs
index 7daecc842f3..7daecc842f3 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs
+++ b/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs b/src/test/run-pass/specialization/defaultimpl/basics.rs
index 594f1e4fcdf..594f1e4fcdf 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs
+++ b/src/test/run-pass/specialization/defaultimpl/basics.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs
index 62c7e3e2e44..19e1af15bdd 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs
+++ b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs
@@ -8,13 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:specialization_cross_crate_defaults.rs
+// aux-build:cross_crate_defaults.rs
 
 #![feature(specialization)]
 
-extern crate specialization_cross_crate_defaults;
+extern crate cross_crate_defaults;
 
-use specialization_cross_crate_defaults::*;
+use cross_crate_defaults::*;
 
 struct LocalDefault;
 struct LocalOverride;
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs
index b9548539e16..67cc694ae12 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs
+++ b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs
@@ -10,11 +10,11 @@
 
 // Test that specialization works even if only the upstream crate enables it
 
-// aux-build:specialization_cross_crate.rs
+// aux-build:cross_crate.rs
 
-extern crate specialization_cross_crate;
+extern crate cross_crate;
 
-use specialization_cross_crate::*;
+use cross_crate::*;
 
 fn  main() {
     assert!(0u8.foo() == "generic Clone");
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs
index 7517824b62b..f1ad105db8f 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs
+++ b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs
@@ -8,13 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:specialization_cross_crate.rs
+// aux-build:cross_crate.rs
 
 #![feature(specialization)]
 
-extern crate specialization_cross_crate;
+extern crate cross_crate;
 
-use specialization_cross_crate::*;
+use cross_crate::*;
 
 struct NotClone;
 
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs b/src/test/run-pass/specialization/defaultimpl/default-methods.rs
index 4ac9afc1c89..4ac9afc1c89 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs
+++ b/src/test/run-pass/specialization/defaultimpl/default-methods.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs b/src/test/run-pass/specialization/defaultimpl/out-of-order.rs
index f77b88e2f85..f77b88e2f85 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs
+++ b/src/test/run-pass/specialization/defaultimpl/out-of-order.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs b/src/test/run-pass/specialization/defaultimpl/overlap-projection.rs
index 500cded38c1..500cded38c1 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs
+++ b/src/test/run-pass/specialization/defaultimpl/overlap-projection.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/projection-alias.rs
index 2397c3e2bff..2397c3e2bff 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs
+++ b/src/test/run-pass/specialization/defaultimpl/projection-alias.rs
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs b/src/test/run-pass/specialization/defaultimpl/projection.rs
index 6a833ba6760..6a833ba6760 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs
+++ b/src/test/run-pass/specialization/defaultimpl/projection.rs
diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs
index f49320e4da4..78a1019578e 100644
--- a/src/test/run-pass/stack-probes-lto.rs
+++ b/src/test/run-pass/stack-probes-lto.rs
@@ -11,7 +11,7 @@
 // ignore-arm
 // ignore-aarch64
 // ignore-wasm
-// ignore-emscripten
+// ignore-emscripten no processes
 // ignore-musl FIXME #31506
 // ignore-pretty
 // no-system-llvm
diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs
index 1d66cb60207..bb9471e1b48 100644
--- a/src/test/run-pass/stack-probes.rs
+++ b/src/test/run-pass/stack-probes.rs
@@ -11,7 +11,7 @@
 // ignore-arm
 // ignore-aarch64
 // ignore-wasm
-// ignore-emscripten
+// ignore-emscripten no processes
 // ignore-musl FIXME #31506
 // no-system-llvm
 
diff --git a/src/test/run-pass/stdio-is-blocking.rs b/src/test/run-pass/stdio-is-blocking.rs
index 448bb7de772..cce1077202c 100644
--- a/src/test/run-pass/stdio-is-blocking.rs
+++ b/src/test/run-pass/stdio-is-blocking.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 use std::env;
 use std::io::prelude::*;
diff --git a/src/test/run-pass/thin-lto-global-allocator.rs b/src/test/run-pass/thin-lto-global-allocator.rs
new file mode 100644
index 00000000000..1c15da5469e
--- /dev/null
+++ b/src/test/run-pass/thin-lto-global-allocator.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=2
+// min-llvm-version 4.0
+
+#![feature(allocator_api, global_allocator)]
+
+#[global_allocator]
+static A: std::heap::System = std::heap::System;
+
+fn main() {}
diff --git a/src/test/run-pass/thinlto/auxiliary/dylib.rs b/src/test/run-pass/thinlto/auxiliary/dylib.rs
new file mode 100644
index 00000000000..cdb3f49cae8
--- /dev/null
+++ b/src/test/run-pass/thinlto/auxiliary/dylib.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.
+
+// compile-flags: -Z thinlto -C codegen-units=8
+
+#[inline]
+pub fn foo(b: u8) {
+    b.to_string();
+}
diff --git a/src/test/run-pass/thinlto/auxiliary/msvc-imp-present.rs b/src/test/run-pass/thinlto/auxiliary/msvc-imp-present.rs
new file mode 100644
index 00000000000..eff7802a245
--- /dev/null
+++ b/src/test/run-pass/thinlto/auxiliary/msvc-imp-present.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.
+
+// no-prefer-dynamic
+// compile-flags: -Z thinlto -C codegen-units=8 -C prefer-dynamic
+
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+
+pub static A: u32 = 43;
+
+pub mod a {
+    pub static A: u32 = 43;
+}
diff --git a/src/libstd/os/nacl/mod.rs b/src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs
index 7dfa2eabe3e..ccbb0e7a718 100644
--- a/src/libstd/os/nacl/mod.rs
+++ b/src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 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,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Nacl-specific definitions
+// no-prefer-dynamic
 
-#![stable(feature = "raw_ext", since = "1.1.0")]
+#![crate_type = "rlib"]
 
-pub mod raw;
-pub mod fs;
+pub fn bar() -> u32 {
+    3
+}
diff --git a/src/test/run-pass/thinlto/dylib-works.rs b/src/test/run-pass/thinlto/dylib-works.rs
new file mode 100644
index 00000000000..3f54519d0d8
--- /dev/null
+++ b/src/test/run-pass/thinlto/dylib-works.rs
@@ -0,0 +1,18 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:dylib.rs
+// min-llvm-version 4.0
+
+extern crate dylib;
+
+fn main() {
+    dylib::foo(1);
+}
diff --git a/src/test/run-pass/thinlto/msvc-imp-present.rs b/src/test/run-pass/thinlto/msvc-imp-present.rs
new file mode 100644
index 00000000000..8329c7032f1
--- /dev/null
+++ b/src/test/run-pass/thinlto/msvc-imp-present.rs
@@ -0,0 +1,31 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:msvc-imp-present.rs
+// compile-flags: -Z thinlto -C codegen-units=8
+// min-llvm-version: 4.0
+// no-prefer-dynamic
+
+// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
+// for all exported statics. This is done because we apply `dllimport` to all
+// imported constants and this allows everything to actually link correctly.
+//
+// The ThinLTO passes aggressively remove symbols if they can, and this test
+// asserts that the ThinLTO passes don't remove these compiler-generated
+// `_imp_*` symbols. The external library that we link in here is compiled with
+// ThinLTO and multiple codegen units and has a few exported constants. Note
+// that we also namely compile the library as both a dylib and an rlib, but we
+// link the rlib to ensure that we assert those generated symbols exist.
+
+extern crate msvc_imp_present as bar;
+
+fn main() {
+    println!("{}", bar::A);
+}
diff --git a/src/test/run-pass/thinlto/thin-lto-inlines.rs b/src/test/run-pass/thinlto/thin-lto-inlines.rs
new file mode 100644
index 00000000000..7a71dd2bc51
--- /dev/null
+++ b/src/test/run-pass/thinlto/thin-lto-inlines.rs
@@ -0,0 +1,39 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// min-llvm-version 4.0
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+    bar::bar()
+}
+
+mod bar {
+    pub fn bar() -> u32 {
+        3
+    }
+}
+
+fn main() {
+    println!("{} {}", foo(), bar::bar());
+
+    unsafe {
+        let foo = foo as usize as *const u8;
+        let bar = bar::bar as usize as *const u8;
+
+        assert_eq!(*foo, *bar);
+    }
+}
diff --git a/src/test/run-pass/thinlto/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs
new file mode 100644
index 00000000000..0e8ad08a5f6
--- /dev/null
+++ b/src/test/run-pass/thinlto/thin-lto-inlines2.rs
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
+// aux-build:thin-lto-inlines-aux.rs
+// min-llvm-version 4.0
+// no-prefer-dynamic
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+    bar::bar()
+}
+
+fn main() {
+    println!("{} {}", foo(), bar::bar());
+
+    unsafe {
+        let foo = foo as usize as *const u8;
+        let bar = bar::bar as usize as *const u8;
+
+        assert_eq!(*foo, *bar);
+    }
+}
+
diff --git a/src/test/run-pass/try-wait.rs b/src/test/run-pass/try-wait.rs
index be87b7b3c87..0ee2cb9238c 100644
--- a/src/test/run-pass/try-wait.rs
+++ b/src/test/run-pass/try-wait.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 #![feature(process_try_wait)]
 
diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs
index b16f6c7b6af..bf506a71250 100644
--- a/src/test/run-pass/u128.rs
+++ b/src/test/run-pass/u128.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten u128 not supported
 
 #![feature(i128_type, test)]
 
diff --git a/src/test/run-pass/vec-macro-no-std.rs b/src/test/run-pass/vec-macro-no-std.rs
index f21027afac3..56ff9cb2477 100644
--- a/src/test/run-pass/vec-macro-no-std.rs
+++ b/src/test/run-pass/vec-macro-no-std.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten missing rust_begin_unwind
+// ignore-emscripten no no_std executables
 
 #![feature(lang_items, start, libc, alloc)]
 #![no_std]
diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs
index 1d1c83cf12a..744f2989bcf 100644
--- a/src/test/run-pass/wait-forked-but-failed-child.rs
+++ b/src/test/run-pass/wait-forked-but-failed-child.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-emscripten
+// ignore-emscripten no processes
 
 #![feature(libc)]
 
diff --git a/src/test/rustdoc/crate-version.rs b/src/test/rustdoc/crate-version.rs
new file mode 100644
index 00000000000..07ab5ceedfa
--- /dev/null
+++ b/src/test/rustdoc/crate-version.rs
@@ -0,0 +1,13 @@
+// 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.
+
+// compile-flags: --crate-version=1.3.37 -Z unstable-options
+
+// @has 'crate_version/index.html' '//div[@class="block version"]/p' 'Version 1.3.37'
diff --git a/src/test/rustdoc/empty-mod-private.rs b/src/test/rustdoc/empty-mod-private.rs
index 6b86af62a66..6c6af19be88 100644
--- a/src/test/rustdoc/empty-mod-private.rs
+++ b/src/test/rustdoc/empty-mod-private.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments --passes strip-priv-imports
+// compile-flags: --document-private-items
 
 // @has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo'
 // @has 'empty_mod_private/sidebar-items.js' 'foo'
diff --git a/src/test/rustdoc/fn-pointer-arg-name.rs b/src/test/rustdoc/fn-pointer-arg-name.rs
new file mode 100644
index 00000000000..af87f1b4669
--- /dev/null
+++ b/src/test/rustdoc/fn-pointer-arg-name.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.
+
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - '//*[@class="rust fn"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
+pub fn f(callback: fn(len: usize, foo: u32)) {}
diff --git a/src/test/rustdoc/issue-15347.rs b/src/test/rustdoc/issue-15347.rs
index 266a3089194..c50df6edd48 100644
--- a/src/test/rustdoc/issue-15347.rs
+++ b/src/test/rustdoc/issue-15347.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags:--no-defaults --passes collapse-docs --passes unindent-comments
+// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments
 
 // @has issue_15347/fn.foo.html
 #[doc(hidden)]
diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs
index 5998734e4a2..24d566e082e 100644
--- a/src/test/rustdoc/pub-method.rs
+++ b/src/test/rustdoc/pub-method.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 // ignore-tidy-linelength
-// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments --passes strip-priv-imports
+// compile-flags: --document-private-items
 
 #![crate_name = "foo"]
 
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs
new file mode 100644
index 00000000000..f2d04c16d99
--- /dev/null
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs
@@ -0,0 +1,40 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    f1(|_: (), _: ()| {});
+    f2(|_: (), _: ()| {});
+    f3(|_: (), _: ()| {});
+    f4(|_: (), _: ()| {});
+    f5(|_: (), _: ()| {});
+    g1(|_: (), _: ()| {});
+    g2(|_: (), _: ()| {});
+    g3(|_: (), _: ()| {});
+    g4(|_: (), _: ()| {});
+    h1(|_: (), _: (), _: (), _: ()| {});
+    h2(|_: (), _: (), _: (), _: ()| {});
+}
+
+// Basic
+fn f1<F>(_: F) where F: Fn(&(), &()) {}
+fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
+fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
+fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
+fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
+
+// Nested
+fn g1<F>(_: F) where F: Fn(&(), Box<Fn(&())>) {}
+fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
+fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<Fn(&())>) {}
+fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
+
+// Mixed
+fn h1<F>(_: F) where F: Fn(&(), Box<Fn(&())>, &(), fn(&(), &())) {}
+fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<Fn(&())>, &'t0 (), fn(&(), &())) {}
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
new file mode 100644
index 00000000000..f962b772203
--- /dev/null
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
@@ -0,0 +1,112 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+   |
+12 |     f1(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _`
+   |
+   = note: required by `f1`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5
+   |
+13 |     f2(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _`
+   |
+   = note: required by `f2`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
+   |
+14 |     f3(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'r> fn(&(), &'r ()) -> _`
+   |
+   = note: required by `f3`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5
+   |
+15 |     f4(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _`
+   |
+   = note: required by `f4`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
+   |
+16 |     f5(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'r> fn(&'r (), &'r ()) -> _`
+   |
+   = note: required by `f5`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5
+   |
+17 |     g1(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'r> fn(&'r (), std::boxed::Box<for<'s> std::ops::Fn(&'s ()) + 'static>) -> _`
+   |
+   = note: required by `g1`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
+   |
+18 |     g2(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _`
+   |
+   = note: required by `g2`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:19:5
+   |
+19 |     g3(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'s> fn(&'s (), std::boxed::Box<for<'r> std::ops::Fn(&'r ()) + 'static>) -> _`
+   |
+   = note: required by `g3`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
+   |
+20 |     g4(|_: (), _: ()| {});
+   |     ^^ ----------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _`
+   |
+   = note: required by `g4`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:21:5
+   |
+21 |     h1(|_: (), _: (), _: (), _: ()| {});
+   |     ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _`
+   |     |
+   |     expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<for<'t0> std::ops::Fn(&'t0 ()) + 'static>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _`
+   |
+   = note: required by `h1`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
+   |
+22 |     h2(|_: (), _: (), _: (), _: ()| {});
+   |     ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _`
+   |     |
+   |     expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<for<'s> std::ops::Fn(&'s ()) + 'static>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _`
+   |
+   = note: required by `h2`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr
index 1a0c74dc01a..11279f5c612 100644
--- a/src/test/ui/did_you_mean/issue-40396.stderr
+++ b/src/test/ui/did_you_mean/issue-40396.stderr
@@ -5,6 +5,7 @@ error: chained comparison operators require parentheses
    |                                     ^^^^^^^^
    |
    = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
 
 error: chained comparison operators require parentheses
   --> $DIR/issue-40396.rs:16:25
@@ -13,6 +14,7 @@ error: chained comparison operators require parentheses
    |                         ^^^^^^^
    |
    = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
 
 error: chained comparison operators require parentheses
   --> $DIR/issue-40396.rs:20:37
@@ -21,6 +23,7 @@ error: chained comparison operators require parentheses
    |                                     ^^^^^^^^
    |
    = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
 
 error: chained comparison operators require parentheses
   --> $DIR/issue-40396.rs:20:41
@@ -29,6 +32,7 @@ error: chained comparison operators require parentheses
    |                                         ^^^^^^
    |
    = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
+   = help: or use `(...)` if you meant to specify fn arguments
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issue-22644.rs b/src/test/ui/issue-22644.rs
index b482d0595f7..c8e0cd1763f 100644
--- a/src/test/ui/issue-22644.rs
+++ b/src/test/ui/issue-22644.rs
@@ -35,5 +35,7 @@ fn main() {
                    <
                    5);
 
+    println!("{}", a as usize << long_name);
+
     println!("{}", a: &mut 4);
 }
diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr
index 54c325b24a3..f4967c4803b 100644
--- a/src/test/ui/issue-22644.stderr
+++ b/src/test/ui/issue-22644.stderr
@@ -76,9 +76,18 @@ help: try comparing the casted value
 33 | 
  ...
 
+error: `<` is interpreted as a start of generic arguments for `usize`, not a shift
+  --> $DIR/issue-22644.rs:38:31
+   |
+38 |     println!("{}", a as usize << long_name);
+   |                    ---------- ^^ --------- interpreted as generic arguments
+   |                    |          |
+   |                    |          not interpreted as shift
+   |                    help: try shifting the casted value: `(a as usize)`
+
 error: expected type, found `4`
-  --> $DIR/issue-22644.rs:38:28
+  --> $DIR/issue-22644.rs:40:28
    |
-38 |     println!("{}", a: &mut 4);
+40 |     println!("{}", a: &mut 4);
    |                            ^ expecting a type here because of type ascription
 
diff --git a/src/test/ui/issue-36400.rs b/src/test/ui/issue-36400.rs
new file mode 100644
index 00000000000..c0aec5b4296
--- /dev/null
+++ b/src/test/ui/issue-36400.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(x: &mut u32) {}
+
+fn main() {
+    let x = Box::new(3);
+    f(&mut *x);
+}
diff --git a/src/test/ui/issue-36400.stderr b/src/test/ui/issue-36400.stderr
new file mode 100644
index 00000000000..69e9c455f35
--- /dev/null
+++ b/src/test/ui/issue-36400.stderr
@@ -0,0 +1,10 @@
+error[E0596]: cannot borrow immutable `Box` content `*x` as mutable
+  --> $DIR/issue-36400.rs:15:12
+   |
+14 |     let x = Box::new(3);
+   |         - consider changing this to `mut x`
+15 |     f(&mut *x);
+   |            ^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issue-44406.rs b/src/test/ui/issue-44406.rs
new file mode 100644
index 00000000000..abf572118fc
--- /dev/null
+++ b/src/test/ui/issue-44406.rs
@@ -0,0 +1,19 @@
+// 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.
+
+macro_rules! foo {
+    ($rest: tt) => {
+        bar(baz: $rest)
+    }
+}
+
+fn main() {
+    foo!(true);
+}
diff --git a/src/test/ui/issue-44406.stderr b/src/test/ui/issue-44406.stderr
new file mode 100644
index 00000000000..9beae91540a
--- /dev/null
+++ b/src/test/ui/issue-44406.stderr
@@ -0,0 +1,26 @@
+error: expected identifier, found keyword `true`
+  --> $DIR/issue-44406.rs:18:10
+   |
+18 |     foo!(true);
+   |          ^^^^
+
+error: expected type, found keyword `true`
+  --> $DIR/issue-44406.rs:18:10
+   |
+13 |         bar(baz: $rest)
+   |                - help: did you mean to use `;` here?
+...
+18 |     foo!(true);
+   |          ^^^^ expecting a type here because of type ascription
+
+error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true`
+  --> $DIR/issue-44406.rs:18:10
+   |
+13 |         bar(baz: $rest)
+   |                 - expected one of 20 possible tokens here
+...
+18 |     foo!(true);
+   |          ^^^^ unexpected token
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/issue-45296.rs b/src/test/ui/issue-45296.rs
new file mode 100644
index 00000000000..7a2b4e56d69
--- /dev/null
+++ b/src/test/ui/issue-45296.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.
+
+fn main() {
+    let unused = ();
+
+    #![allow(unused_variables)]
+}
diff --git a/src/test/ui/issue-45296.stderr b/src/test/ui/issue-45296.stderr
new file mode 100644
index 00000000000..7bfcac974c5
--- /dev/null
+++ b/src/test/ui/issue-45296.stderr
@@ -0,0 +1,11 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/issue-45296.rs:14:7
+   |
+14 |     #![allow(unused_variables)]
+   |       ^
+   |
+   = note: inner attributes and doc comments, like `#![no_std]` or `//! My crate`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes and doc comments, like `#[test]` and
+                                              `/// My function`, annotate the item following them.
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lint/suggestions.rs b/src/test/ui/lint/suggestions.rs
index 874124a7d36..e078056ab5e 100644
--- a/src/test/ui/lint/suggestions.rs
+++ b/src/test/ui/lint/suggestions.rs
@@ -11,10 +11,27 @@
 #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
 #![feature(no_debug)]
 
+#[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+#[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+
+#[no_mangle] // should suggest removal (generics can't be no-mangle)
+pub fn defiant<T>(_t: T) {}
+
+#[no_mangle]
+fn rio_grande() {} // should suggest `pub`
+
+struct Equinox {
+    warp_factor: f32,
+}
+
 #[no_debug] // should suggest removal of deprecated attribute
 fn main() {
     while true { // should suggest `loop`
         let mut a = (1); // should suggest no `mut`, no parens
+        let d = Equinox { warp_factor: 9.975 };
+        match d {
+            Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+        }
         println!("{}", a);
     }
 }
diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr
index 5b2a4f589f7..7a498b56413 100644
--- a/src/test/ui/lint/suggestions.stderr
+++ b/src/test/ui/lint/suggestions.stderr
@@ -1,45 +1,100 @@
 warning: unnecessary parentheses around assigned value
-  --> $DIR/suggestions.rs:17:21
+  --> $DIR/suggestions.rs:30:21
    |
-17 |         let mut a = (1); // should suggest no `mut`, no parens
+30 |         let mut a = (1); // should suggest no `mut`, no parens
    |                     ^^^ help: remove these parentheses
    |
    = note: #[warn(unused_parens)] on by default
 
 warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721
-  --> $DIR/suggestions.rs:14:1
+  --> $DIR/suggestions.rs:27:1
    |
-14 | #[no_debug] // should suggest removal of deprecated attribute
+27 | #[no_debug] // should suggest removal of deprecated attribute
    | ^^^^^^^^^^^ help: remove this attribute
    |
    = note: #[warn(deprecated)] on by default
 
+warning: variable does not need to be mutable
+  --> $DIR/suggestions.rs:30:13
+   |
+30 |         let mut a = (1); // should suggest no `mut`, no parens
+   |             ---^^
+   |             |
+   |             help: remove this `mut`
+   |
+note: lint level defined here
+  --> $DIR/suggestions.rs:11:9
+   |
+11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
+   |         ^^^^^^^^^^
+
+warning: static is marked #[no_mangle], but not exported
+  --> $DIR/suggestions.rs:14:14
+   |
+14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+   |              -^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              help: try making it public: `pub `
+   |
+   = note: #[warn(private_no_mangle_statics)] on by default
+
+error: const items should never be #[no_mangle]
+  --> $DIR/suggestions.rs:15:14
+   |
+15 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+   |              -----^^^^^^^^^^^^^^^^^^^^^^
+   |              |
+   |              help: try a static value: `pub static`
+   |
+   = note: #[deny(no_mangle_const_items)] on by default
+
+warning: functions generic over types must be mangled
+  --> $DIR/suggestions.rs:18:1
+   |
+17 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
+   | ------------ help: remove this attribute
+18 | pub fn defiant<T>(_t: T) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(no_mangle_generic_items)] on by default
+
+warning: function is marked #[no_mangle], but not exported
+  --> $DIR/suggestions.rs:21:1
+   |
+21 | fn rio_grande() {} // should suggest `pub`
+   | -^^^^^^^^^^^^^^^^^
+   | |
+   | help: try making it public: `pub `
+   |
+   = note: #[warn(private_no_mangle_fns)] on by default
+
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/suggestions.rs:16:5
+  --> $DIR/suggestions.rs:29:5
    |
-16 |       while true { // should suggest `loop`
+29 |       while true { // should suggest `loop`
    |       ^---------
    |       |
    |  _____help: use `loop`
    | |
-17 | |         let mut a = (1); // should suggest no `mut`, no parens
-18 | |         println!("{}", a);
-19 | |     }
+30 | |         let mut a = (1); // should suggest no `mut`, no parens
+31 | |         let d = Equinox { warp_factor: 9.975 };
+32 | |         match d {
+...  |
+35 | |         println!("{}", a);
+36 | |     }
    | |_____^
    |
    = note: #[warn(while_true)] on by default
 
-warning: variable does not need to be mutable
-  --> $DIR/suggestions.rs:17:13
+warning: the `warp_factor:` in this pattern is redundant
+  --> $DIR/suggestions.rs:33:23
    |
-17 |         let mut a = (1); // should suggest no `mut`, no parens
-   |             ---^^
-   |             |
-   |             help: remove this `mut`
-   |
-note: lint level defined here
-  --> $DIR/suggestions.rs:11:9
+33 |             Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+   |                       ------------^^^^^^^^^^^^
+   |                       |
+   |                       help: remove this
    |
-11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
-   |         ^^^^^^^^^^
+   = note: #[warn(non_shorthand_field_patterns)] on by default
+
+error: aborting due to previous error
 
diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs
index d7cbd11472a..9decb0cff36 100644
--- a/src/test/ui/lint/unused_parens_json_suggestion.rs
+++ b/src/test/ui/lint/unused_parens_json_suggestion.rs
@@ -10,8 +10,6 @@
 
 // compile-flags: --error-format json
 
-// ignore-windows (see Issue #44968)
-
 // The output for humans should just highlight the whole span without showing
 // the suggested replacement, but we also want to test that suggested
 // replacement only removes one set of parentheses, rather than naïvely
diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr
index 140224e0814..4b4dd92855d 100644
--- a/src/test/ui/lint/unused_parens_json_suggestion.stderr
+++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr
@@ -1 +1 @@
-{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1014,"byte_end":1027,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1014,"byte_end":1027,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":"    let _a = 1 / (2 + 3);"}],"rendered":null}
+{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":"    let _a = 1 / (2 + 3);"}],"rendered":null}
diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/ui/method-call-err-msg.rs
index 14fa74d1f32..14fa74d1f32 100644
--- a/src/test/compile-fail/method-call-err-msg.rs
+++ b/src/test/ui/method-call-err-msg.rs
diff --git a/src/test/ui/method-call-err-msg.stderr b/src/test/ui/method-call-err-msg.stderr
new file mode 100644
index 00000000000..c39c62daf9e
--- /dev/null
+++ b/src/test/ui/method-call-err-msg.stderr
@@ -0,0 +1,44 @@
+error[E0061]: this function takes 0 parameters but 1 parameter was supplied
+  --> $DIR/method-call-err-msg.rs:25:12
+   |
+15 |     fn zero(self) -> Foo { self }
+   |     ----------------------------- defined here
+...
+25 |     x.zero(0)   //~ ERROR this function takes 0 parameters but 1 parameter was supplied
+   |            ^ expected 0 parameters
+
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+  --> $DIR/method-call-err-msg.rs:27:7
+   |
+17 |     fn one(self, _: isize) -> Foo { self }
+   |     -------------------------------------- defined here
+...
+27 |      .one()     //~ ERROR this function takes 1 parameter but 0 parameters were supplied
+   |       ^^^ expected 1 parameter
+
+error[E0061]: this function takes 2 parameters but 1 parameter was supplied
+  --> $DIR/method-call-err-msg.rs:29:11
+   |
+19 |     fn two(self, _: isize, _: isize) -> Foo { self }
+   |     ------------------------------------------------ defined here
+...
+29 |      .two(0);   //~ ERROR this function takes 2 parameters but 1 parameter was supplied
+   |           ^ expected 2 parameters
+
+error[E0599]: no method named `take` found for type `Foo` in the current scope
+  --> $DIR/method-call-err-msg.rs:34:7
+   |
+34 |      .take()    //~ ERROR no method named `take` found for type `Foo` in the current scope
+   |       ^^^^
+   |
+   = note: the method `take` exists but the following trait bounds were not satisfied:
+           `&mut Foo : std::iter::Iterator`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following traits define an item `take`, perhaps you need to implement one of them:
+           candidate #1: `std::collections::hash::Recover`
+           candidate #2: `std::io::Read`
+           candidate #3: `std::iter::Iterator`
+           candidate #4: `alloc::btree::Recover`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs
index f94471a73ca..5d2d1d2b04c 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.rs
+++ b/src/test/ui/mismatched_types/closure-arg-count.rs
@@ -16,4 +16,8 @@ fn main() {
     [1, 2, 3].sort_by(|tuple| panic!());
     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
     f(|| panic!());
+
+    let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
+    let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
+    let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
 }
diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr
index 3031a77b1e8..9d4ac630546 100644
--- a/src/test/ui/mismatched_types/closure-arg-count.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-count.stderr
@@ -1,16 +1,16 @@
-error[E0593]: closure takes 0 arguments but 2 arguments are required
+error[E0593]: closure is expected to take 2 arguments, but it takes 0 arguments
   --> $DIR/closure-arg-count.rs:15:15
    |
 15 |     [1, 2, 3].sort_by(|| panic!());
-   |               ^^^^^^^ ----------- takes 0 arguments
+   |               ^^^^^^^ -- takes 0 arguments
    |               |
    |               expected closure that takes 2 arguments
 
-error[E0593]: closure takes 1 argument but 2 arguments are required
+error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument
   --> $DIR/closure-arg-count.rs:16:15
    |
 16 |     [1, 2, 3].sort_by(|tuple| panic!());
-   |               ^^^^^^^ ---------------- takes 1 argument
+   |               ^^^^^^^ ------- takes 1 argument
    |               |
    |               expected closure that takes 2 arguments
 
@@ -23,23 +23,47 @@ error[E0308]: mismatched types
    = note: expected type `&{integer}`
               found type `(_, _)`
 
-error[E0593]: closure takes 1 argument but 2 arguments are required
+error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument
   --> $DIR/closure-arg-count.rs:17:15
    |
 17 |     [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
-   |               ^^^^^^^ -------------------------- takes 1 argument
+   |               ^^^^^^^ ----------------- takes 1 argument
    |               |
    |               expected closure that takes 2 arguments
 
-error[E0593]: closure takes 0 arguments but 1 argument is required
+error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
   --> $DIR/closure-arg-count.rs:18:5
    |
 18 |     f(|| panic!());
-   |     ^ ----------- takes 0 arguments
+   |     ^ -- takes 0 arguments
    |     |
    |     expected closure that takes 1 argument
    |
    = note: required by `f`
 
-error: aborting due to 5 previous errors
+error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments
+  --> $DIR/closure-arg-count.rs:20:53
+   |
+20 |     let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
+   |                                                     ^^^ ------ help: consider changing the closure to accept a tuple: `|(i, x)|`
+   |                                                     |
+   |                                                     expected closure that takes a single tuple as argument
+
+error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments
+  --> $DIR/closure-arg-count.rs:21:53
+   |
+21 |     let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
+   |                                                     ^^^ ------------- help: consider changing the closure to accept a tuple: `|(i, x): (usize, _)|`
+   |                                                     |
+   |                                                     expected closure that takes a single tuple as argument
+
+error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments
+  --> $DIR/closure-arg-count.rs:22:53
+   |
+22 |     let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
+   |                                                     ^^^ --------- takes 3 distinct arguments
+   |                                                     |
+   |                                                     expected closure that takes a single 2-tuple as argument
+
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions-fn-subtyping-return-static.stderr
index 1598a8a40d2..4a97537223c 100644
--- a/src/test/ui/regions-fn-subtyping-return-static.stderr
+++ b/src/test/ui/regions-fn-subtyping-return-static.stderr
@@ -4,8 +4,8 @@ error[E0308]: mismatched types
 51 |     want_F(bar); //~ ERROR E0308
    |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
    |
-   = note: expected type `fn(&'cx S) -> &'cx S`
-              found type `fn(&'a S) -> &S {bar::<'_>}`
+   = note: expected type `for<'cx> fn(&'cx S) -> &'cx S`
+              found type `for<'a> fn(&'a S) -> &S {bar::<'_>}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/missing-unit-argument.rs b/src/test/ui/span/missing-unit-argument.rs
index 2cdab5bedc4..ba1a999121c 100644
--- a/src/test/ui/span/missing-unit-argument.rs
+++ b/src/test/ui/span/missing-unit-argument.rs
@@ -11,9 +11,17 @@
 fn foo(():(), ():()) {}
 fn bar(():()) {}
 
+struct S;
+impl S {
+    fn baz(self, (): ()) { }
+    fn generic<T>(self, _: T) { }
+}
+
 fn main() {
     let _: Result<(), String> = Ok();
     foo();
     foo(());
     bar();
+    S.baz();
+    S.generic::<()>();
 }
diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr
index e508a30d182..af558d0ab83 100644
--- a/src/test/ui/span/missing-unit-argument.stderr
+++ b/src/test/ui/span/missing-unit-argument.stderr
@@ -1,45 +1,73 @@
 error[E0061]: this function takes 1 parameter but 0 parameters were supplied
-  --> $DIR/missing-unit-argument.rs:15:33
+  --> $DIR/missing-unit-argument.rs:21:33
    |
-15 |     let _: Result<(), String> = Ok();
+21 |     let _: Result<(), String> = Ok();
    |                                 ^^^^
    |
-help: expected the unit value `()`. You can create one with a pair of parenthesis
+help: expected the unit value `()`; create it with empty parentheses
    |
-15 |     let _: Result<(), String> = Ok(());
+21 |     let _: Result<(), String> = Ok(());
    |                                    ^^
 
 error[E0061]: this function takes 2 parameters but 0 parameters were supplied
-  --> $DIR/missing-unit-argument.rs:16:5
+  --> $DIR/missing-unit-argument.rs:22:5
    |
 11 | fn foo(():(), ():()) {}
    | ----------------------- defined here
 ...
-16 |     foo();
+22 |     foo();
    |     ^^^^^ expected 2 parameters
 
 error[E0061]: this function takes 2 parameters but 1 parameter was supplied
-  --> $DIR/missing-unit-argument.rs:17:9
+  --> $DIR/missing-unit-argument.rs:23:9
    |
 11 | fn foo(():(), ():()) {}
    | ----------------------- defined here
 ...
-17 |     foo(());
+23 |     foo(());
    |         ^^ expected 2 parameters
 
 error[E0061]: this function takes 1 parameter but 0 parameters were supplied
-  --> $DIR/missing-unit-argument.rs:18:5
+  --> $DIR/missing-unit-argument.rs:24:5
    |
 12 | fn bar(():()) {}
    | ---------------- defined here
 ...
-18 |     bar();
+24 |     bar();
    |     ^^^^^
    |
-help: expected the unit value `()`. You can create one with a pair of parenthesis
+help: expected the unit value `()`; create it with empty parentheses
    |
-18 |     bar(());
+24 |     bar(());
    |         ^^
 
-error: aborting due to 4 previous errors
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+  --> $DIR/missing-unit-argument.rs:25:7
+   |
+16 |     fn baz(self, (): ()) { }
+   |     ------------------------ defined here
+...
+25 |     S.baz();
+   |       ^^^
+   |
+help: expected the unit value `()`; create it with empty parentheses
+   |
+25 |     S.baz(());
+   |           ^^
+
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+  --> $DIR/missing-unit-argument.rs:26:7
+   |
+17 |     fn generic<T>(self, _: T) { }
+   |     ----------------------------- defined here
+...
+26 |     S.generic::<()>();
+   |       ^^^^^^^
+   |
+help: expected the unit value `()`; create it with empty parentheses
+   |
+26 |     S.generic::<()>(());
+   |                     ^^
+
+error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/struct-field-init-syntax.rs b/src/test/ui/struct-field-init-syntax.rs
new file mode 100644
index 00000000000..8ea62fef9fa
--- /dev/null
+++ b/src/test/ui/struct-field-init-syntax.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+// issue #41834
+
+fn main() {
+    let foo = Foo {
+        one: 111,
+        ..Foo::default(),
+        //~^ ERROR cannot use a comma after struct expansion
+    };
+
+    let foo = Foo {
+        ..Foo::default(),
+        //~^ ERROR cannot use a comma after struct expansion
+        one: 111,
+    };
+}
diff --git a/src/test/ui/struct-field-init-syntax.stderr b/src/test/ui/struct-field-init-syntax.stderr
new file mode 100644
index 00000000000..0bca3f83eb1
--- /dev/null
+++ b/src/test/ui/struct-field-init-syntax.stderr
@@ -0,0 +1,18 @@
+error: cannot use a comma after the base struct
+  --> $DIR/struct-field-init-syntax.rs:18:9
+   |
+18 |         ..Foo::default(),
+   |         ^^^^^^^^^^^^^^^^- help: remove this comma
+   |
+   = note: the base struct must always be the last field
+
+error: cannot use a comma after the base struct
+  --> $DIR/struct-field-init-syntax.rs:23:9
+   |
+23 |         ..Foo::default(),
+   |         ^^^^^^^^^^^^^^^^- help: remove this comma
+   |
+   = note: the base struct must always be the last field
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.rs b/src/test/ui/suggestions/closure-immutable-outer-variable.rs
new file mode 100644
index 00000000000..fe8e2bc6c8e
--- /dev/null
+++ b/src/test/ui/suggestions/closure-immutable-outer-variable.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.
+
+// Point at the captured immutable outer variable
+
+fn foo(mut f: Box<FnMut()>) {
+    f();
+}
+
+fn main() {
+    let y = true;
+    foo(Box::new(move || y = false) as Box<_>);
+}
diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.stderr b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr
new file mode 100644
index 00000000000..19f1cd07171
--- /dev/null
+++ b/src/test/ui/suggestions/closure-immutable-outer-variable.stderr
@@ -0,0 +1,10 @@
+error[E0594]: cannot assign to captured outer variable in an `FnMut` closure
+  --> $DIR/closure-immutable-outer-variable.rs:19:26
+   |
+18 |     let y = true;
+   |         - help: consider making `y` mutable: `mut y`
+19 |     foo(Box::new(move || y = false) as Box<_>);
+   |                          ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/suggestions/suggest-labels.rs b/src/test/ui/suggestions/suggest-labels.rs
new file mode 100644
index 00000000000..5bebce79ecc
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-labels.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[allow(unreachable_code)]
+fn main() {
+    'foo: loop {
+        break 'fo;
+    }
+
+    'bar: loop {
+        continue 'bor;
+    }
+
+    'longlabel: loop {
+        'longlabel1: loop {
+            break 'longlable;
+        }
+    }
+}
diff --git a/src/test/ui/suggestions/suggest-labels.stderr b/src/test/ui/suggestions/suggest-labels.stderr
new file mode 100644
index 00000000000..23aa18a3655
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-labels.stderr
@@ -0,0 +1,20 @@
+error[E0426]: use of undeclared label `'fo`
+  --> $DIR/suggest-labels.rs:14:15
+   |
+14 |         break 'fo;
+   |               ^^^ did you mean `'foo`?
+
+error[E0426]: use of undeclared label `'bor`
+  --> $DIR/suggest-labels.rs:18:18
+   |
+18 |         continue 'bor;
+   |                  ^^^^ did you mean `'bar`?
+
+error[E0426]: use of undeclared label `'longlable`
+  --> $DIR/suggest-labels.rs:23:19
+   |
+23 |             break 'longlable;
+   |                   ^^^^^^^^^^ did you mean `'longlabel1`?
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index db957a7a0fc..8c1b130b116 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -83,6 +83,7 @@ static TARGETS: &'static [&'static str] = &[
     "powerpc64le-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
     "sparc64-unknown-linux-gnu",
+    "sparcv9-sun-solaris",
     "wasm32-unknown-emscripten",
     "x86_64-linux-android",
     "x86_64-apple-darwin",
@@ -90,9 +91,11 @@ static TARGETS: &'static [&'static str] = &[
     "x86_64-pc-windows-gnu",
     "x86_64-pc-windows-msvc",
     "x86_64-rumprun-netbsd",
+    "x86_64-sun-solaris",
     "x86_64-unknown-freebsd",
     "x86_64-unknown-fuchsia",
     "x86_64-unknown-linux-gnu",
+    "x86_64-unknown-linux-gnux32",
     "x86_64-unknown-linux-musl",
     "x86_64-unknown-netbsd",
     "x86_64-unknown-redox",
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject 25444585592f5da648edd5317fcdd21f2db8bb6
+Subproject 281bd790de7b992831a1ff8a589c0fc38c842c9
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index cee7e52c7f3..aa98f818f40 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -201,6 +201,8 @@ pub struct Config {
     pub cc: String,
     pub cxx: String,
     pub cflags: String,
+    pub ar: String,
+    pub linker: Option<String>,
     pub llvm_components: String,
     pub llvm_cxxflags: String,
     pub nodejs: Option<String>,
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index b7fb3670165..251dd4d5edb 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -45,7 +45,7 @@ impl FromStr for ErrorKind {
 impl fmt::Display for ErrorKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ErrorKind::Help => write!(f, "help"),
+            ErrorKind::Help => write!(f, "help message"),
             ErrorKind::Error => write!(f, "error"),
             ErrorKind::Note => write!(f, "note"),
             ErrorKind::Suggestion => write!(f, "suggestion"),
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index bb9bf57d55e..19195838791 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -567,6 +567,19 @@ impl Config {
             None
         }
     }
+
+    pub fn find_rust_src_root(&self) -> Option<PathBuf> {
+        let mut path = self.src_base.clone();
+        let path_postfix = Path::new("src/etc/lldb_batchmode.py");
+
+        while path.pop() {
+            if path.join(&path_postfix).is_file() {
+                return Some(path);
+            }
+        }
+
+        None
+    }
 }
 
 pub fn lldb_version_to_int(version_string: &str) -> isize {
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 26c447d01d3..1701c8a3e43 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -102,6 +102,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
         .reqopt("", "cc", "path to a C compiler", "PATH")
         .reqopt("", "cxx", "path to a C++ compiler", "PATH")
         .reqopt("", "cflags", "flags for the C compiler", "FLAGS")
+        .optopt("", "ar", "path to an archiver", "PATH")
+        .optopt("", "linker", "path to a linker", "PATH")
         .reqopt("", "llvm-components", "list of LLVM components built in", "LIST")
         .reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS")
         .optopt("", "nodejs", "the name of nodejs", "PATH")
@@ -198,6 +200,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
         cc: matches.opt_str("cc").unwrap(),
         cxx: matches.opt_str("cxx").unwrap(),
         cflags: matches.opt_str("cflags").unwrap(),
+        ar: matches.opt_str("ar").unwrap_or("ar".into()),
+        linker: matches.opt_str("linker"),
         llvm_components: matches.opt_str("llvm-components").unwrap(),
         llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
         nodejs: matches.opt_str("nodejs"),
@@ -234,6 +238,8 @@ pub fn log_config(config: &Config) {
     logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
     logv(c, format!("adb_device_status: {}",
                     config.adb_device_status));
+    logv(c, format!("ar: {}", config.ar));
+    logv(c, format!("linker: {:?}", config.linker));
     logv(c, format!("verbose: {}", config.verbose));
     logv(c, format!("quiet: {}", config.quiet));
     logv(c, "\n".to_string());
@@ -489,15 +495,28 @@ fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf {
 }
 
 fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> bool {
+    let rust_src_dir = config.find_rust_src_root().expect(
+        "Could not find Rust source root",
+    );
     let stamp = mtime(&stamp(config, testpaths));
-    let mut inputs = vec![
-        mtime(&testpaths.file),
-        mtime(&config.rustc_path),
-    ];
+    let mut inputs = vec![mtime(&testpaths.file), mtime(&config.rustc_path)];
     for aux in props.aux.iter() {
-        inputs.push(mtime(&testpaths.file.parent().unwrap()
-                                         .join("auxiliary")
-                                         .join(aux)));
+        inputs.push(mtime(
+            &testpaths.file.parent().unwrap().join("auxiliary").join(
+                aux,
+            ),
+        ));
+    }
+    // Relevant pretty printer files
+    let pretty_printer_files = [
+        "src/etc/debugger_pretty_printers_common.py",
+        "src/etc/gdb_load_rust_pretty_printers.py",
+        "src/etc/gdb_rust_pretty_printing.py",
+        "src/etc/lldb_batchmode.py",
+        "src/etc/lldb_rust_formatters.py",
+    ];
+    for pretty_printer_file in &pretty_printer_files {
+        inputs.push(mtime(&rust_src_dir.join(pretty_printer_file)));
     }
     for lib in config.run_lib_path.read_dir().unwrap() {
         let lib = lib.unwrap();
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 10ef326d9db..0473c2a5405 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -25,6 +25,7 @@ use std::collections::HashSet;
 use std::env;
 use std::ffi::OsString;
 use std::fs::{self, File, create_dir_all};
+use std::fmt;
 use std::io::prelude::*;
 use std::io::{self, BufReader};
 use std::path::{Path, PathBuf};
@@ -571,9 +572,10 @@ actual:\n\
                 }
             }
 
-            _=> {
-                let rust_src_root = self.find_rust_src_root()
-                                        .expect("Could not find Rust source root");
+            _ => {
+                let rust_src_root = self.config.find_rust_src_root().expect(
+                    "Could not find Rust source root",
+                );
                 let rust_pp_module_rel_path = Path::new("./src/etc");
                 let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
                                                            .to_str()
@@ -664,19 +666,6 @@ actual:\n\
         self.check_debugger_output(&debugger_run_result, &check_lines);
     }
 
-    fn find_rust_src_root(&self) -> Option<PathBuf> {
-        let mut path = self.config.src_base.clone();
-        let path_postfix = Path::new("src/etc/lldb_batchmode.py");
-
-        while path.pop() {
-            if path.join(&path_postfix).is_file() {
-                return Some(path);
-            }
-        }
-
-        None
-    }
-
     fn run_debuginfo_lldb_test(&self) {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
@@ -735,7 +724,9 @@ actual:\n\
         script_str.push_str("version\n");
 
         // Switch LLDB into "Rust mode"
-        let rust_src_root = self.find_rust_src_root().expect("Could not find Rust source root");
+        let rust_src_root = self.config.find_rust_src_root().expect(
+            "Could not find Rust source root",
+        );
         let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
         let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
                                                    .to_str()
@@ -1050,7 +1041,7 @@ actual:\n\
                 None => {
                     if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) {
                         self.error(
-                            &format!("{}:{}: unexpected {:?}: '{}'",
+                            &format!("{}:{}: unexpected {}: '{}'",
                                      file_name,
                                      actual_error.line_num,
                                      actual_error.kind.as_ref()
@@ -1164,6 +1155,9 @@ actual:\n\
             .arg("-o").arg(out_dir)
             .arg(&self.testpaths.file)
             .args(&self.props.compile_flags);
+        if let Some(ref linker) = self.config.linker {
+            rustdoc.arg("--linker").arg(linker).arg("-Z").arg("unstable-options");
+        }
 
         self.compose_and_run_compiler(rustdoc, None)
     }
@@ -1450,6 +1444,9 @@ actual:\n\
         } else {
             rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
         }
+        if let Some(ref linker) = self.config.linker {
+            rustc.arg(format!("-Clinker={}", linker));
+        }
 
         rustc.args(&self.props.compile_flags);
 
@@ -1717,11 +1714,13 @@ actual:\n\
         if self.props.check_test_line_numbers_match {
             self.check_rustdoc_test_option(proc_res);
         } else {
-            let root = self.find_rust_src_root().unwrap();
-            let res = self.cmd2procres(Command::new(&self.config.docck_python)
-                                       .arg(root.join("src/etc/htmldocck.py"))
-                                       .arg(out_dir)
-                                       .arg(&self.testpaths.file));
+            let root = self.config.find_rust_src_root().unwrap();
+            let res = self.cmd2procres(
+                Command::new(&self.config.docck_python)
+                    .arg(root.join("src/etc/htmldocck.py"))
+                    .arg(out_dir)
+                    .arg(&self.testpaths.file),
+            );
             if !res.status.success() {
                 self.fatal_proc_rec("htmldocck failed!", &res);
             }
@@ -2036,7 +2035,6 @@ actual:\n\
         // Add an extra flag pointing at the incremental directory.
         let mut revision_props = self.props.clone();
         revision_props.incremental_dir = Some(incremental_dir);
-        revision_props.compile_flags.push(String::from("-Zincremental-info"));
 
         let revision_cx = TestCx {
             config: self.config,
@@ -2109,6 +2107,10 @@ actual:\n\
            .env("LLVM_COMPONENTS", &self.config.llvm_components)
            .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags);
 
+        if let Some(ref linker) = self.config.linker {
+            cmd.env("RUSTC_LINKER", linker);
+        }
+
         // We don't want RUSTFLAGS set from the outside to interfere with
         // compiler flags set in the test cases:
         cmd.env_remove("RUSTFLAGS");
@@ -2131,7 +2133,8 @@ actual:\n\
                .env("CXX", &self.config.cxx);
         } else {
             cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
-               .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags));
+               .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
+               .env("AR", &self.config.ar);
 
             if self.config.target.contains("windows") {
                 cmd.env("IS_WINDOWS", "1");
@@ -2237,7 +2240,7 @@ actual:\n\
             let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
             let tests_text_str = String::from(tests_text);
             let mut curr_test : Option<&str> = None;
-            let mut curr_test_contents = Vec::new();
+            let mut curr_test_contents = vec![ExpectedLine::Elision];
             for l in tests_text_str.lines() {
                 debug!("line: {:?}", l);
                 if l.starts_with("// START ") {
@@ -2251,11 +2254,14 @@ actual:\n\
                     self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
                     curr_test = None;
                     curr_test_contents.clear();
+                    curr_test_contents.push(ExpectedLine::Elision);
                 } else if l.is_empty() {
                     // ignore
+                } else if l.starts_with("//") && l.split_at("//".len()).1.trim() == "..." {
+                    curr_test_contents.push(ExpectedLine::Elision)
                 } else if l.starts_with("// ") {
                     let (_, test_content) = l.split_at("// ".len());
-                    curr_test_contents.push(test_content);
+                    curr_test_contents.push(ExpectedLine::Text(test_content));
                 }
             }
         }
@@ -2273,7 +2279,7 @@ actual:\n\
         }
     }
 
-    fn compare_mir_test_output(&self, test_name: &str, expected_content: &[&str]) {
+    fn compare_mir_test_output(&self, test_name: &str, expected_content: &[ExpectedLine<&str>]) {
         let mut output_file = PathBuf::new();
         output_file.push(self.get_mir_dump_dir());
         output_file.push(test_name);
@@ -2285,38 +2291,77 @@ actual:\n\
         let mut dumped_string = String::new();
         dumped_file.read_to_string(&mut dumped_string).unwrap();
         let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty());
-        let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty());
+        let mut expected_lines = expected_content.iter().filter(|&l| {
+            if let &ExpectedLine::Text(l) = l {
+                !l.is_empty()
+            } else {
+                true
+            }
+        }).peekable();
 
-        // We expect each non-empty line from expected_content to appear
-        // in the dump in order, but there may be extra lines interleaved
-        while let Some(expected_line) = expected_lines.next() {
+        let compare = |expected_line, dumped_line| {
             let e_norm = normalize_mir_line(expected_line);
-            if e_norm.is_empty() {
-                continue;
+            let d_norm = normalize_mir_line(dumped_line);
+            debug!("found: {:?}", d_norm);
+            debug!("expected: {:?}", e_norm);
+            e_norm == d_norm
+        };
+
+        let error = |expected_line, extra_msg| {
+            let normalize_all = dumped_string.lines()
+                                             .map(nocomment_mir_line)
+                                             .filter(|l| !l.is_empty())
+                                             .collect::<Vec<_>>()
+                                             .join("\n");
+            let f = |l: &ExpectedLine<_>| match l {
+                &ExpectedLine::Elision => "... (elided)".into(),
+                &ExpectedLine::Text(t) => t
             };
-            let mut found = false;
-            while let Some(dumped_line) = dumped_lines.next() {
-                let d_norm = normalize_mir_line(dumped_line);
-                debug!("found: {:?}", d_norm);
-                debug!("expected: {:?}", e_norm);
-                if e_norm == d_norm {
-                    found = true;
-                    break;
-                };
-            }
-            if !found {
-                let normalize_all = dumped_string.lines()
-                                                 .map(nocomment_mir_line)
-                                                 .filter(|l| !l.is_empty())
-                                                 .collect::<Vec<_>>()
-                                                 .join("\n");
-                panic!("ran out of mir dump output to match against.\n\
-                        Did not find expected line: {:?}\n\
-                        Expected:\n{}\n\
-                        Actual:\n{}",
-                        expected_line,
-                        expected_content.join("\n"),
-                        normalize_all);
+            let expected_content = expected_content.iter()
+                                                   .map(|l| f(l))
+                                                   .collect::<Vec<_>>()
+                                                   .join("\n");
+            panic!("Did not find expected line, error: {}\n\
+                   Actual Line: {:?}\n\
+                   Expected:\n{}\n\
+                   Actual:\n{}",
+                   extra_msg,
+                   expected_line,
+                   expected_content,
+                   normalize_all);
+        };
+
+        // We expect each non-empty line to appear consecutively, non-consecutive lines
+        // must be separated by at least one Elision
+        while let Some(dumped_line) = dumped_lines.next() {
+            match expected_lines.next() {
+                Some(&ExpectedLine::Text(expected_line)) =>
+                    if !compare(expected_line, dumped_line) {
+                        error(expected_line,
+                              format!("Mismatch in lines\nExpected Line: {:?}", dumped_line));
+                    },
+                Some(&ExpectedLine::Elision) => {
+                    // skip any number of elisions in a row.
+                    while let Some(&&ExpectedLine::Elision) = expected_lines.peek() {
+                        expected_lines.next();
+                    }
+                    if let Some(&ExpectedLine::Text(expected_line)) = expected_lines.next() {
+                        let mut found = compare(expected_line, dumped_line);
+                        if found {
+                            continue;
+                        }
+                        while let Some(dumped_line) = dumped_lines.next() {
+                            found = compare(expected_line, dumped_line);
+                            if found {
+                                break;
+                            }
+                        }
+                        if !found {
+                            error(expected_line, "ran out of mir dump to match against".into());
+                        }
+                    }
+                },
+                None => {},
             }
         }
     }
@@ -2333,8 +2378,15 @@ actual:\n\
 
     fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
         let parent_dir = self.testpaths.file.parent().unwrap();
-        let parent_dir_str = parent_dir.display().to_string();
+        let cflags = self.props.compile_flags.join(" ");
+        let parent_dir_str = if cflags.contains("--error-format json") {
+            parent_dir.display().to_string().replace("\\", "\\\\")
+        } else {
+            parent_dir.display().to_string()
+        };
+
         let mut normalized = output.replace(&parent_dir_str, "$DIR")
+              .replace("\\\\", "\\") // denormalize for paths on windows
               .replace("\\", "/") // normalize for paths on windows
               .replace("\r\n", "\n") // normalize for linebreaks on windows
               .replace("\t", "\\t"); // makes tabs visible
@@ -2439,6 +2491,25 @@ enum TargetLocation {
     ThisDirectory(PathBuf),
 }
 
+#[derive(Clone, PartialEq, Eq)]
+enum ExpectedLine<T: AsRef<str>> {
+    Elision,
+    Text(T)
+}
+
+impl<T> fmt::Debug for ExpectedLine<T>
+where
+    T: AsRef<str> + fmt::Debug
+{
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        if let &ExpectedLine::Text(ref t) = self {
+            write!(formatter, "{:?}", t)
+        } else {
+            write!(formatter, "\"...\" (Elision)")
+        }
+    }
+}
+
 fn normalize_mir_line(line: &str) -> String {
     nocomment_mir_line(line).replace(char::is_whitespace, "")
 }
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 85fa38bbd3b..bd4044b4df3 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -73,7 +73,7 @@ pub fn get_env(triple: &str) -> Option<&str> {
 }
 
 pub fn get_pointer_width(triple: &str) -> &'static str {
-    if triple.contains("64") || triple.starts_with("s390x") {
+    if (triple.contains("64") && !triple.ends_with("gnux32")) || triple.starts_with("s390x") {
         "64bit"
     } else {
         "32bit"
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 90bf7a5e0a6..c316ec46762 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -33,10 +33,9 @@ macro_rules! t {
 
 macro_rules! tidy_error {
     ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
-        use std::io::Write;
         *$bad = true;
-        write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr");
-        writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr");
+        eprint!("tidy error: ");
+        eprintln!($fmt, $($arg)*);
     });
 }
 
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 433192a21ec..f6640c902bc 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -22,7 +22,6 @@ use tidy::*;
 use std::process;
 use std::path::PathBuf;
 use std::env;
-use std::io::{self, Write};
 
 fn main() {
     let path = env::args_os().skip(1).next().expect("need an argument");
@@ -44,7 +43,7 @@ fn main() {
     }
 
     if bad {
-        writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr");
+        eprintln!("some tidy checks failed");
         process::exit(1);
     }
 }
diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml
index 1700daa0aff..9dd420c1458 100644
--- a/src/tools/toolstate.toml
+++ b/src/tools/toolstate.toml
@@ -3,7 +3,7 @@
 #
 # There are three states a tool can be in:
 # 1. Broken: The tool doesn't build
-# 2. Building: The tool builds but its tests are failing
+# 2. Compiling: The tool builds but its tests are failing
 # 3. Testing: The tool builds and its tests are passing
 #
 # In the future there will be further states like "Distributing", which
@@ -29,8 +29,7 @@ miri = "Broken"
 clippy = "Broken"
 
 # ping @nrc
-rls = "Testing"
+rls = "Broken"
 
 # ping @nrc
-rustfmt = "Testing"
-
+rustfmt = "Broken"