about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--RELEASES.md12
-rw-r--r--config.toml.example20
-rw-r--r--src/Cargo.lock47
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/README.md4
-rw-r--r--src/bootstrap/bin/rustc.rs20
-rw-r--r--src/bootstrap/bin/rustdoc.rs11
-rw-r--r--src/bootstrap/bootstrap.py3
-rw-r--r--src/bootstrap/builder.rs58
-rw-r--r--src/bootstrap/cc_detect.rs52
-rw-r--r--src/bootstrap/check.rs38
-rw-r--r--src/bootstrap/compile.rs3
-rw-r--r--src/bootstrap/config.rs11
-rwxr-xr-xsrc/bootstrap/configure.py64
-rw-r--r--src/bootstrap/dist.rs198
-rw-r--r--src/bootstrap/lib.rs38
-rw-r--r--src/bootstrap/native.rs64
-rw-r--r--src/bootstrap/tool.rs6
-rw-r--r--src/bootstrap/toolstate.rs7
-rw-r--r--src/build_helper/lib.rs21
-rw-r--r--src/ci/docker/cross2/Dockerfile14
-rwxr-xr-xsrc/ci/docker/cross2/build-solaris-toolchain.sh22
-rw-r--r--src/ci/docker/scripts/android-sdk.sh2
-rw-r--r--src/doc/man/rustc.13
-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/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/boxed.rs44
-rw-r--r--src/liballoc/lib.rs1
-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/libcore/iter/iterator.rs186
-rw-r--r--src/libcore/mem.rs10
-rw-r--r--src/libcore/str/mod.rs13
-rw-r--r--src/libcore/tests/mem.rs16
-rw-r--r--src/libproc_macro/lib.rs2
-rw-r--r--src/libprofiler_builtins/Cargo.toml2
-rw-r--r--src/librustc/dep_graph/dep_node.rs4
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/hir/itemlikevisit.rs2
-rw-r--r--src/librustc/hir/lowering.rs2
-rw-r--r--src/librustc/ich/impls_ty.rs129
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/lint/builtin.rs9
-rw-r--r--src/librustc/middle/borrowck.rs31
-rw-r--r--src/librustc/middle/reachable.rs6
-rw-r--r--src/librustc/mir/mod.rs21
-rw-r--r--src/librustc/session/config.rs53
-rw-r--r--src/librustc/session/mod.rs91
-rw-r--r--src/librustc/traits/error_reporting.rs215
-rw-r--r--src/librustc/traits/mod.rs94
-rw-r--r--src/librustc/traits/trans/mod.rs138
-rw-r--r--src/librustc/ty/context.rs6
-rw-r--r--src/librustc/ty/instance.rs3
-rw-r--r--src/librustc/ty/maps/config.rs12
-rw-r--r--src/librustc/ty/maps/keys.rs18
-rw-r--r--src/librustc/ty/maps/mod.rs20
-rw-r--r--src/librustc/ty/maps/plumbing.rs202
-rw-r--r--src/librustc/util/ppaux.rs1757
-rw-r--r--src/librustc_back/build.rs1
-rw-r--r--src/librustc_back/target/asmjs_unknown_emscripten.rs1
-rw-r--r--src/librustc_back/target/mod.rs12
-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/check_loans.rs3
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs6
-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.rs469
-rw-r--r--src/librustc_borrowck/lib.rs10
-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_driver/lib.rs3
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs421
-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_lint/Cargo.toml1
-rw-r--r--src/librustc_lint/lib.rs2
-rw-r--r--src/librustc_lint/unused.rs89
-rw-r--r--src/librustc_llvm/Cargo.toml2
-rw-r--r--src/librustc_mir/borrow_check.rs277
-rw-r--r--src/librustc_mir/build/matches/mod.rs29
-rw-r--r--src/librustc_mir/build/mod.rs4
-rw-r--r--src/librustc_mir/diagnostics.rs461
-rw-r--r--src/librustc_mir/transform/dump_mir.rs13
-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/util/borrowck_errors.rs133
-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_resolve/diagnostics.rs6
-rw-r--r--src/librustc_resolve/lib.rs36
-rw-r--r--src/librustc_save_analysis/sig.rs2
-rw-r--r--src/librustc_trans/Cargo.toml2
-rw-r--r--src/librustc_trans/back/archive.rs7
-rw-r--r--src/librustc_trans/back/link.rs2
-rw-r--r--src/librustc_trans/back/lto.rs20
-rw-r--r--src/librustc_trans/back/symbol_names.rs54
-rw-r--r--src/librustc_trans/back/write.rs42
-rw-r--r--src/librustc_trans/base.rs2
-rw-r--r--src/librustc_trans/callee.rs7
-rw-r--r--src/librustc_trans/collector.rs10
-rw-r--r--src/librustc_trans/declare.rs5
-rw-r--r--src/librustc_trans/meth.rs4
-rw-r--r--src/librustc_trans/monomorphize.rs9
-rw-r--r--src/librustc_trans/partitioning.rs136
-rw-r--r--src/librustc_trans/trans_item.rs61
-rw-r--r--src/librustc_typeck/astconv.rs12
-rw-r--r--src/librustc_typeck/check/callee.rs3
-rw-r--r--src/librustc_typeck/check/method/mod.rs9
-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.rs43
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs14
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustc_typeck/namespace.rs39
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/mod.rs17
-rw-r--r--src/librustdoc/externalfiles.rs9
-rw-r--r--src/librustdoc/html/layout.rs4
-rw-r--r--src/librustdoc/html/render.rs68
-rw-r--r--src/librustdoc/html/static/main.js167
-rw-r--r--src/librustdoc/html/static/rustdoc.css53
-rw-r--r--src/librustdoc/html/static/styles/main.css4
-rw-r--r--src/librustdoc/lib.rs14
-rw-r--r--src/librustdoc/markdown.rs18
-rw-r--r--src/librustdoc/test.rs101
-rw-r--r--src/libstd/Cargo.toml1
-rw-r--r--src/libstd/build.rs12
-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.rs51
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/net/tcp.rs15
-rw-r--r--src/libstd/process.rs122
-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/rwlock.rs13
-rw-r--r--src/libstd/sys/unix/net.rs13
-rw-r--r--src/libstd/sys/windows/ext/ffi.rs56
-rw-r--r--src/libstd/sys_common/remutex.rs13
-rw-r--r--src/libstd/thread/mod.rs12
-rw-r--r--src/libsyntax/ast.rs9
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs2
-rw-r--r--src/libsyntax/parse/parser.rs97
-rw-r--r--src/libsyntax/parse/token.rs6
-rw-r--r--src/libsyntax/print/pprust.rs5
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/libsyntax_pos/lib.rs7
-rw-r--r--src/libsyntax_pos/symbol.rs9
m---------src/llvm0
-rw-r--r--src/rustc/compiler_builtins_shim/Cargo.toml2
-rw-r--r--src/rustllvm/PassWrapper.cpp13
-rw-r--r--src/rustllvm/RustWrapper.cpp2
-rw-r--r--src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs1
-rw-r--r--src/test/codegen-units/item-collection/generic-drop-glue.rs1
-rw-r--r--src/test/codegen-units/item-collection/instantiation-through-vtable.rs1
-rw-r--r--src/test/codegen-units/item-collection/non-generic-drop-glue.rs1
-rw-r--r--src/test/codegen-units/item-collection/transitive-drop-glue.rs1
-rw-r--r--src/test/codegen-units/item-collection/tuple-drop-glue.rs1
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs1
-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/auxiliary/nounwind.rs13
-rw-r--r--src/test/codegen/float_math.rs2
-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-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-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/dyn-trait-compatibility.rs29
-rw-r--r--src/test/compile-fail/feature-gate-dyn-trait.rs14
-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/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.rs230
-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.rs7
-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.rs17
-rw-r--r--src/test/mir-opt/validate_5.rs7
-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/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/Makefile3
-rw-r--r--src/test/run-make/sepcomp-inlining/Makefile3
-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/backtrace-debuginfo.rs4
-rw-r--r--src/test/run-pass/dyn-trait.rs24
-rw-r--r--src/test/run-pass/issue-35600.rs24
-rw-r--r--src/test/run-pass/issue-44247.rs27
-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/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/thin-lto-inlines-aux.rs (renamed from src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs)0
-rw-r--r--src/test/run-pass/thinlto/dylib-works.rs18
-rw-r--r--src/test/run-pass/thinlto/thin-lto-inlines.rs (renamed from src/test/run-pass/thin-lto-inlines.rs)0
-rw-r--r--src/test/run-pass/thinlto/thin-lto-inlines2.rs (renamed from src/test/run-pass/thin-lto-inlines2.rs)0
-rw-r--r--src/test/rustdoc/crate-version.rs13
-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-44406.rs19
-rw-r--r--src/test/ui/issue-44406.stderr26
-rw-r--r--src/test/ui/lint/suggestions.stderr28
-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.rs1
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.rs178
m---------src/tools/rustfmt13
-rw-r--r--src/tools/tidy/src/lib.rs5
-rw-r--r--src/tools/tidy/src/main.rs3
-rw-r--r--src/tools/toolstate.toml5
341 files changed, 8896 insertions, 3971 deletions
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..f50543e18a7 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -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 77e33855f23..328ce353e2a 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -42,7 +42,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 +99,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)",
 ]
 
@@ -136,7 +136,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)",
@@ -199,7 +199,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.7 (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)",
@@ -246,7 +246,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]]
@@ -275,7 +275,7 @@ name = "cmake"
 version = "0.1.26"
 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)",
 ]
 
 [[package]]
@@ -290,7 +290,7 @@ dependencies = [
 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",
 ]
 
@@ -407,7 +407,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)",
@@ -759,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "jobserver"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -833,7 +833,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)",
@@ -860,7 +860,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)",
@@ -880,7 +880,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)",
@@ -968,7 +968,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)",
 ]
 
@@ -1104,7 +1104,7 @@ 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)",
@@ -1208,7 +1208,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",
 ]
 
@@ -1429,7 +1429,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.7 (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",
@@ -1504,6 +1504,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",
@@ -1611,7 +1612,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",
@@ -1623,7 +1623,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",
 ]
 
@@ -1755,9 +1755,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.7 (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)",
@@ -1824,7 +1824,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)",
@@ -1994,7 +1994,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",
@@ -2485,7 +2484,7 @@ 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 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"
@@ -2530,7 +2529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "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 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.7 (registry+https://github.com/rust-lang/crates.io-index)" = "094f87ed101b6832def8632f43db43dc204d27897eb95aca69b26ce2e4011e84"
 "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"
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..6eb074605fc 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,7 +126,7 @@ 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
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index 848b10d312c..aeeda85e924 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)
@@ -258,6 +251,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 +268,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 fecb8e6a05e..842144ff1ea 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -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():
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index e7a5196178c..6480b5a619c 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
     }
 
@@ -481,8 +484,14 @@ 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(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 +565,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 +601,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
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..d9ee63eef8c 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");
@@ -358,6 +364,7 @@ impl Step for Miri {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Clippy {
+    stage: u32,
     host: Interned<String>,
 }
 
@@ -372,6 +379,7 @@ impl Step for Clippy {
 
     fn make_run(run: RunConfig) {
         run.builder.ensure(Clippy {
+            stage: run.builder.top_stage,
             host: run.target,
         });
     }
@@ -379,10 +387,11 @@ 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 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"));
 
@@ -390,6 +399,8 @@ impl Step for Clippy {
         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);
 
@@ -736,12 +747,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 +808,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 +836,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..b1c630a8de9 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -560,9 +560,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)]
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index c8b2ed042c1..69e0f58f1cd 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -88,7 +88,6 @@ pub struct Config {
     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>,
@@ -464,7 +466,6 @@ 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 {
@@ -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 3c161b7bb14..42425a164a2 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -20,6 +20,7 @@ rust_dir = os.path.dirname(rust_dir)
 sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))
 import bootstrap
 
+
 class Option(object):
     def __init__(self, name, rustbuild, desc, value):
         self.name = name
@@ -27,14 +28,18 @@ class Option(object):
         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")
@@ -120,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).
@@ -137,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('')
@@ -209,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
@@ -228,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
@@ -346,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):
@@ -361,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:
@@ -376,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:
@@ -408,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..02dfa04d920 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");
@@ -1035,7 +1035,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 +1050,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");
@@ -1102,7 +1107,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 +1207,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 +1254,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 +1295,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 +1321,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 +1333,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 +1424,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 +1469,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 +1516,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/lib.rs b/src/bootstrap/lib.rs
index 2d721f45578..6ac919d3fbd 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,
@@ -612,7 +614,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 +622,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 +646,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 +659,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..941ea96bbec 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);
@@ -352,34 +359,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..662c56d728d 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -387,7 +387,7 @@ pub struct Clippy {
 
 impl Step for Clippy {
     type Output = PathBuf;
-    const DEFAULT: bool = false;
+    const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun) -> ShouldRun {
@@ -411,7 +411,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),
@@ -561,7 +561,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/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/cross2/Dockerfile b/src/ci/docker/cross2/Dockerfile
index f5fc06767ce..cc260382f49 100644
--- a/src/ci/docker/cross2/Dockerfile
+++ b/src/ci/docker/cross2/Dockerfile
@@ -5,6 +5,7 @@ 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 \
@@ -36,17 +37,18 @@ ENV \
     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.11-ar \
-    CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-gcc \
-    CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.11-g++ \
-    AR_x86_64_sun_solaris=x86_64-sun-solaris2.11-ar \
-    CC_x86_64_sun_solaris=x86_64-sun-solaris2.11-gcc \
-    CXX_x86_64_sun_solaris=x86_64-sun-solaris2.11-g++
+    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/cross2/build-solaris-toolchain.sh b/src/ci/docker/cross2/build-solaris-toolchain.sh
index ae84cc62b60..935cbe5d61b 100755
--- a/src/ci/docker/cross2/build-solaris-toolchain.sh
+++ b/src/ci/docker/cross2/build-solaris-toolchain.sh
@@ -25,7 +25,7 @@ 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.11
+hide_output ../binutils-$BINUTILS/configure --target=$ARCH-sun-solaris2.10
 hide_output make -j10
 hide_output make install
 
@@ -58,13 +58,17 @@ for deb in *$APT_ARCH.deb; do
   dpkg -x $deb .
 done
 
-mkdir                  /usr/local/$ARCH-sun-solaris2.11/usr
-mv usr/include         /usr/local/$ARCH-sun-solaris2.11/usr/include
-mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib
-mv     lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.11/lib
+# Strip Solaris 11 functions that are optionally used by libbacktrace.
+# This is for Solaris 10 compatibility.
+$ARCH-sun-solaris2.10-strip -N dl_iterate_phdr -N strnlen lib/$LIB_ARCH/libc.so
 
-ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/sys-include
-ln -s /usr/local/$ARCH-sun-solaris2.11/usr/include /usr/local/$ARCH-sun-solaris2.11/include
+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/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/sys-include
+ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/include
 
 cd ..
 rm -rf solaris
@@ -80,7 +84,7 @@ mkdir ../gcc-build
 cd ../gcc-build
 hide_output ../gcc-$GCC/configure \
   --enable-languages=c,c++        \
-  --target=$ARCH-sun-solaris2.11  \
+  --target=$ARCH-sun-solaris2.10  \
   --with-gnu-as                   \
   --with-gnu-ld                   \
   --disable-multilib              \
@@ -94,7 +98,7 @@ hide_output ../gcc-$GCC/configure \
   --disable-libsanitizer          \
   --disable-libquadmath-support   \
   --disable-lto                   \
-  --with-sysroot=/usr/local/$ARCH-sun-solaris2.11
+  --with-sysroot=/usr/local/$ARCH-sun-solaris2.10
 
 hide_output make -j10
 hide_output make install
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/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/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/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/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/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/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/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/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/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/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/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/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 1ecbc62225e..4600cdbc692 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;
@@ -505,6 +505,8 @@ define_dep_nodes!( <'tcx>
     [] 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>> },
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 8d2cf676849..690db8a5522 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -19,7 +19,7 @@ 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::prev::PreviousDepGraph;
 pub use self::query::DepGraphQuery;
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 64a2ba1fa6f..54aecb4b00f 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -705,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 {
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index fe060aaf426..f719ce15092 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);
@@ -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/lib.rs b/src/librustc/lib.rs
index 015dbbb7aff..ed440849b48 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -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/reachable.rs b/src/librustc/middle/reachable.rs
index 55d0c6b4c66..bb6213cb5fa 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -336,6 +336,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/mir/mod.rs b/src/librustc/mir/mod.rs
index 075a629de04..0159a198bc6 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -415,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)]
@@ -551,7 +553,7 @@ pub struct UpvarDecl {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlock
 
-newtype_index!(BasicBlock, "bb");
+newtype_index!(BasicBlock { DEBUG_NAME = "bb" });
 
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlockData and Terminator
@@ -1131,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> {
@@ -1196,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 {
@@ -1522,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 8b35b064eb3..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],
     }
 );
 
@@ -505,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,
     }
 }
 
@@ -864,8 +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 (has no effect currently, \
-         rustc doesn't use an external archiver)"),
+        "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],
@@ -1100,6 +1099,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "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 {
@@ -1709,48 +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 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
-            //
-            // Another note worth mentioning here, however, is that this number
-            // isn't *too* high. When codegen units are increased that means we
-            // currently have to codegen `#[inline]` functions into each codegen
-            // unit, which means the more codegen units we're using the more we
-            // may be generating. In other words, increasing codegen units may
-            // increase the overall work the compiler does. If we don't have
-            // enough cores to make up for this loss then increasing the number
-            // of codegen units could become an overall loss!
-            //
-            // As a result we choose a hopefully conservative value 16, which
-            // should be more than the number of cpus of most hardware compiling
-            // Rust but also not too much for 2-4 core machines to have too much
-            // loss of compile time.
-            OptLevel::No => 16,
-
-            // 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,
@@ -1775,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/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/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/trans/mod.rs b/src/librustc/traits/trans/mod.rs
index 947e7117c4e..aa3179dd01f 100644
--- a/src/librustc/traits/trans/mod.rs
+++ b/src/librustc/traits/trans/mod.rs
@@ -17,85 +17,77 @@ use dep_graph::{DepGraph, DepKind, DepTrackingMap, 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,
@@ -149,14 +141,12 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
 /// 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)),
         }
     }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 740299b91f1..24ba38cf147 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -898,11 +898,6 @@ pub struct GlobalCtxt<'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>,
@@ -1185,7 +1180,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             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()),
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/config.rs b/src/librustc/ty/maps/config.rs
index c8520c5be2d..137039598a5 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -221,6 +221,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,6 +503,12 @@ 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")
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..58405c261ad 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,6 +31,7 @@ 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};
@@ -182,7 +184,7 @@ define_maps! { <'tcx>
 
     [] 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) -> (),
 
@@ -227,7 +229,11 @@ define_maps! { <'tcx>
     [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
     [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> 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,
@@ -347,6 +353,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 +473,7 @@ 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 }
+}
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index 88b619558d9..d6eaf6d1bc4 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -344,6 +344,52 @@ 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());
+                use dep_graph::DepNodeColor;
+                match tcx.dep_graph.node_color(&dep_node) {
+                    Some(DepNodeColor::Green(dep_node_index)) => {
+                        tcx.dep_graph.read_index(dep_node_index);
+                    }
+                    Some(DepNodeColor::Red) => {
+                        // A DepNodeColor::Red DepNode means that this query was executed
+                        // before. We can not call `dep_graph.read()` here as we don't have
+                        // the DepNodeIndex. Instead, We call the query again to issue the
+                        // appropriate `dep_graph.read()` call. The performance cost this
+                        // introduces should be negligible as we'll immediately hit the
+                        // in-memory cache.
+                        let _ = tcx.$name(key);
+                    }
+                    None => {
+                        // Huh
+                        if !tcx.dep_graph.is_fully_enabled() {
+                            let _ = tcx.$name(key);
+                            return;
+                        }
+                        match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
+                            Some(dep_node_index) => {
+                                debug_assert!(tcx.dep_graph.is_green(dep_node_index));
+                                tcx.dep_graph.read_index(dep_node_index);
+                            }
+                            None => {
+                                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 +514,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 +525,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 +552,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 +681,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 +699,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TypeParamPredicates |
         DepKind::CodegenUnit |
         DepKind::CompileCodegenUnit |
+        DepKind::FulfillObligation |
+        DepKind::VtableMethods |
 
         // These are just odd
         DepKind::Null |
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/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/mod.rs b/src/librustc_back/target/mod.rs
index 039e0153656..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),
@@ -268,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.
@@ -430,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 {
@@ -439,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(),
@@ -492,6 +493,7 @@ impl Default for TargetOptions {
             crt_static_respected: false,
             stack_probes: false,
             min_global_align: None,
+            default_codegen_units: None,
         }
     }
 }
@@ -680,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);
@@ -732,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()) {
@@ -872,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);
@@ -924,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/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index fea662e21fa..6ce5afd4bf1 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -770,7 +770,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..1827ddabe4e 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -442,13 +442,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/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 031dbcb1ebb..3fea01443be 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -9,472 +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);
-}
-```
-"##,
-
-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_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..6c5a37aa1e5 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(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_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 0270e3618e2..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.
@@ -40,9 +40,12 @@
 //!
 
 use std::collections::HashSet;
+use std::iter::FromIterator;
 use std::vec::Vec;
-use rustc::dep_graph::DepNode;
+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;
@@ -53,11 +56,183 @@ 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
     if !tcx.sess.features.borrow().rustc_attrs {
@@ -91,14 +266,189 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
 }
 
 impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
-    fn labels(&self, attr: &Attribute) -> Labels {
+
+    /// 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);
+                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());
             }
         }
-        self.tcx.sess.span_fatal(attr.span, "no `label` found");
+        // 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 {
@@ -174,22 +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);
-                    let labels = self.labels(attr);
-                    for dep_node in self.dep_nodes(&labels, def_id) {
-                        self.assert_dirty(item_span, dep_node);
-                    }
-                }
-            } else if attr.check_name(ATTR_CLEAN) {
-                if check_config(self.tcx, attr) {
-                    self.checked_attrs.insert(attr.id);
-                    let labels = self.labels(attr);
-                    for dep_node in self.dep_nodes(&labels, def_id) {
-                        self.assert_clean(item_span, dep_node);
-                    }
-                }
+            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);
             }
         }
     }
@@ -363,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_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/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/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_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs
index db6a0ee4ba5..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};
@@ -586,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;
@@ -611,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.
@@ -642,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>
     {
@@ -664,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),
         }
@@ -733,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,
@@ -846,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)
@@ -1080,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);
@@ -1131,6 +1232,77 @@ 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.source_info(borrow.location).span
@@ -1266,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/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/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 645af0bff64..98c5345c69d 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,104 @@ 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.
+
+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 };
+```
+"##,
+
 E0384: r##"
 This error occurs when an attempt is made to reassign an immutable variable.
 For example:
@@ -272,6 +421,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.
@@ -1265,12 +1569,169 @@ fn main() {
 ```
 "##,
 
+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/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/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 37d53ca829e..216f6e44570 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -294,6 +294,139 @@ pub trait BorrowckErrors {
         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_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..4aab43cbec7 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 => {
@@ -1790,9 +1794,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 +1816,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
@@ -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/sig.rs b/src/librustc_save_analysis/sig.rs
index c7e00245d63..47e5ad6c010 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -288,7 +288,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))
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/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 3f25c182fa2..570a6bbac1e 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -467,7 +467,7 @@ fn link_rlib<'a>(sess: &'a Session,
                 // 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;
+                        sess.codegen_units() > 1;
                 if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
                     remove(sess, &bc_filename);
                 }
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 8f75b891a30..01d3d656dfe 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -130,6 +130,7 @@ pub fn run(cgcx: &CodegenContext,
         .filter_map(symbol_filter)
         .collect::<Vec<CString>>();
     timeline.record("whitelist");
+    info!("{} symbols to preserve in this crate", symbol_white_list.len());
 
     // 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
@@ -437,7 +438,24 @@ fn run_pass_manager(cgcx: &CodegenContext,
         assert!(!pass.is_null());
         llvm::LLVMRustAddPass(pm, pass);
 
-        with_llvm_pmb(llmod, config, &mut |b| {
+        // 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");
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index 306071223fc..66a27f1c4a9 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::{TransItemExt, 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 b3b2384a027..f7e0ad029af 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -217,7 +217,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>,
@@ -507,7 +507,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);
             })
@@ -1037,10 +1038,10 @@ fn produce_final_output_artifacts(sess: &Session,
         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);
+                (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[..]);
@@ -1079,13 +1080,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 {
@@ -1247,7 +1244,7 @@ fn start_executing_work(tcx: TyCtxt,
                         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));
@@ -1695,7 +1692,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")
@@ -1721,11 +1718,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
@@ -1846,16 +1843,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);
@@ -2018,7 +2016,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>,
 }
 
@@ -2026,7 +2024,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.");
             }
@@ -2048,7 +2050,7 @@ impl OngoingCrateTranslation {
 
         // 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(); }
         }
 
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 17e00ac1346..6b53b5b6411 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1218,7 +1218,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", || {
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/collector.rs b/src/librustc_trans/collector.rs
index 73df1b45c59..33a2e96ee66 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -401,9 +401,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 +849,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/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/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/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index cd2a881451c..471be439a8f 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/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()
         }
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 4656d212f9b..386806e4c9c 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -163,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))
@@ -279,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
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 526b61303e1..060f02ee23e 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -26,11 +26,12 @@ use monomorphize::Instance;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::middle::trans::{Linkage, Visibility};
+use rustc::session::config::OptLevel;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst::{Subst, Substs};
 use syntax::ast;
-use syntax::attr;
+use syntax::attr::{self, InlineAttr};
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 use type_of;
@@ -44,7 +45,20 @@ pub use rustc::middle::trans::TransItem;
 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,
+    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).
@@ -154,18 +168,47 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
     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 self.explicit_linkage(tcx).is_none() &&
-                    common::requests_inline(tcx, 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)
                 {
-                    InstantiationMode::LocalCopy
-                } else {
-                    InstantiationMode::GloballyShared
+                    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,
-            TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared,
+            TransItem::Static(..) => {
+                InstantiationMode::GloballyShared { may_conflict: false }
+            }
+            TransItem::GlobalAsm(..) => {
+                InstantiationMode::GloballyShared { may_conflict: false }
+            }
         }
     }
 
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/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 3ddeba9d440..d4eda13c6cd 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};
@@ -275,7 +276,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);
@@ -371,10 +372,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..0ebccbc835f 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;
@@ -728,7 +729,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);
         }
     })?)
 }
@@ -1293,7 +1294,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 +2359,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 +2379,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 +2392,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 +2402,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 +2443,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 +2465,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 +2485,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 +2514,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 +2528,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 +2881,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)
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/lib.rs b/src/librustc_typeck/lib.rs
index 7a6ee73b9b9..1c047ef98d8 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -123,6 +123,7 @@ mod constrained_type_params;
 mod impl_wf_check;
 mod coherence;
 mod variance;
+mod namespace;
 
 pub struct TypeAndSubsts<'tcx> {
     substs: &'tcx Substs<'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/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/mod.rs b/src/librustdoc/clean/mod.rs
index 424f48a17e9..e217978648e 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,
@@ -1681,6 +1683,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 {
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/layout.rs b/src/librustdoc/html/layout.rs
index d08a7bde71c..873d978b9cb 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -97,9 +97,9 @@ 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>&#9166;</dt>
                     <dd>Go to active search result</dd>
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index a3f446885f9..3c789cb3a15 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);
                 }
             }
@@ -3422,6 +3454,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..bccad6c89dc 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -342,6 +342,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 +387,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 +424,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 +476,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 +624,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;
                 }
             }
@@ -692,18 +739,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 +799,32 @@
                               '<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 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">' +
+                '<div class="selected">Types/modules</div>' +
+                '<div>As parameters</div>' +
+                '<div>As return value</div></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 +839,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 +880,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 +1392,27 @@
         return wrapper;
     }
 
+    // In the search display, allows to switch between tabs.
+    function printTab(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..a132223a051 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;
@@ -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..890e1169c05 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -243,6 +243,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")
+        }),
     ]
 }
 
@@ -354,15 +360,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")),
@@ -460,6 +467,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 +492,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") {
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..866c0038a7f 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -36,7 +36,6 @@ rustc_tsan = { path = "../librustc_tsan" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0"
 
 [features]
 backtrace = []
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/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..a97075ff8d8 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -32,18 +32,65 @@ 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
+/// [`from`]: ../convert/trait.From.html#tymethod.from
+/// [`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/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/net/tcp.rs b/src/libstd/net/tcp.rs
index b904641a336..4656cc5a7a7 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1580,6 +1580,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/process.rs b/src/libstd/process.rs
index dbb58991215..f448cffd372 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -702,6 +702,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 +751,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 +1199,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 +1208,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/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/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/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_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/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..f445def9e03 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1419,7 +1419,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 +1438,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")``
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index a2f29181a20..9060a613bc1 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -398,6 +398,9 @@ 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)),
 );
 
 declare_features! (
@@ -1417,6 +1420,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)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 03c47b71d02..d7d491db71f 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)))
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 978e06c75dd..bd400ef6dd6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -33,7 +33,7 @@ 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};
@@ -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,
@@ -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();
             }
@@ -4231,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) ||
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..02f871c58c7 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[..])?;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 05077d42a0b..521c6030eba 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -348,7 +348,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);
         }
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/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 e37f048dd47..1287b94159a 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -901,9 +901,7 @@ addPreservedGUID(const ModuleSummaryIndex &Index,
       }
     }
 
-    GlobalValueSummary *GVSummary = Summary.get();
-    if (isa<FunctionSummary>(GVSummary)) {
-      FunctionSummary *FS = cast<FunctionSummary>(GVSummary);
+    if (auto *FS = dyn_cast<FunctionSummary>(Summary.get())) {
       for (auto &Call: FS->calls()) {
         if (Call.first.isGUID()) {
           addPreservedGUID(Index, Preserved, Call.first.getGUID());
@@ -916,6 +914,10 @@ addPreservedGUID(const ModuleSummaryIndex &Index,
         addPreservedGUID(Index, Preserved, GUID);
       }
     }
+    if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
+      auto GUID = AS->getAliasee().getOriginalName();
+      addPreservedGUID(Index, Preserved, GUID);
+    }
   }
 }
 
@@ -963,12 +965,13 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
   // combined index
   //
   // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
-  computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+  auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
   ComputeCrossModuleImport(
     Ret->Index,
     Ret->ModuleToDefinedGVSummaries,
     Ret->ImportLists,
-    Ret->ExportLists
+    Ret->ExportLists,
+    &DeadSymbols
   );
 
   // Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
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 bd1325e7501..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,6 +10,7 @@
 
 // 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_intrinsic0[Internal]
 struct StructWithDtor(u32);
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 108a8b570de..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)]
 
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 875cacb3907..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)]
 
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 a6081b2c5eb..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,6 +10,7 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
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 8eef5f00f2a..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,6 +10,7 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
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 7edb1c14525..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,6 +10,7 @@
 
 // ignore-tidy-linelength
 // compile-flags:-Zprint-trans-items=eager
+// compile-flags:-Zinline-in-all-cgus
 
 #![deny(dead_code)]
 
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index cf0c6643238..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)]
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/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/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-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-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/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-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/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/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..5067b571ee6 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,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")]
+    // FIXME(michaelwoerister): This is curious but an unused lifetime parameter doesn't seem to
+    // show up in any of the derived data structures.
+    #[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
+    #[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 +388,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",
+    )]
+    #[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 +412,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 +436,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,GenericsOfItem,PredicatesOfItem,TypeOfItem")]
+    #[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 +457,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")]
+    #[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 +478,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 +502,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 +526,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 +547,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 +568,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 d2ca65775a4..5a31be8bd50 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -31,12 +31,15 @@ fn main() {
 // START rustc.node12.EraseRegions.after.mir
 //     bb0: {
 //         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{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), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::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 d240b51e222..bcb21c60b26 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), index: DefIndex(1:9) => validate_4[8cd8]::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[8cd8]::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[8cd8]::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[8cd8]::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), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]);
 //         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::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), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::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 e1eeb2102d1..44280539c41 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), index: DefIndex(0:4) => validate_5[8cd8]::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), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::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/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/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 8324a074d6c..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
+	$(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 6dc837b8a78..1d20d940000 100644
--- a/src/test/run-make/sepcomp-inlining/Makefile
+++ b/src/test/run-make/sepcomp-inlining/Makefile
@@ -7,7 +7,8 @@
 # in only one compilation unit.
 
 all:
-	$(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3
+	$(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" ]
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/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/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/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-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/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/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/auxiliary/thin-lto-inlines-aux.rs b/src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs
index ccbb0e7a718..ccbb0e7a718 100644
--- a/src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs
+++ b/src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs
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/thin-lto-inlines.rs b/src/test/run-pass/thinlto/thin-lto-inlines.rs
index 3135a682d86..3135a682d86 100644
--- a/src/test/run-pass/thin-lto-inlines.rs
+++ b/src/test/run-pass/thinlto/thin-lto-inlines.rs
diff --git a/src/test/run-pass/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs
index ed899d2b115..ed899d2b115 100644
--- a/src/test/run-pass/thin-lto-inlines2.rs
+++ b/src/test/run-pass/thinlto/thin-lto-inlines2.rs
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/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-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/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr
index 5b2a4f589f7..9a69c52e6cf 100644
--- a/src/test/ui/lint/suggestions.stderr
+++ b/src/test/ui/lint/suggestions.stderr
@@ -14,6 +14,20 @@ warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was
    |
    = note: #[warn(deprecated)] on by default
 
+warning: variable does not need to be mutable
+  --> $DIR/suggestions.rs:17:13
+   |
+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
+   |
+11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
+   |         ^^^^^^^^^^
+
 warning: denote infinite loops with `loop { ... }`
   --> $DIR/suggestions.rs:16:5
    |
@@ -29,17 +43,3 @@ warning: denote infinite loops with `loop { ... }`
    |
    = note: #[warn(while_true)] on by default
 
-warning: variable does not need to be mutable
-  --> $DIR/suggestions.rs:17:13
-   |
-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
-   |
-11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
-   |         ^^^^^^^^^^
-
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 daeac35a017..8c1b130b116 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -95,6 +95,7 @@ static TARGETS: &'static [&'static str] = &[
     "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 b62b1b68edcdf23a70cb12f31403c80e97f1363
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..d61077643f1 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 => {},
             }
         }
     }
@@ -2439,6 +2484,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/rustfmt b/src/tools/rustfmt
-Subproject 22eb5241c0ee5bb7eaf95e270a2b1500e82bf76
+Subproject 16a478368c8dcc0c0ee47372a9f663b23d28b09
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..e62597c5216 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
@@ -26,11 +26,10 @@
 miri = "Broken"
 
 # ping @Manishearth @llogiq @mcarton @oli-obk
-clippy = "Broken"
+clippy = "Compiling"
 
 # ping @nrc
 rls = "Testing"
 
 # ping @nrc
 rustfmt = "Testing"
-