about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--.gitmodules3
-rw-r--r--CONTRIBUTING.md8
-rw-r--r--Cargo.lock36
-rw-r--r--config.toml.example4
-rw-r--r--src/bootstrap/bootstrap.py4
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/cache.rs2
-rw-r--r--src/bootstrap/compile.rs27
-rw-r--r--src/bootstrap/config.rs1
-rwxr-xr-xsrc/bootstrap/configure.py5
-rw-r--r--src/bootstrap/dist.rs4
-rw-r--r--src/bootstrap/lib.rs9
-rw-r--r--src/bootstrap/native.rs85
-rw-r--r--src/bootstrap/test.rs18
-rw-r--r--src/build_helper/lib.rs7
-rw-r--r--src/ci/azure-pipelines/auto.yml4
-rw-r--r--src/ci/docker/README.md9
-rw-r--r--src/ci/docker/asmjs/Dockerfile47
-rw-r--r--src/ci/docker/disabled/asmjs/Dockerfile41
-rw-r--r--src/ci/docker/disabled/wasm32-exp/Dockerfile35
-rwxr-xr-xsrc/ci/docker/disabled/wasm32-exp/node.sh9
-rw-r--r--src/ci/docker/disabled/wasm32/Dockerfile32
-rw-r--r--src/ci/docker/dist-armv7-linux/Dockerfile8
-rw-r--r--src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config799
-rw-r--r--src/ci/docker/dist-armv7-linux/crosstool-ng.sh12
-rw-r--r--src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch48
-rw-r--r--src/ci/docker/dist-various-1/Dockerfile1
-rw-r--r--src/ci/docker/scripts/cross-apt-packages.sh1
-rw-r--r--src/ci/docker/scripts/emscripten-wasm.sh37
-rw-r--r--src/ci/docker/scripts/emscripten.sh21
-rw-r--r--src/ci/docker/wasm32/Dockerfile44
-rwxr-xr-xsrc/ci/init_repo.sh2
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/codegen-options/index.md2
-rw-r--r--src/doc/rustc/src/command-line-arguments.md11
-rw-r--r--src/doc/rustc/src/json.md231
-rw-r--r--src/doc/rustc/src/lints/listing/warn-by-default.md24
-rw-r--r--src/doc/rustc/src/profile-guided-optimization.md11
-rw-r--r--src/doc/rustc/src/targets/index.md6
-rw-r--r--src/doc/rustc/src/targets/known-issues.md13
-rw-r--r--src/liballoc/boxed.rs16
-rw-r--r--src/liballoc/collections/btree/set.rs239
-rw-r--r--src/liballoc/fmt.rs389
-rw-r--r--src/liballoc/rc.rs131
-rw-r--r--src/liballoc/sync.rs116
-rw-r--r--src/liballoc/tests/binary_heap.rs13
-rw-r--r--src/liballoc/tests/boxed.rs18
-rw-r--r--src/liballoc/tests/btree/set.rs26
-rw-r--r--src/liballoc/tests/lib.rs2
-rw-r--r--src/liballoc/tests/str.rs2
-rw-r--r--src/liballoc/tests/vec.rs7
-rw-r--r--src/libcore/any.rs9
-rw-r--r--src/libcore/ffi.rs56
-rw-r--r--src/libcore/fmt/builders.rs16
-rw-r--r--src/libcore/fmt/mod.rs4
-rw-r--r--src/libcore/hint.rs16
-rw-r--r--src/libcore/iter/traits/collect.rs2
-rw-r--r--src/libcore/mem/mod.rs4
-rw-r--r--src/libcore/num/mod.rs16
-rw-r--r--src/libcore/num/wrapping.rs4
-rw-r--r--src/libcore/ops/unsize.rs2
-rw-r--r--src/libcore/option.rs8
-rw-r--r--src/libcore/ptr/mod.rs4
-rw-r--r--src/libcore/str/mod.rs4
-rw-r--r--src/libcore/tests/fmt/builders.rs40
-rw-r--r--src/librustc/Cargo.toml3
-rw-r--r--src/librustc/arena.rs1
-rw-r--r--src/librustc/dep_graph/graph.rs149
-rw-r--r--src/librustc/error_codes.rs102
-rw-r--r--src/librustc/hir/def.rs2
-rw-r--r--src/librustc/hir/lowering.rs32
-rw-r--r--src/librustc/hir/lowering/item.rs2
-rw-r--r--src/librustc/hir/map/def_collector.rs4
-rw-r--r--src/librustc/hir/map/definitions.rs9
-rw-r--r--src/librustc/hir/map/mod.rs2
-rw-r--r--src/librustc/hir/mod.rs25
-rw-r--r--src/librustc/hir/print.rs2
-rw-r--r--src/librustc/hir/ptr.rs2
-rw-r--r--src/librustc/ich/hcx.rs2
-rw-r--r--src/librustc/ich/impls_syntax.rs2
-rw-r--r--src/librustc/infer/canonical/canonicalizer.rs6
-rw-r--r--src/librustc/infer/canonical/mod.rs8
-rw-r--r--src/librustc/infer/canonical/query_response.rs7
-rw-r--r--src/librustc/infer/combine.rs2
-rw-r--r--src/librustc/infer/error_reporting/mod.rs6
-rw-r--r--src/librustc/infer/freshen.rs2
-rw-r--r--src/librustc/infer/lexical_region_resolve/mod.rs74
-rw-r--r--src/librustc/infer/mod.rs2
-rw-r--r--src/librustc/infer/nll_relate/mod.rs8
-rw-r--r--src/librustc/infer/region_constraints/mod.rs2
-rw-r--r--src/librustc/infer/resolve.rs6
-rw-r--r--src/librustc/lib.rs3
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc/lint/levels.rs9
-rw-r--r--src/librustc/lint/mod.rs2
-rw-r--r--src/librustc/middle/cstore.rs9
-rw-r--r--src/librustc/middle/mem_categorization.rs8
-rw-r--r--src/librustc/middle/resolve_lifetime.rs8
-rw-r--r--src/librustc/middle/stability.rs5
-rw-r--r--src/librustc/mir/interpret/allocation.rs37
-rw-r--r--src/librustc/mir/interpret/error.rs13
-rw-r--r--src/librustc/mir/interpret/value.rs11
-rw-r--r--src/librustc/mir/mod.rs20
-rw-r--r--src/librustc/mir/mono.rs6
-rw-r--r--src/librustc/mir/visit.rs215
-rw-r--r--src/librustc/query/mod.rs19
-rw-r--r--src/librustc/session/config.rs536
-rw-r--r--src/librustc/session/mod.rs6
-rw-r--r--src/librustc/session/search_paths.rs3
-rw-r--r--src/librustc/traits/error_reporting.rs176
-rw-r--r--src/librustc/traits/query/dropck_outlives.rs16
-rw-r--r--src/librustc/traits/query/mod.rs2
-rw-r--r--src/librustc/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--src/librustc/traits/query/type_op/outlives.rs3
-rw-r--r--src/librustc/traits/specialize/mod.rs2
-rw-r--r--src/librustc/ty/binding.rs2
-rw-r--r--src/librustc/ty/codec.rs35
-rw-r--r--src/librustc/ty/context.rs28
-rw-r--r--src/librustc/ty/error.rs1
-rw-r--r--src/librustc/ty/fast_reject.rs8
-rw-r--r--src/librustc/ty/flags.rs2
-rw-r--r--src/librustc/ty/fold.rs27
-rw-r--r--src/librustc/ty/layout.rs10
-rw-r--r--src/librustc/ty/mod.rs32
-rw-r--r--src/librustc/ty/print/pretty.rs2
-rw-r--r--src/librustc/ty/query/keys.rs9
-rw-r--r--src/librustc/ty/query/on_disk_cache.rs7
-rw-r--r--src/librustc/ty/query/plumbing.rs4
-rw-r--r--src/librustc/ty/structural_impls.rs20
-rw-r--r--src/librustc/ty/sty.rs10
-rw-r--r--src/librustc/ty/subst.rs6
-rw-r--r--src/librustc/ty/util.rs26
-rw-r--r--src/librustc_codegen_llvm/Cargo.toml6
-rw-r--r--src/librustc_codegen_llvm/allocator.rs2
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs4
-rw-r--r--src/librustc_codegen_llvm/builder.rs1
-rw-r--r--src/librustc_codegen_llvm/callee.rs2
-rw-r--r--src/librustc_codegen_llvm/common.rs42
-rw-r--r--src/librustc_codegen_llvm/context.rs25
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs4
-rw-r--r--src/librustc_codegen_llvm/error_codes.rs38
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs6
-rw-r--r--src/librustc_codegen_llvm/lib.rs16
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs10
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs3
-rw-r--r--src/librustc_codegen_ssa/Cargo.toml1
-rw-r--r--src/librustc_codegen_ssa/README.md2
-rw-r--r--src/librustc_codegen_ssa/back/symbol_export.rs2
-rw-r--r--src/librustc_codegen_ssa/back/write.rs37
-rw-r--r--src/librustc_codegen_ssa/base.rs99
-rw-r--r--src/librustc_codegen_ssa/callee.rs53
-rw-r--r--src/librustc_codegen_ssa/common.rs5
-rw-r--r--src/librustc_codegen_ssa/error_codes.rs35
-rw-r--r--src/librustc_codegen_ssa/lib.rs12
-rw-r--r--src/librustc_codegen_ssa/meth.rs12
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs8
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs4
-rw-r--r--src/librustc_codegen_ssa/mir/operand.rs1
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs4
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs26
-rw-r--r--src/librustc_codegen_ssa/traits/backend.rs4
-rw-r--r--src/librustc_codegen_ssa/traits/builder.rs2
-rw-r--r--src/librustc_codegen_ssa/traits/consts.rs4
-rw-r--r--src/librustc_codegen_ssa/traits/debuginfo.rs2
-rw-r--r--src/librustc_codegen_ssa/traits/declare.rs4
-rw-r--r--src/librustc_codegen_ssa/traits/misc.rs8
-rw-r--r--src/librustc_codegen_ssa/traits/mod.rs1
-rw-r--r--src/librustc_codegen_utils/codegen_backend.rs1
-rw-r--r--src/librustc_codegen_utils/lib.rs5
-rw-r--r--src/librustc_data_structures/graph/implementation/mod.rs4
-rw-r--r--src/librustc_data_structures/sharded.rs32
-rw-r--r--src/librustc_data_structures/snapshot_map/mod.rs2
-rw-r--r--src/librustc_data_structures/stable_hasher.rs10
-rw-r--r--src/librustc_data_structures/sync.rs53
-rw-r--r--src/librustc_data_structures/thin_vec.rs2
-rw-r--r--src/librustc_data_structures/tiny_list.rs4
-rw-r--r--src/librustc_data_structures/transitive_relation.rs6
-rw-r--r--src/librustc_driver/lib.rs5
-rw-r--r--src/librustc_errors/annotate_snippet_emitter_writer.rs18
-rw-r--r--src/librustc_errors/emitter.rs78
-rw-r--r--src/librustc_errors/lib.rs32
-rw-r--r--src/librustc_index/bit_set.rs70
-rw-r--r--src/librustc_interface/Cargo.toml2
-rw-r--r--src/librustc_interface/interface.rs63
-rw-r--r--src/librustc_interface/lib.rs3
-rw-r--r--src/librustc_interface/passes.rs37
-rw-r--r--src/librustc_interface/tests.rs (renamed from src/librustc/session/config/tests.rs)89
-rw-r--r--src/librustc_lint/builtin.rs37
-rw-r--r--src/librustc_lint/lib.rs4
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_metadata/Cargo.toml1
-rw-r--r--src/librustc_metadata/creader.rs92
-rw-r--r--src/librustc_metadata/cstore.rs132
-rw-r--r--src/librustc_metadata/cstore_impl.rs34
-rw-r--r--src/librustc_metadata/decoder.rs379
-rw-r--r--src/librustc_metadata/dependency_format.rs2
-rw-r--r--src/librustc_metadata/dynamic_lib.rs61
-rw-r--r--src/librustc_metadata/encoder.rs1049
-rw-r--r--src/librustc_metadata/foreign_modules.rs2
-rw-r--r--src/librustc_metadata/index.rs141
-rw-r--r--src/librustc_metadata/lib.rs10
-rw-r--r--src/librustc_metadata/link_args.rs2
-rw-r--r--src/librustc_metadata/locator.rs89
-rw-r--r--src/librustc_metadata/native_libs.rs8
-rw-r--r--src/librustc_metadata/schema.rs164
-rw-r--r--src/librustc_metadata/table.rs239
-rw-r--r--src/librustc_mir/borrow_check/conflict_errors.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/constraints/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/member_constraints.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/values.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs17
-rw-r--r--src/librustc_mir/borrow_check/nll/universal_regions.rs2
-rw-r--r--src/librustc_mir/dataflow/impls/indirect_mutation.rs17
-rw-r--r--src/librustc_mir/dataflow/mod.rs6
-rw-r--r--src/librustc_mir/error_codes.rs505
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs258
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs19
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs11
-rw-r--r--src/librustc_mir/interpret/eval_context.rs16
-rw-r--r--src/librustc_mir/interpret/intern.rs7
-rw-r--r--src/librustc_mir/interpret/memory.rs23
-rw-r--r--src/librustc_mir/interpret/operand.rs18
-rw-r--r--src/librustc_mir/interpret/place.rs29
-rw-r--r--src/librustc_mir/interpret/terminator.rs4
-rw-r--r--src/librustc_mir/interpret/validity.rs2
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/lints.rs4
-rw-r--r--src/librustc_mir/monomorphize/collector.rs2
-rw-r--r--src/librustc_mir/transform/const_prop.rs181
-rw-r--r--src/librustc_mir/transform/erase_regions.rs16
-rw-r--r--src/librustc_mir/transform/generator.rs46
-rw-r--r--src/librustc_mir/transform/inline.rs56
-rw-r--r--src/librustc_mir/transform/promote_consts.rs18
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs75
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs2
-rw-r--r--src/librustc_mir/transform/simplify.rs89
-rw-r--r--src/librustc_mir/util/def_use.rs44
-rw-r--r--src/librustc_passes/Cargo.toml1
-rw-r--r--src/librustc_passes/ast_validation.rs5
-rw-r--r--src/librustc_plugin/Cargo.toml1
-rw-r--r--src/librustc_plugin/lib.rs2
-rw-r--r--src/librustc_plugin/registry.rs4
-rw-r--r--src/librustc_privacy/lib.rs14
-rw-r--r--src/librustc_resolve/Cargo.toml1
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs56
-rw-r--r--src/librustc_resolve/diagnostics.rs8
-rw-r--r--src/librustc_resolve/error_codes.rs205
-rw-r--r--src/librustc_resolve/late.rs8
-rw-r--r--src/librustc_resolve/late/diagnostics.rs27
-rw-r--r--src/librustc_resolve/lib.rs68
-rw-r--r--src/librustc_resolve/macros.rs28
-rw-r--r--src/librustc_resolve/resolve_imports.rs99
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs51
-rw-r--r--src/librustc_save_analysis/lib.rs4
-rw-r--r--src/librustc_target/abi/call/asmjs.rs47
-rw-r--r--src/librustc_target/abi/call/mod.rs13
-rw-r--r--src/librustc_target/abi/call/wasm32.rs52
-rw-r--r--src/librustc_target/abi/call/wasm32_bindgen_compat.rs27
-rw-r--r--src/librustc_target/abi/mod.rs6
-rw-r--r--src/librustc_target/spec/asmjs_unknown_emscripten.rs44
-rw-r--r--src/librustc_target/spec/mod.rs13
-rw-r--r--src/librustc_target/spec/wasm32_experimental_emscripten.rs44
-rw-r--r--src/librustc_target/spec/wasm32_unknown_emscripten.rs41
-rw-r--r--src/librustc_target/spec/wasm32_wasi.rs4
-rw-r--r--src/librustc_traits/chalk_context/mod.rs4
-rw-r--r--src/librustc_traits/chalk_context/resolvent_ops.rs17
-rw-r--r--src/librustc_traits/dropck_outlives.rs113
-rw-r--r--src/librustc_traits/lowering/mod.rs4
-rw-r--r--src/librustc_typeck/astconv.rs7
-rw-r--r--src/librustc_typeck/check/closure.rs15
-rw-r--r--src/librustc_typeck/check/coercion.rs10
-rw-r--r--src/librustc_typeck/check/demand.rs10
-rw-r--r--src/librustc_typeck/check/dropck.rs6
-rw-r--r--src/librustc_typeck/check/expr.rs2
-rw-r--r--src/librustc_typeck/check/method/suggest.rs115
-rw-r--r--src/librustc_typeck/check/mod.rs66
-rw-r--r--src/librustc_typeck/check/op.rs4
-rw-r--r--src/librustc_typeck/check/pat.rs2
-rw-r--r--src/librustc_typeck/check/wfcheck.rs4
-rw-r--r--src/librustc_typeck/collect.rs69
-rw-r--r--src/librustc_typeck/constrained_generic_params.rs4
-rw-r--r--src/librustc_typeck/error_codes.rs46
-rw-r--r--src/librustc_typeck/impl_wf_check.rs2
-rw-r--r--src/librustc_typeck/outlives/explicit.rs2
-rw-r--r--src/librustdoc/clean/auto_trait.rs4
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/cfg.rs4
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs16
-rw-r--r--src/librustdoc/config.rs4
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/doctree.rs4
-rw-r--r--src/librustdoc/html/highlight.rs4
-rw-r--r--src/librustdoc/html/item_type.rs2
-rw-r--r--src/librustdoc/html/render.rs8
-rw-r--r--src/librustdoc/html/static/main.js3
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/test.rs7
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/libserialize/collection_impls.rs4
-rw-r--r--src/libstd/ffi/c_str.rs26
-rw-r--r--src/libstd/fs.rs22
-rw-r--r--src/libstd/io/stdio.rs2
-rw-r--r--src/libstd/keyword_docs.rs67
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/net/udp.rs2
-rw-r--r--src/libstd/panic.rs2
-rw-r--r--src/libstd/panicking.rs17
-rw-r--r--src/libstd/process.rs12
-rw-r--r--src/libstd/sync/once.rs5
-rw-r--r--src/libstd/sys/unix/fast_thread_local.rs3
-rw-r--r--src/libstd/sys/unix/fd.rs34
-rw-r--r--src/libstd/sys/unix/fs.rs229
-rw-r--r--src/libstd/sys/wasi/thread.rs8
-rw-r--r--src/libstd/sys/windows/fs.rs2
-rw-r--r--src/libstd/sys_common/os_str_bytes.rs8
-rw-r--r--src/libsyntax/ast.rs74
-rw-r--r--src/libsyntax/attr/builtin.rs59
-rw-r--r--src/libsyntax/attr/mod.rs68
-rw-r--r--src/libsyntax/config.rs23
-rw-r--r--src/libsyntax/error_codes.rs28
-rw-r--r--src/libsyntax/feature_gate/builtin_attrs.rs12
-rw-r--r--src/libsyntax/feature_gate/check.rs57
-rw-r--r--src/libsyntax/feature_gate/mod.rs3
-rw-r--r--src/libsyntax/json.rs36
-rw-r--r--src/libsyntax/lib.rs44
-rw-r--r--src/libsyntax/mut_visit.rs6
-rw-r--r--src/libsyntax/parse/lexer/mod.rs2
-rw-r--r--src/libsyntax/parse/lexer/tokentrees.rs21
-rw-r--r--src/libsyntax/parse/literal.rs177
-rw-r--r--src/libsyntax/parse/mod.rs272
-rw-r--r--src/libsyntax/parse/parser.rs401
-rw-r--r--src/libsyntax/parse/parser/attr.rs (renamed from src/libsyntax/parse/attr.rs)44
-rw-r--r--src/libsyntax/parse/parser/diagnostics.rs (renamed from src/libsyntax/parse/diagnostics.rs)148
-rw-r--r--src/libsyntax/parse/parser/expr.rs195
-rw-r--r--src/libsyntax/parse/parser/generics.rs2
-rw-r--r--src/libsyntax/parse/parser/item.rs700
-rw-r--r--src/libsyntax/parse/parser/module.rs12
-rw-r--r--src/libsyntax/parse/parser/pat.rs62
-rw-r--r--src/libsyntax/parse/parser/path.rs19
-rw-r--r--src/libsyntax/parse/parser/stmt.rs13
-rw-r--r--src/libsyntax/parse/parser/ty.rs15
-rw-r--r--src/libsyntax/parse/token.rs153
-rw-r--r--src/libsyntax/print/pprust.rs6
-rw-r--r--src/libsyntax/ptr.rs1
-rw-r--r--src/libsyntax/sess.rs124
-rw-r--r--src/libsyntax/source_map.rs5
-rw-r--r--src/libsyntax/tests.rs7
-rw-r--r--src/libsyntax/tokenstream.rs243
-rw-r--r--src/libsyntax_expand/Cargo.toml26
-rw-r--r--src/libsyntax_expand/allocator.rs (renamed from src/libsyntax/ext/allocator.rs)4
-rw-r--r--src/libsyntax_expand/base.rs (renamed from src/libsyntax/ext/base.rs)54
-rw-r--r--src/libsyntax_expand/build.rs (renamed from src/libsyntax/ext/build.rs)15
-rw-r--r--src/libsyntax_expand/expand.rs (renamed from src/libsyntax/ext/expand.rs)328
-rw-r--r--src/libsyntax_expand/lib.rs39
-rw-r--r--src/libsyntax_expand/mbe.rs (renamed from src/libsyntax/ext/mbe.rs)8
-rw-r--r--src/libsyntax_expand/mbe/macro_check.rs (renamed from src/libsyntax/ext/mbe/macro_check.rs)14
-rw-r--r--src/libsyntax_expand/mbe/macro_parser.rs (renamed from src/libsyntax/ext/mbe/macro_parser.rs)23
-rw-r--r--src/libsyntax_expand/mbe/macro_rules.rs (renamed from src/libsyntax/ext/mbe/macro_rules.rs)77
-rw-r--r--src/libsyntax_expand/mbe/quoted.rs (renamed from src/libsyntax/ext/mbe/quoted.rs)17
-rw-r--r--src/libsyntax_expand/mbe/transcribe.rs (renamed from src/libsyntax/ext/mbe/transcribe.rs)17
-rw-r--r--src/libsyntax_expand/placeholders.rs (renamed from src/libsyntax/ext/placeholders.rs)44
-rw-r--r--src/libsyntax_expand/proc_macro.rs (renamed from src/libsyntax/ext/proc_macro.rs)38
-rw-r--r--src/libsyntax_expand/proc_macro_server.rs (renamed from src/libsyntax/ext/proc_macro_server.rs)30
-rw-r--r--src/libsyntax_ext/Cargo.toml1
-rw-r--r--src/libsyntax_ext/asm.rs2
-rw-r--r--src/libsyntax_ext/assert.rs2
-rw-r--r--src/libsyntax_ext/cfg.rs2
-rw-r--r--src/libsyntax_ext/cmdline_attrs.rs5
-rw-r--r--src/libsyntax_ext/compile_error.rs2
-rw-r--r--src/libsyntax_ext/concat.rs2
-rw-r--r--src/libsyntax_ext/concat_idents.rs2
-rw-r--r--src/libsyntax_ext/deriving/bounds.rs2
-rw-r--r--src/libsyntax_ext/deriving/clone.rs24
-rw-r--r--src/libsyntax_ext/deriving/cmp/eq.rs2
-rw-r--r--src/libsyntax_ext/deriving/cmp/ord.rs2
-rw-r--r--src/libsyntax_ext/deriving/cmp/partial_eq.rs2
-rw-r--r--src/libsyntax_ext/deriving/cmp/partial_ord.rs2
-rw-r--r--src/libsyntax_ext/deriving/debug.rs2
-rw-r--r--src/libsyntax_ext/deriving/decodable.rs2
-rw-r--r--src/libsyntax_ext/deriving/default.rs4
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs2
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs8
-rw-r--r--src/libsyntax_ext/deriving/generic/ty.rs2
-rw-r--r--src/libsyntax_ext/deriving/hash.rs2
-rw-r--r--src/libsyntax_ext/deriving/mod.rs2
-rw-r--r--src/libsyntax_ext/env.rs2
-rw-r--r--src/libsyntax_ext/format.rs2
-rw-r--r--src/libsyntax_ext/global_allocator.rs7
-rw-r--r--src/libsyntax_ext/global_asm.rs2
-rw-r--r--src/libsyntax_ext/lib.rs7
-rw-r--r--src/libsyntax_ext/log_syntax.rs2
-rw-r--r--src/libsyntax_ext/plugin_macro_defs.rs4
-rw-r--r--src/libsyntax_ext/proc_macro_harness.rs38
-rw-r--r--src/libsyntax_ext/source_util.rs29
-rw-r--r--src/libsyntax_ext/standard_library_imports.rs8
-rw-r--r--src/libsyntax_ext/test.rs6
-rw-r--r--src/libsyntax_ext/test_harness.rs6
-rw-r--r--src/libsyntax_ext/trace_macros.rs2
-rw-r--r--src/libsyntax_ext/util.rs11
-rw-r--r--src/libsyntax_pos/lib.rs4
-rw-r--r--src/libsyntax_pos/symbol.rs124
-rw-r--r--src/libsyntax_pos/symbol/tests.rs7
-rw-r--r--src/libtest/bench.rs258
-rw-r--r--src/libtest/cli.rs444
-rw-r--r--src/libtest/console.rs308
-rw-r--r--src/libtest/event.rs41
-rw-r--r--src/libtest/formatters/json.rs35
-rw-r--r--src/libtest/formatters/mod.rs14
-rw-r--r--src/libtest/formatters/pretty.rs40
-rw-r--r--src/libtest/formatters/terse.rs40
-rw-r--r--src/libtest/helpers/concurrency.rs143
-rw-r--r--src/libtest/helpers/exit_code.rs20
-rw-r--r--src/libtest/helpers/isatty.rs33
-rw-r--r--src/libtest/helpers/metrics.rs50
-rw-r--r--src/libtest/helpers/mod.rs8
-rw-r--r--src/libtest/helpers/sink.rs24
-rw-r--r--src/libtest/lib.rs1853
-rw-r--r--src/libtest/options.rs90
-rw-r--r--src/libtest/stats/tests.rs2
-rw-r--r--src/libtest/test_result.rs107
-rw-r--r--src/libtest/tests.rs63
-rw-r--r--src/libtest/time.rs206
-rw-r--r--src/libtest/types.rs145
m---------src/llvm-emscripten0
-rw-r--r--src/test/codegen/c-variadic.rs1
-rw-r--r--src/test/codegen/drop.rs1
-rw-r--r--src/test/codegen/external-no-mangle-statics.rs1
-rw-r--r--src/test/codegen/link_section.rs1
-rw-r--r--src/test/codegen/no-output-asm-is-volatile.rs2
-rw-r--r--src/test/codegen/personality_lifetimes.rs1
-rw-r--r--src/test/codegen/repr-transparent-aggregates-2.rs3
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-log.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs1
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs2
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs160
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs6
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs1
-rw-r--r--src/test/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs1
-rw-r--r--src/test/codegen/union-abi.rs1
-rw-r--r--src/test/codegen/unwind-extern-exports.rs1
-rw-r--r--src/test/codegen/unwind-extern-imports.rs1
-rw-r--r--src/test/compile-fail/consts/const-err3.rs1
-rw-r--r--src/test/compile-fail/weak-lang-item.rs2
-rw-r--r--src/test/incremental/change_crate_dep_kind.rs1
-rw-r--r--src/test/incremental/commandline-args.rs1
-rw-r--r--src/test/incremental/const-generics/issue-61338.rs14
-rw-r--r--src/test/incremental/const-generics/issue-61516.rs16
-rw-r--r--src/test/incremental/const-generics/issue-62536.rs12
-rw-r--r--src/test/incremental/const-generics/issue-64087.rs11
-rw-r--r--src/test/incremental/const-generics/issue-65623.rs14
-rw-r--r--src/test/incremental/hashes/for_loops.rs2
-rw-r--r--src/test/incremental/hashes/let_expressions.rs8
-rw-r--r--src/test/incremental/hashes/loop_expressions.rs2
-rw-r--r--src/test/incremental/hashes/while_let_loops.rs2
-rw-r--r--src/test/incremental/hashes/while_loops.rs2
-rw-r--r--src/test/incremental/remapped_paths_cc/main.rs1
-rw-r--r--src/test/incremental/span_hash_stable/main.rs1
-rw-r--r--src/test/incremental/spans_in_type_debuginfo.rs1
-rw-r--r--src/test/incremental/spans_significant_w_debuginfo.rs1
-rw-r--r--src/test/mir-opt/box_expr.rs2
-rw-r--r--src/test/mir-opt/const_prop/aggregate.rs25
-rw-r--r--src/test/mir-opt/const_prop/boxes.rs56
-rw-r--r--src/test/mir-opt/const_prop/discriminant.rs53
-rw-r--r--src/test/mir-opt/const_prop/repeat.rs37
-rw-r--r--src/test/mir-opt/generator-storage-dead-unwind.rs2
-rw-r--r--src/test/mir-opt/issue-41110.rs2
-rw-r--r--src/test/mir-opt/issue-62289.rs2
-rw-r--r--src/test/mir-opt/no-spurious-drop-after-call.rs2
-rw-r--r--src/test/mir-opt/packed-struct-drop-aligned.rs2
-rw-r--r--src/test/mir-opt/remove_fake_borrows.rs2
-rw-r--r--src/test/mir-opt/retag.rs2
-rw-r--r--src/test/mir-opt/simplify-locals-removes-unused-consts.rs89
-rw-r--r--src/test/mir-opt/slice-drop-shim.rs4
-rw-r--r--src/test/run-fail/overflowing-rsh-5.rs1
-rw-r--r--src/test/run-fail/overflowing-rsh-6.rs1
-rw-r--r--src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile14
-rw-r--r--src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs10
-rw-r--r--src/test/run-make/wasm-custom-section/Makefile2
-rw-r--r--src/test/run-make/wasm-custom-sections-opt/Makefile2
-rw-r--r--src/test/run-make/wasm-export-all-symbols/Makefile2
-rw-r--r--src/test/run-make/wasm-import-module/Makefile2
-rw-r--r--src/test/run-make/wasm-panic-small/Makefile2
-rw-r--r--src/test/run-make/wasm-symbols-not-exported/Makefile2
-rw-r--r--src/test/run-make/wasm-symbols-not-imported/Makefile2
-rw-r--r--src/test/rustdoc-ui/failed-doctest-missing-codes.stdout14
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.stdout8
-rw-r--r--src/test/rustdoc-ui/unparseable-doc-test.stdout8
-rw-r--r--src/test/rustdoc/macro-in-closure.rs9
-rw-r--r--src/test/rustdoc/sanitizer-option.rs17
-rw-r--r--src/test/ui-fulldeps/ast_stmt_expr_attr.rs5
-rw-r--r--src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs3
-rw-r--r--src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs3
-rw-r--r--src/test/ui-fulldeps/auxiliary/plugin-args.rs5
-rw-r--r--src/test/ui-fulldeps/auxiliary/roman-numerals.rs3
-rw-r--r--src/test/ui-fulldeps/gated-plugin.stderr4
-rw-r--r--src/test/ui-fulldeps/issue-15778-fail.stderr4
-rw-r--r--src/test/ui-fulldeps/issue-15778-pass.stderr4
-rw-r--r--src/test/ui-fulldeps/issue-40001.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-group-plugin.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-plugin-deny-attr.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-plugin.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr4
-rw-r--r--src/test/ui-fulldeps/lint-tool-test.stderr4
-rw-r--r--src/test/ui-fulldeps/llvm-pass-plugin.stderr4
-rw-r--r--src/test/ui-fulldeps/lto-syntax-extension.stderr4
-rw-r--r--src/test/ui-fulldeps/macro-crate-rlib.stderr4
-rw-r--r--src/test/ui-fulldeps/mod_dir_path_canonicalized.rs3
-rw-r--r--src/test/ui-fulldeps/outlive-expansion-phase.stderr4
-rw-r--r--src/test/ui-fulldeps/plugin-args-1.stderr4
-rw-r--r--src/test/ui-fulldeps/plugin-args-2.stderr4
-rw-r--r--src/test/ui-fulldeps/plugin-args-3.stderr4
-rw-r--r--src/test/ui-fulldeps/plugin-attr-register-deny.stderr4
-rw-r--r--src/test/ui-fulldeps/plugin-reexport.stderr4
-rw-r--r--src/test/ui-fulldeps/pprust-expr-roundtrip.rs4
-rw-r--r--src/test/ui-fulldeps/roman-numerals-macro.stderr4
-rw-r--r--src/test/ui/abi/statics/static-mut-foreign.rs4
-rw-r--r--src/test/ui/asm/issue-51431.rs10
-rw-r--r--src/test/ui/asm/issue-51431.stderr8
-rw-r--r--src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr2
-rw-r--r--src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr4
-rw-r--r--src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr4
-rw-r--r--src/test/ui/associated-const/issue-63496.rs9
-rw-r--r--src/test/ui/associated-const/issue-63496.stderr21
-rw-r--r--src/test/ui/associated-item/issue-48027.rs8
-rw-r--r--src/test/ui/associated-item/issue-48027.stderr21
-rw-r--r--src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr18
-rw-r--r--src/test/ui/associated-type-bounds/union-bounds.rs15
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.fixed29
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.rs2
-rw-r--r--src/test/ui/associated-types/associated-types-bound-failure.stderr7
-rw-r--r--src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed15
-rw-r--r--src/test/ui/associated-types/associated-types-for-unimpl-trait.rs3
-rw-r--r--src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr9
-rw-r--r--src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr4
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-bound.stderr7
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr7
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr7
-rw-r--r--src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed30
-rw-r--r--src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs1
-rw-r--r--src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr9
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.fixed14
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.rs3
-rw-r--r--src/test/ui/associated-types/associated-types-unsized.stderr5
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr2
-rw-r--r--src/test/ui/associated-types/issue-44153.rs19
-rw-r--r--src/test/ui/associated-types/issue-44153.stderr16
-rw-r--r--src/test/ui/associated-types/issue-48010.rs23
-rw-r--r--src/test/ui/async-await/async-fn-size-moved-locals.rs2
-rw-r--r--src/test/ui/async-await/async-fn-size-uninit-locals.rs2
-rw-r--r--src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr3
-rw-r--r--src/test/ui/async-await/issue-60709.rs1
-rw-r--r--src/test/ui/async-await/issues/issue-51719.stderr1
-rw-r--r--src/test/ui/async-await/issues/issue-51751.stderr1
-rw-r--r--src/test/ui/async-await/issues/issue-62009-1.stderr3
-rw-r--r--src/test/ui/async-await/issues/issue-62009-2.stderr1
-rw-r--r--src/test/ui/async-await/issues/issue-63388-2.stderr4
-rw-r--r--src/test/ui/async-await/issues/issue-65159.rs10
-rw-r--r--src/test/ui/async-await/issues/issue-65159.stderr9
-rw-r--r--src/test/ui/async-await/issues/non-async-enclosing-span.stderr1
-rw-r--r--src/test/ui/async-await/unused-lifetime.rs42
-rw-r--r--src/test/ui/async-await/unused-lifetime.stderr32
-rw-r--r--src/test/ui/bad/bad-method-typaram-kind.stderr3
-rw-r--r--src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs2
-rw-r--r--src/test/ui/binding/match-arm-statics.rs1
-rw-r--r--src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr4
-rw-r--r--src/test/ui/builtin-clone-unwind.rs2
-rw-r--r--src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr10
-rw-r--r--src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr5
-rw-r--r--src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr5
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-4.stderr2
-rw-r--r--src/test/ui/catch-unwind-bang.rs2
-rw-r--r--src/test/ui/check_match/issue-43253.rs19
-rw-r--r--src/test/ui/check_match/issue-43253.stderr28
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr4
-rw-r--r--src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr6
-rw-r--r--src/test/ui/closures/closure-bounds-subtype.stderr4
-rw-r--r--src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr4
-rw-r--r--src/test/ui/closures/issue-41366.rs13
-rw-r--r--src/test/ui/closures/issue-41366.stderr22
-rw-r--r--src/test/ui/closures/issue-52437.rs5
-rw-r--r--src/test/ui/closures/issue-52437.stderr15
-rw-r--r--src/test/ui/coercion/coerce-issue-49593-box-never.rs2
-rw-r--r--src/test/ui/coherence/impl-foreign-for-foreign.rs17
-rw-r--r--src/test/ui/coherence/impl-foreign-for-foreign.stderr12
-rw-r--r--src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs25
-rw-r--r--src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr30
-rw-r--r--src/test/ui/coherence/impl-foreign-for-foreign[local].rs16
-rw-r--r--src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs21
-rw-r--r--src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr21
-rw-r--r--src/test/ui/coherence/impl-foreign-for-fundamental[local].rs17
-rw-r--r--src/test/ui/coherence/impl-foreign-for-local.rs15
-rw-r--r--src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs26
-rw-r--r--src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr30
-rw-r--r--src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs18
-rw-r--r--src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs23
-rw-r--r--src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr21
-rw-r--r--src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs17
-rw-r--r--src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr11
-rw-r--r--src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs17
-rw-r--r--src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs17
-rw-r--r--src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs19
-rw-r--r--src/test/ui/const-generics/auxiliary/const_generic_lib.rs9
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs10
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr21
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate.rs12
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.stderr2
-rw-r--r--src/test/ui/const-generics/struct-with-invalid-const-param.stderr1
-rw-r--r--src/test/ui/consts/const-err2.rs1
-rw-r--r--src/test/ui/consts/const-err2.stderr8
-rw-r--r--src/test/ui/consts/const-err3.rs1
-rw-r--r--src/test/ui/consts/const-err3.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.rs10
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.stderr11
-rw-r--r--src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs28
-rw-r--r--src/test/ui/consts/const-int-pow-rpass.rs11
-rw-r--r--src/test/ui/consts/const-int-saturating-arith.rs1
-rw-r--r--src/test/ui/consts/const-prop-ice.rs1
-rw-r--r--src/test/ui/consts/const-prop-ice.stderr8
-rw-r--r--src/test/ui/consts/issue-64506.rs20
-rw-r--r--src/test/ui/consts/issue-65348.rs23
-rw-r--r--src/test/ui/consts/miri_unleashed/non_const_fn.rs13
-rw-r--r--src/test/ui/consts/miri_unleashed/non_const_fn.stderr29
-rw-r--r--src/test/ui/consts/too_generic_eval_ice.stderr8
-rw-r--r--src/test/ui/debuginfo-lto.rs1
-rw-r--r--src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr2
-rw-r--r--src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr2
-rw-r--r--src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr4
-rw-r--r--src/test/ui/drop/dynamic-drop-async.rs2
-rw-r--r--src/test/ui/drop/dynamic-drop.rs14
-rw-r--r--src/test/ui/dst/dst-object-from-unsized-type.stderr6
-rw-r--r--src/test/ui/enum/enum-variant-type-2.stderr1
-rw-r--r--src/test/ui/error-codes/E0423.stderr2
-rw-r--r--src/test/ui/error-codes/E0424.stderr14
-rw-r--r--src/test/ui/error-codes/E0478.stderr4
-rw-r--r--src/test/ui/exhaustive_integer_patterns.rs9
-rw-r--r--src/test/ui/exhaustive_integer_patterns.stderr34
-rw-r--r--src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr8
-rw-r--r--src/test/ui/expr_attr_paren_order.stderr2
-rw-r--r--src/test/ui/extern/extern-const.fixed3
-rw-r--r--src/test/ui/extern/extern-const.rs3
-rw-r--r--src/test/ui/extern/extern-const.stderr2
-rw-r--r--src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr24
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs1
-rw-r--r--src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-plugin.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-untagged_unions.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-untagged_unions.stderr29
-rw-r--r--src/test/ui/feature-gates/feature-gate-unwind-attributes.rs1
-rw-r--r--src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr2
-rw-r--r--src/test/ui/for-loop-while/loop-break-value.rs1
-rw-r--r--src/test/ui/generator/issue-58888.rs1
-rw-r--r--src/test/ui/generator/panic-drops.rs2
-rw-r--r--src/test/ui/generator/panic-safe.rs2
-rw-r--r--src/test/ui/generator/resume-after-return.rs2
-rw-r--r--src/test/ui/generator/size-moved-locals.rs1
-rw-r--r--src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs14
-rw-r--r--src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr21
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr4
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr5
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr10
-rw-r--r--src/test/ui/hygiene/globs.stderr2
-rw-r--r--src/test/ui/hygiene/rustc-macro-transparency.stderr2
-rw-r--r--src/test/ui/hygiene/unpretty-debug.stdout2
-rw-r--r--src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr2
-rw-r--r--src/test/ui/impl-trait/hidden-lifetimes.stderr4
-rw-r--r--src/test/ui/impl-trait/issue-55872-1.stderr7
-rw-r--r--src/test/ui/impl-trait/issues/universal-issue-48703.rs2
-rw-r--r--src/test/ui/impl-trait/issues/universal-issue-48703.stderr2
-rw-r--r--src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs2
-rw-r--r--src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr2
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr8
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.stderr2
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.stderr4
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr2
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr2
-rw-r--r--src/test/ui/intrinsics/intrinsics-integer.rs1
-rw-r--r--src/test/ui/invalid/invalid-plugin-attr.stderr4
-rw-r--r--src/test/ui/issues/issue-10200.stderr2
-rw-r--r--src/test/ui/issues/issue-10291.stderr2
-rw-r--r--src/test/ui/issues/issue-13867.rs1
-rw-r--r--src/test/ui/issues/issue-14875.rs2
-rw-r--r--src/test/ui/issues/issue-16683.stderr2
-rw-r--r--src/test/ui/issues/issue-17001.stderr1
-rw-r--r--src/test/ui/issues/issue-17405.stderr1
-rw-r--r--src/test/ui/issues/issue-17546.stderr5
-rw-r--r--src/test/ui/issues/issue-17718-const-naming.stderr2
-rw-r--r--src/test/ui/issues/issue-17740.stderr4
-rw-r--r--src/test/ui/issues/issue-17758.stderr2
-rw-r--r--src/test/ui/issues/issue-17905-2.stderr4
-rw-r--r--src/test/ui/issues/issue-18119.stderr1
-rw-r--r--src/test/ui/issues/issue-20005.stderr2
-rw-r--r--src/test/ui/issues/issue-20831-debruijn.stderr6
-rw-r--r--src/test/ui/issues/issue-21449.stderr1
-rw-r--r--src/test/ui/issues/issue-21475.rs2
-rw-r--r--src/test/ui/issues/issue-21837.stderr6
-rw-r--r--src/test/ui/issues/issue-22872.stderr3
-rw-r--r--src/test/ui/issues/issue-23189.stderr1
-rw-r--r--src/test/ui/issues/issue-23477.rs1
-rw-r--r--src/test/ui/issues/issue-24687-embed-debuginfo/main.rs1
-rw-r--r--src/test/ui/issues/issue-24945-repeat-dash-opts.rs1
-rw-r--r--src/test/ui/issues/issue-26251.rs2
-rw-r--r--src/test/ui/issues/issue-26459.stderr1
-rw-r--r--src/test/ui/issues/issue-26484.rs1
-rw-r--r--src/test/ui/issues/issue-27060-2.stderr3
-rw-r--r--src/test/ui/issues/issue-27078.stderr5
-rw-r--r--src/test/ui/issues/issue-27815.stderr1
-rw-r--r--src/test/ui/issues/issue-27942.stderr4
-rw-r--r--src/test/ui/issues/issue-28848.stderr4
-rw-r--r--src/test/ui/issues/issue-29948.rs2
-rw-r--r--src/test/ui/issues/issue-30535.stderr1
-rw-r--r--src/test/ui/issues/issue-33096.rs1
-rw-r--r--src/test/ui/issues/issue-33992.rs2
-rw-r--r--src/test/ui/issues/issue-34569.rs1
-rw-r--r--src/test/ui/issues/issue-35675.stderr2
-rw-r--r--src/test/ui/issues/issue-36856.rs1
-rw-r--r--src/test/ui/issues/issue-37884.stderr2
-rw-r--r--src/test/ui/issues/issue-38821.stderr1
-rw-r--r--src/test/ui/issues/issue-42210.rs1
-rw-r--r--src/test/ui/issues/issue-42312.stderr5
-rw-r--r--src/test/ui/issues/issue-43784-associated-type.stderr6
-rw-r--r--src/test/ui/issues/issue-43784-supertrait.stderr6
-rw-r--r--src/test/ui/issues/issue-43853.rs2
-rw-r--r--src/test/ui/issues/issue-45731.rs1
-rw-r--r--src/test/ui/issues/issue-46332.stderr2
-rw-r--r--src/test/ui/issues/issue-46519.rs2
-rw-r--r--src/test/ui/issues/issue-47486.rs4
-rw-r--r--src/test/ui/issues/issue-47486.stderr19
-rw-r--r--src/test/ui/issues/issue-48508.rs1
-rw-r--r--src/test/ui/issues/issue-49579.rs1
-rw-r--r--src/test/ui/issues/issue-52213.stderr4
-rw-r--r--src/test/ui/issues/issue-54348.rs2
-rw-r--r--src/test/ui/issues/issue-54348.stderr16
-rw-r--r--src/test/ui/issues/issue-55796.stderr4
-rw-r--r--src/test/ui/issues/issue-58463.rs2
-rw-r--r--src/test/ui/iterators/iter-count-overflow-debug.rs2
-rw-r--r--src/test/ui/iterators/iter-position-overflow-debug.rs2
-rw-r--r--src/test/ui/iterators/iter-step-overflow-debug.rs2
-rw-r--r--src/test/ui/iterators/iter-sum-overflow-debug.rs2
-rw-r--r--src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs2
-rw-r--r--src/test/ui/kindck/kindck-impl-type-params.nll.stderr16
-rw-r--r--src/test/ui/kindck/kindck-impl-type-params.stderr16
-rw-r--r--src/test/ui/lexical-scopes.stderr3
-rw-r--r--src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr4
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts2.rs2
-rw-r--r--src/test/ui/lint/lint-exceeding-bitshifts2.stderr8
-rw-r--r--src/test/ui/lint/lint-non-camel-case-types.stderr10
-rw-r--r--src/test/ui/lint/lint-non-snake-case-functions.stderr6
-rw-r--r--src/test/ui/lint/lint-non-uppercase-statics.stderr2
-rw-r--r--src/test/ui/lint/lint-uppercase-variables.stderr6
-rw-r--r--src/test/ui/lint/must_use-unit.rs1
-rw-r--r--src/test/ui/lint/must_use-unit.stderr6
-rw-r--r--src/test/ui/lint/not_found.stderr2
-rw-r--r--src/test/ui/lint/reasons.stderr2
-rw-r--r--src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr2
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.fixed7
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.rs7
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.stderr106
-rw-r--r--src/test/ui/lint/unused_parens_remove_json_suggestion.fixed21
-rw-r--r--src/test/ui/lint/unused_parens_remove_json_suggestion.rs21
-rw-r--r--src/test/ui/lint/unused_parens_remove_json_suggestion.stderr658
-rw-r--r--src/test/ui/lint/use_suggestion_json.stderr2
-rw-r--r--src/test/ui/lub-if.stderr4
-rw-r--r--src/test/ui/lub-match.stderr4
-rw-r--r--src/test/ui/macros/macro-comma-behavior-rpass.rs2
-rw-r--r--src/test/ui/macros/same-sequence-span.rs1
-rw-r--r--src/test/ui/macros/same-sequence-span.stderr8
-rw-r--r--src/test/ui/malformed/malformed-plugin-1.stderr4
-rw-r--r--src/test/ui/malformed/malformed-plugin-2.stderr4
-rw-r--r--src/test/ui/malformed/malformed-plugin-3.stderr4
-rw-r--r--src/test/ui/match/match-range-fail-dominate.rs22
-rw-r--r--src/test/ui/match/match-range-fail-dominate.stderr22
-rw-r--r--src/test/ui/match/match-ref-mut-invariance.stderr4
-rw-r--r--src/test/ui/match/match-ref-mut-let-invariance.stderr4
-rw-r--r--src/test/ui/mir/mir_calls_to_shims.rs2
-rw-r--r--src/test/ui/mir/mir_drop_order.rs2
-rw-r--r--src/test/ui/mod/mod_file_disambig.stderr1
-rw-r--r--src/test/ui/multiple-plugin-registrars.stderr8
-rw-r--r--src/test/ui/never_type/adjust_never.rs (renamed from src/test/run-fail/adjust_never.rs)1
-rw-r--r--src/test/ui/never_type/call-fn-never-arg-wrong-type.rs (renamed from src/test/ui/call-fn-never-arg-wrong-type.rs)0
-rw-r--r--src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr (renamed from src/test/ui/call-fn-never-arg-wrong-type.stderr)0
-rw-r--r--src/test/ui/never_type/call-fn-never-arg.rs (renamed from src/test/run-fail/call-fn-never-arg.rs)1
-rw-r--r--src/test/ui/never_type/cast-never.rs (renamed from src/test/run-fail/cast-never.rs)1
-rw-r--r--src/test/ui/never_type/defaulted-never-note.rs (renamed from src/test/ui/defaulted-never-note.rs)0
-rw-r--r--src/test/ui/never_type/defaulted-never-note.stderr (renamed from src/test/ui/defaulted-never-note.stderr)0
-rw-r--r--src/test/ui/never_type/dispatch_from_dyn_zst.rs (renamed from src/test/ui/dispatch_from_dyn_zst.rs)0
-rw-r--r--src/test/ui/never_type/diverging-fallback-control-flow.rs (renamed from src/test/ui/diverging-fallback-control-flow.rs)1
-rw-r--r--src/test/ui/never_type/impl-for-never.rs (renamed from src/test/ui/impl-for-never.rs)3
-rw-r--r--src/test/ui/never_type/issue-13352.rs (renamed from src/test/ui/issues/issue-13352.rs)0
-rw-r--r--src/test/ui/never_type/issue-13352.stderr (renamed from src/test/ui/issues/issue-13352.stderr)0
-rw-r--r--src/test/ui/never_type/issue-2149.rs (renamed from src/test/ui/issues/issue-2149.rs)0
-rw-r--r--src/test/ui/never_type/issue-2149.stderr (renamed from src/test/ui/issues/issue-2149.stderr)0
-rw-r--r--src/test/ui/never_type/issue-44402.rs (renamed from src/test/ui/issues/issue-44402.rs)3
-rw-r--r--src/test/ui/never_type/never-assign-dead-code.rs (renamed from src/test/ui/never-assign-dead-code.rs)4
-rw-r--r--src/test/ui/never_type/never-assign-dead-code.stderr (renamed from src/test/ui/never-assign-dead-code.stderr)4
-rw-r--r--src/test/ui/never_type/never-assign-wrong-type.rs (renamed from src/test/ui/never-assign-wrong-type.rs)0
-rw-r--r--src/test/ui/never_type/never-assign-wrong-type.stderr (renamed from src/test/ui/never-assign-wrong-type.stderr)0
-rw-r--r--src/test/ui/never_type/never-associated-type.rs (renamed from src/test/run-fail/never-associated-type.rs)1
-rw-r--r--src/test/ui/never_type/never-from-impl-is-reserved.rs (renamed from src/test/ui/never-from-impl-is-reserved.rs)0
-rw-r--r--src/test/ui/never_type/never-from-impl-is-reserved.stderr (renamed from src/test/ui/never-from-impl-is-reserved.stderr)0
-rw-r--r--src/test/ui/never_type/never-result.rs (renamed from src/test/ui/never-result.rs)1
-rw-r--r--src/test/ui/never_type/never-type-arg.rs (renamed from src/test/run-fail/never-type-arg.rs)1
-rw-r--r--src/test/ui/never_type/never-type-rvalues.rs (renamed from src/test/ui/never-type-rvalues.rs)0
-rw-r--r--src/test/ui/never_type/never_coercions.rs (renamed from src/test/ui/never_coercions.rs)0
-rw-r--r--src/test/ui/never_type/never_transmute_never.rs (renamed from src/test/ui/never_transmute_never.rs)2
-rw-r--r--src/test/ui/never_type/panic-uninitialized-zeroed.rs (renamed from src/test/ui/panic-uninitialized-zeroed.rs)2
-rw-r--r--src/test/ui/never_type/try_from.rs (renamed from src/test/ui/try_from.rs)0
-rw-r--r--src/test/ui/nll/issue-50716.stderr2
-rw-r--r--src/test/ui/nll/issue-52742.stderr2
-rw-r--r--src/test/ui/nll/issue-55394.stderr2
-rw-r--r--src/test/ui/nll/issue-55401.stderr2
-rw-r--r--src/test/ui/nll/normalization-bounds-error.stderr4
-rw-r--r--src/test/ui/nll/trait-associated-constant.stderr4
-rw-r--r--src/test/ui/nll/type-alias-free-regions.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr2
-rw-r--r--src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs1
-rw-r--r--src/test/ui/numbers-arithmetic/i128.rs3
-rw-r--r--src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs2
-rw-r--r--src/test/ui/numbers-arithmetic/u128-as-f32.rs1
-rw-r--r--src/test/ui/numbers-arithmetic/u128.rs2
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-elision.stderr8
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr2
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr2
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr2
-rw-r--r--src/test/ui/panic-runtime/transitive-link-a-bunch.rs2
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort.rs2
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort2.rs2
-rw-r--r--src/test/ui/parser/doc-inside-trait-item.stderr1
-rw-r--r--src/test/ui/parser/intersection-patterns.rs40
-rw-r--r--src/test/ui/parser/intersection-patterns.stderr33
-rw-r--r--src/test/ui/parser/mismatched-delim-brace-empty-block.rs5
-rw-r--r--src/test/ui/parser/mismatched-delim-brace-empty-block.stderr14
-rw-r--r--src/test/ui/partialeq_help.stderr1
-rw-r--r--src/test/ui/phantom-oibit.stderr8
-rw-r--r--src/test/ui/precise_pointer_size_matching.rs2
-rw-r--r--src/test/ui/privacy/privacy-ns1.stderr2
-rw-r--r--src/test/ui/privacy/privacy-ns2.stderr2
-rw-r--r--src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs23
-rw-r--r--src/test/ui/proc-macro/auxiliary/more-gates.rs35
-rw-r--r--src/test/ui/proc-macro/expand-with-a-macro.rs2
-rw-r--r--src/test/ui/proc-macro/gen-macro-rules-hygiene.rs23
-rw-r--r--src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr28
-rw-r--r--src/test/ui/proc-macro/more-gates.rs22
-rw-r--r--src/test/ui/proc-macro/more-gates.stderr48
-rw-r--r--src/test/ui/reachable-unnameable-items.rs2
-rw-r--r--src/test/ui/reachable/auxiliary/unreachable_variant.rs (renamed from src/test/ui/unreachable/auxiliary/unreachable_variant.rs)0
-rw-r--r--src/test/ui/reachable/unreachable-arm.rs (renamed from src/test/ui/unreachable/unreachable-arm.rs)0
-rw-r--r--src/test/ui/reachable/unreachable-arm.stderr (renamed from src/test/ui/unreachable/unreachable-arm.stderr)0
-rw-r--r--src/test/ui/reachable/unreachable-code.rs (renamed from src/test/ui/unreachable/unreachable-code.rs)0
-rw-r--r--src/test/ui/reachable/unreachable-code.stderr (renamed from src/test/ui/unreachable/unreachable-code.stderr)0
-rw-r--r--src/test/ui/reachable/unreachable-in-call.rs (renamed from src/test/ui/unreachable/unreachable-in-call.rs)0
-rw-r--r--src/test/ui/reachable/unreachable-in-call.stderr (renamed from src/test/ui/unreachable/unreachable-in-call.stderr)0
-rw-r--r--src/test/ui/reachable/unreachable-loop-patterns.rs (renamed from src/test/ui/unreachable/unreachable-loop-patterns.rs)2
-rw-r--r--src/test/ui/reachable/unreachable-loop-patterns.stderr (renamed from src/test/ui/unreachable/unreachable-loop-patterns.stderr)6
-rw-r--r--src/test/ui/reachable/unreachable-try-pattern.rs (renamed from src/test/ui/unreachable/unreachable-try-pattern.rs)2
-rw-r--r--src/test/ui/reachable/unreachable-try-pattern.stderr (renamed from src/test/ui/unreachable/unreachable-try-pattern.stderr)0
-rw-r--r--src/test/ui/reachable/unreachable-variant.rs (renamed from src/test/ui/unreachable/unreachable-variant.rs)0
-rw-r--r--src/test/ui/reachable/unreachable-variant.stderr (renamed from src/test/ui/unreachable/unreachable-variant.stderr)0
-rw-r--r--src/test/ui/reachable/unwarned-match-on-never.rs (renamed from src/test/ui/unreachable/unwarned-match-on-never.rs)0
-rw-r--r--src/test/ui/reachable/unwarned-match-on-never.stderr (renamed from src/test/ui/unreachable/unwarned-match-on-never.stderr)0
-rw-r--r--src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr4
-rw-r--r--src/test/ui/regions/region-invariant-static-error-reporting.rs2
-rw-r--r--src/test/ui/regions/region-invariant-static-error-reporting.stderr2
-rw-r--r--src/test/ui/regions/region-object-lifetime-2.stderr4
-rw-r--r--src/test/ui/regions/region-object-lifetime-4.stderr4
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.stderr4
-rw-r--r--src/test/ui/regions/regions-addr-of-upvar-self.stderr2
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr4
-rw-r--r--src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr6
-rw-r--r--src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr2
-rw-r--r--src/test/ui/regions/regions-bounds.stderr8
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-2.stderr2
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.stderr2
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr4
-rw-r--r--src/test/ui/regions/regions-creating-enums4.stderr4
-rw-r--r--src/test/ui/regions/regions-early-bound-error-method.stderr4
-rw-r--r--src/test/ui/regions/regions-early-bound-error.stderr4
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-callee-4.stderr4
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-incorrect.stderr4
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr4
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr2
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr2
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr2
-rw-r--r--src/test/ui/regions/regions-infer-not-param.stderr12
-rw-r--r--src/test/ui/regions/regions-infer-paramd-indirect.stderr2
-rw-r--r--src/test/ui/regions/regions-nested-fns.stderr2
-rw-r--r--src/test/ui/regions/regions-normalize-in-where-clause-list.stderr4
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr8
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr4
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container.stderr16
-rw-r--r--src/test/ui/regions/regions-ret-borrowed-1.stderr2
-rw-r--r--src/test/ui/regions/regions-ret-borrowed.stderr2
-rw-r--r--src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr2
-rw-r--r--src/test/ui/regions/regions-static-bound.migrate.stderr2
-rw-r--r--src/test/ui/regions/regions-trait-1.stderr2
-rw-r--r--src/test/ui/regions/regions-trait-object-subtyping.stderr12
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-covariant.stderr2
-rw-r--r--src/test/ui/regions/regions-wf-trait-object.stderr4
-rw-r--r--src/test/ui/reject-specialized-drops-8142.stderr6
-rw-r--r--src/test/ui/repr/repr-packed-contains-align.stderr1
-rw-r--r--src/test/ui/resolve/issue-16058.stderr1
-rw-r--r--src/test/ui/resolve/issue-21221-1.stderr2
-rw-r--r--src/test/ui/resolve/issue-2356.stderr18
-rw-r--r--src/test/ui/resolve/levenshtein.stderr4
-rw-r--r--src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs2
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-union.rs5
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-union.rs5
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/nested-union.stderr4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr4
-rw-r--r--src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr4
-rw-r--r--src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs2
-rw-r--r--src/test/ui/rfcs/rfc1857-drop-order.rs2
-rw-r--r--src/test/ui/rust-2018/issue-52202-use-suggestions.stderr2
-rw-r--r--src/test/ui/save-analysis/issue-64659.rs10
-rw-r--r--src/test/ui/save-analysis/issue-65411.rs15
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr4
-rw-r--r--src/test/ui/self/self-in-typedefs.rs11
-rw-r--r--src/test/ui/sepcomp/sepcomp-lib-lto.rs1
-rw-r--r--src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr6
-rw-r--r--src/test/ui/static/static-closures.stderr1
-rw-r--r--src/test/ui/static/static-lifetime.stderr2
-rw-r--r--src/test/ui/suggestions/constrain-trait.fixed47
-rw-r--r--src/test/ui/suggestions/constrain-trait.rs47
-rw-r--r--src/test/ui/suggestions/constrain-trait.stderr27
-rw-r--r--src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs25
-rw-r--r--src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr43
-rw-r--r--src/test/ui/suggestions/restrict-type-argument.rs31
-rw-r--r--src/test/ui/suggestions/restrict-type-argument.stderr83
-rw-r--r--src/test/ui/symbol-names/impl1.legacy.stderr4
-rw-r--r--src/test/ui/synthetic-param.rs6
-rw-r--r--src/test/ui/synthetic-param.stderr6
-rw-r--r--src/test/ui/test-attrs/test-allow-fail-attr.rs2
-rw-r--r--src/test/ui/test-attrs/test-should-fail-good-message.rs2
-rw-r--r--src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr3
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-wf.stderr7
-rw-r--r--src/test/ui/traits/trait-as-struct-constructor.stderr1
-rw-r--r--src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr14
-rw-r--r--src/test/ui/traits/trait-impl-for-module.stderr1
-rw-r--r--src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr4
-rw-r--r--src/test/ui/traits/trait-matching-lifetimes.stderr8
-rw-r--r--src/test/ui/traits/trait-suggest-where-clause.stderr10
-rw-r--r--src/test/ui/traits/traits-repeated-supertrait-ambig.stderr8
-rw-r--r--src/test/ui/try-block/try-block-in-edition2015.stderr1
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr8
-rw-r--r--src/test/ui/type/type-ascription-with-fn-call.stderr1
-rw-r--r--src/test/ui/type/type-check-defaults.stderr7
-rw-r--r--src/test/ui/type/type-params-in-different-spaces-2.stderr8
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed17
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs2
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr5
-rw-r--r--src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr3
-rw-r--r--src/test/ui/ufcs/ufcs-explicit-self-bad.stderr8
-rw-r--r--src/test/ui/ufcs/ufcs-partially-resolved.stderr2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs1
-rw-r--r--src/test/ui/underscore-imports/hygiene-2.rs33
-rw-r--r--src/test/ui/underscore-imports/hygiene.rs40
-rw-r--r--src/test/ui/underscore-imports/hygiene.stderr27
-rw-r--r--src/test/ui/underscore-imports/macro-expanded.rs45
-rw-r--r--src/test/ui/uninhabited/always-inhabited-union-ref.rs (renamed from src/test/ui/always-inhabited-union-ref.rs)0
-rw-r--r--src/test/ui/uninhabited/always-inhabited-union-ref.stderr (renamed from src/test/ui/always-inhabited-union-ref.stderr)0
-rw-r--r--src/test/ui/union/issue-41073.rs24
-rw-r--r--src/test/ui/union/issue-41073.stderr15
-rw-r--r--src/test/ui/union/union-borrow-move-parent-sibling.rs61
-rw-r--r--src/test/ui/union/union-borrow-move-parent-sibling.stderr34
-rw-r--r--src/test/ui/union/union-custom-drop.rs19
-rw-r--r--src/test/ui/union/union-custom-drop.stderr15
-rw-r--r--src/test/ui/union/union-derive-clone.rs13
-rw-r--r--src/test/ui/union/union-derive-clone.stderr12
-rw-r--r--src/test/ui/union/union-derive-rpass.rs5
-rw-r--r--src/test/ui/union/union-drop-assign.rs11
-rw-r--r--src/test/ui/union/union-drop.rs11
-rw-r--r--src/test/ui/union/union-generic-rpass.rs18
-rw-r--r--src/test/ui/union/union-manuallydrop-rpass.rs42
-rw-r--r--src/test/ui/union/union-nodrop.rs15
-rw-r--r--src/test/ui/union/union-overwrite.rs14
-rw-r--r--src/test/ui/union/union-sized-field.stderr9
-rw-r--r--src/test/ui/union/union-unsafe.rs34
-rw-r--r--src/test/ui/union/union-unsafe.stderr66
-rw-r--r--src/test/ui/union/union-with-drop-fields-lint-rpass.rs32
-rw-r--r--src/test/ui/union/union-with-drop-fields-lint.stderr26
-rw-r--r--src/test/ui/union/union-with-drop-fields.rs (renamed from src/test/ui/union/union-with-drop-fields-lint.rs)7
-rw-r--r--src/test/ui/union/union-with-drop-fields.stderr39
-rw-r--r--src/test/ui/unsized/unsized-bare-typaram.stderr5
-rw-r--r--src/test/ui/unsized/unsized-enum.stderr5
-rw-r--r--src/test/ui/unsized/unsized-enum2.stderr16
-rw-r--r--src/test/ui/unsized/unsized-inherent-impl-self-type.stderr5
-rw-r--r--src/test/ui/unsized/unsized-struct.stderr10
-rw-r--r--src/test/ui/unsized/unsized-trait-impl-self-type.stderr5
-rw-r--r--src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr5
-rw-r--r--src/test/ui/unsized3.stderr18
-rw-r--r--src/test/ui/unsized5.stderr13
-rw-r--r--src/test/ui/unsized6.stderr51
-rw-r--r--src/test/ui/unsized7.stderr5
-rw-r--r--src/test/ui/use/issue-18986.stderr1
-rw-r--r--src/test/ui/variance/variance-btree-invariant-types.stderr24
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.stderr8
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-trait-match.stderr8
-rw-r--r--src/test/ui/variance/variance-contravariant-self-trait-match.stderr8
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.stderr8
-rw-r--r--src/test/ui/variance/variance-covariant-arg-trait-match.stderr8
-rw-r--r--src/test/ui/variance/variance-covariant-self-trait-match.stderr8
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.stderr8
-rw-r--r--src/test/ui/variance/variance-invariant-arg-trait-match.stderr8
-rw-r--r--src/test/ui/variance/variance-invariant-self-trait-match.stderr8
-rw-r--r--src/test/ui/variance/variance-use-contravariant-struct-1.stderr4
-rw-r--r--src/test/ui/variance/variance-use-covariant-struct-1.stderr4
-rw-r--r--src/test/ui/variance/variance-use-invariant-struct-1.stderr8
-rw-r--r--src/test/ui/variants/variant-used-as-type.stderr1
-rw-r--r--src/test/ui/wf/issue-48638.rs21
-rw-r--r--src/test/ui/wf/wf-enum-bound.stderr3
-rw-r--r--src/test/ui/wf/wf-enum-fields-struct-variant.stderr5
-rw-r--r--src/test/ui/wf/wf-enum-fields.stderr4
-rw-r--r--src/test/ui/wf/wf-fn-where-clause.stderr7
-rw-r--r--src/test/ui/wf/wf-impl-associated-type-trait.stderr4
-rw-r--r--src/test/ui/wf/wf-in-fn-arg.stderr7
-rw-r--r--src/test/ui/wf/wf-in-fn-ret.stderr7
-rw-r--r--src/test/ui/wf/wf-in-fn-type-arg.stderr5
-rw-r--r--src/test/ui/wf/wf-in-fn-type-ret.stderr5
-rw-r--r--src/test/ui/wf/wf-in-fn-where-clause.stderr3
-rw-r--r--src/test/ui/wf/wf-in-obj-type-trait.stderr5
-rw-r--r--src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr4
-rw-r--r--src/test/ui/wf/wf-inherent-impl-where-clause.stderr7
-rw-r--r--src/test/ui/wf/wf-static-method.stderr20
-rw-r--r--src/test/ui/wf/wf-struct-bound.stderr3
-rw-r--r--src/test/ui/wf/wf-struct-field.stderr4
-rw-r--r--src/test/ui/wf/wf-trait-associated-type-bound.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-associated-type-trait.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-bound.stderr3
-rw-r--r--src/test/ui/wf/wf-trait-default-fn-arg.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-default-fn-ret.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-default-fn-where-clause.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-fn-arg.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-fn-ret.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-fn-where-clause.stderr7
-rw-r--r--src/test/ui/wf/wf-trait-superbound.stderr7
-rw-r--r--src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr5
-rw-r--r--src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr5
m---------src/tools/cargo0
m---------src/tools/clippy35
-rw-r--r--src/tools/compiletest/src/header.rs5
m---------src/tools/miri16
-rw-r--r--src/tools/tidy/src/debug_artifacts.rs24
-rw-r--r--src/tools/tidy/src/lib.rs2
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--triagebot.toml11
1082 files changed, 14624 insertions, 10691 deletions
diff --git a/.gitignore b/.gitignore
index 81a472451d7..487867c375d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,10 @@
-# This file should only ignore things that are generated during a build,
-# generated by common IDEs, and optional files controlled by the user
-# that affect the build (such as config.toml).
+# This file should only ignore things that are generated during a `x.py` build,
+# generated by common IDEs, and optional files controlled by the user that
+# affect the build (such as config.toml).
+# In particular, things like `mir_dump` should not be listed here; they are only
+# created during manual debugging and many people like to clean up instead of
+# having git ignore such leftovers. You can use `.git/info/exclude` to
+# configure your local ignore list.
 # FIXME: This needs cleanup.
 *~
 .#*
@@ -52,3 +56,4 @@ config.stamp
 Session.vim
 .cargo
 no_llvm_build
+# Before adding new lines, see the comment at the top.
diff --git a/.gitmodules b/.gitmodules
index 3ff5af78097..1dcf9ed319f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -28,9 +28,6 @@
 [submodule "src/doc/rust-by-example"]
 	path = src/doc/rust-by-example
 	url = https://github.com/rust-lang/rust-by-example.git
-[submodule "src/llvm-emscripten"]
-	path = src/llvm-emscripten
-	url = https://github.com/rust-lang/llvm.git
 [submodule "src/stdarch"]
 	path = src/stdarch
 	url = https://github.com/rust-lang/stdarch.git
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c3a9a68963e..37a217d2a04 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -128,6 +128,14 @@ the master branch to your feature branch.
 Also, please make sure that fixup commits are squashed into other related
 commits with meaningful commit messages.
 
+GitHub allows [closing issues using keywords][closing-keywords]. This feature
+should be used to keep the issue tracker tidy. However, it is generally preferred
+to put the "closes #123" text in the PR description rather than the issue commit;
+particularly during rebasing, citing the issue number in the commit can "spam"
+the issue in question.
+
+[closing-keywords]: https://help.github.com/en/articles/closing-issues-using-keywords
+
 Please make sure your pull request is in compliance with Rust's style
 guidelines by running
 
diff --git a/Cargo.lock b/Cargo.lock
index 844320fff3f..3f37a1b7eb0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -556,9 +556,9 @@ dependencies = [
 
 [[package]]
 name = "compiletest_rs"
-version = "0.3.23"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb783fe7afb90ec3d3e49ccaf9196d29ab63c6ed61d4b0695839daa580ae3a3d"
+checksum = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a"
 dependencies = [
  "diff",
  "filetime",
@@ -1713,9 +1713,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
 
 [[package]]
 name = "libc"
-version = "0.2.62"
+version = "0.2.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
+checksum = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -3112,6 +3112,7 @@ dependencies = [
  "serialize",
  "smallvec",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
 ]
 
@@ -3427,6 +3428,7 @@ dependencies = [
  "rustc_target",
  "serialize",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
  "tempfile",
 ]
@@ -3554,11 +3556,13 @@ dependencies = [
  "rustc_plugin_impl",
  "rustc_privacy",
  "rustc_resolve",
+ "rustc_target",
  "rustc_traits",
  "rustc_typeck",
  "serialize",
  "smallvec",
  "syntax",
+ "syntax_expand",
  "syntax_ext",
  "syntax_pos",
  "tempfile",
@@ -3630,6 +3634,7 @@ dependencies = [
  "smallvec",
  "stable_deref_trait",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
 ]
 
@@ -3678,6 +3683,7 @@ dependencies = [
  "rustc_index",
  "rustc_target",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
 ]
 
@@ -3695,6 +3701,7 @@ dependencies = [
  "rustc",
  "rustc_metadata",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
 ]
 
@@ -3723,6 +3730,7 @@ dependencies = [
  "rustc_metadata",
  "smallvec",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
 ]
 
@@ -4337,6 +4345,25 @@ dependencies = [
 ]
 
 [[package]]
+name = "syntax_expand"
+version = "0.0.0"
+dependencies = [
+ "bitflags",
+ "lazy_static 1.3.0",
+ "log",
+ "rustc_data_structures",
+ "rustc_errors",
+ "rustc_index",
+ "rustc_lexer",
+ "rustc_target",
+ "scoped-tls",
+ "serialize",
+ "smallvec",
+ "syntax",
+ "syntax_pos",
+]
+
+[[package]]
 name = "syntax_ext"
 version = "0.0.0"
 dependencies = [
@@ -4347,6 +4374,7 @@ dependencies = [
  "rustc_target",
  "smallvec",
  "syntax",
+ "syntax_expand",
  "syntax_pos",
 ]
 
diff --git a/config.toml.example b/config.toml.example
index 848147c2974..be977024426 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -374,9 +374,7 @@
 
 # This is an array of the codegen backends that will be compiled for the rustc
 # that's being compiled. The default is to only build the LLVM codegen backend,
-# but you can also optionally enable the "emscripten" backend for asm.js or
-# make this an empty array (but that probably won't get too far in the
-# bootstrap)
+# and currently the only standard option supported is `"llvm"`
 #codegen-backends = ["llvm"]
 
 # This is the name of the directory in which codegen backends will get installed
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 65129eeeec5..4caf36a6f2a 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -734,10 +734,6 @@ class RustBuild(object):
             if module.endswith("llvm-project"):
                 if self.get_toml('llvm-config') and self.get_toml('lld') != 'true':
                     continue
-            if module.endswith("llvm-emscripten"):
-                backends = self.get_toml('codegen-backends')
-                if backends is None or not 'emscripten' in backends:
-                    continue
             check = self.check_submodule(module, slow_submodules)
             filtered_submodules.append((module, check))
             submodules_names.append(module)
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 0caf2d9b6db..b8071b98f70 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -980,6 +980,7 @@ impl<'a> Builder<'a> {
                 Some("-Wl,-rpath,@loader_path/../lib")
             } else if !target.contains("windows") &&
                       !target.contains("wasm32") &&
+                      !target.contains("emscripten") &&
                       !target.contains("fuchsia") {
                 Some("-Wl,-rpath,$ORIGIN/../lib")
             } else {
diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs
index 53071df8552..4310f2c6fa1 100644
--- a/src/bootstrap/cache.rs
+++ b/src/bootstrap/cache.rs
@@ -161,7 +161,7 @@ impl Ord for Interned<String> {
     }
 }
 
-struct TyIntern<T: Hash + Clone + Eq> {
+struct TyIntern<T: Clone + Eq> {
     items: Vec<T>,
     set: HashMap<T, Interned<T>>,
 }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 6ea32edfb20..5074b035789 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -210,7 +210,6 @@ pub fn std_cargo(builder: &Builder<'_>,
             // config.toml equivalent) is used
             let llvm_config = builder.ensure(native::Llvm {
                 target: builder.config.build,
-                emscripten: false,
             });
             cargo.env("LLVM_CONFIG", llvm_config);
             cargo.env("RUSTC_BUILD_SANITIZERS", "1");
@@ -615,36 +614,27 @@ pub fn build_codegen_backend(builder: &Builder<'_>,
                              compiler: &Compiler,
                              target: Interned<String>,
                              backend: Interned<String>) -> String {
-    let mut features = String::new();
-
     match &*backend {
-        "llvm" | "emscripten" => {
+        "llvm" => {
             // Build LLVM for our target. This will implicitly build the
             // host LLVM if necessary.
             let llvm_config = builder.ensure(native::Llvm {
                 target,
-                emscripten: backend == "emscripten",
             });
 
-            if backend == "emscripten" {
-                features.push_str(" emscripten");
-            }
-
             builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
                      compiler.stage, &compiler.host, target, backend));
 
             // Pass down configuration from the LLVM build into the build of
             // librustc_llvm and librustc_codegen_llvm.
-            if builder.is_rust_llvm(target) && backend != "emscripten" {
+            if builder.is_rust_llvm(target) {
                 cargo.env("LLVM_RUSTLLVM", "1");
             }
 
             cargo.env("LLVM_CONFIG", &llvm_config);
-            if backend != "emscripten" {
-                let target_config = builder.config.target_config.get(&target);
-                if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
-                    cargo.env("CFG_LLVM_ROOT", s);
-                }
+            let target_config = builder.config.target_config.get(&target);
+            if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
+                cargo.env("CFG_LLVM_ROOT", s);
             }
             // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm.
             if let Some(ref s) = builder.config.llvm_ldflags {
@@ -662,9 +652,7 @@ pub fn build_codegen_backend(builder: &Builder<'_>,
                                          "libstdc++.a");
                 cargo.env("LLVM_STATIC_STDCPP", file);
             }
-            if builder.config.llvm_link_shared ||
-                (builder.config.llvm_thin_lto && backend != "emscripten")
-            {
+            if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
                 cargo.env("LLVM_LINK_SHARED", "1");
             }
             if builder.config.llvm_use_libcxx {
@@ -676,8 +664,7 @@ pub fn build_codegen_backend(builder: &Builder<'_>,
         }
         _ => panic!("unknown backend: {}", backend),
     }
-
-    features
+    String::new()
 }
 
 /// Creates the `codegen-backends` folder for a compiler that's about to be
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 52b5cd888df..441bb8d68fa 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -668,7 +668,6 @@ impl Config {
 
     pub fn llvm_enabled(&self) -> bool {
         self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
-        || self.rust_codegen_backends.contains(&INTERNER.intern_str("emscripten"))
     }
 }
 
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 346f0cb2039..76509134f7c 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -55,7 +55,6 @@ o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, m
 o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
 o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
 o("profiler", "build.profiler", "build the profiler runtime")
-o("emscripten", None, "compile the emscripten backend as well as LLVM")
 o("full-tools", None, "enable all tools")
 o("lld", "rust.lld", "build lld")
 o("lldb", "rust.lldb", "build lldb")
@@ -335,10 +334,8 @@ for key in known_args:
         set('build.host', value.split(','))
     elif option.name == 'target':
         set('build.target', value.split(','))
-    elif option.name == 'emscripten':
-        set('rust.codegen-backends', ['llvm', 'emscripten'])
     elif option.name == 'full-tools':
-        set('rust.codegen-backends', ['llvm', 'emscripten'])
+        set('rust.codegen-backends', ['llvm'])
         set('rust.lld', True)
         set('rust.llvm-tools', True)
         set('build.extended', True)
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index d9dff77a30e..514ad114449 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -826,7 +826,6 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str]
 
         const LLVM_TEST: &[&str] = &[
             "llvm-project/llvm/test", "llvm-project\\llvm\\test",
-            "llvm-emscripten/test", "llvm-emscripten\\test",
         ];
         if LLVM_TEST.iter().any(|path| spath.contains(path)) &&
             (spath.ends_with(".ll") ||
@@ -834,9 +833,6 @@ fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str]
              spath.ends_with(".s")) {
             return false
         }
-        if spath.contains("test/emscripten") || spath.contains("test\\emscripten") {
-            return false
-        }
 
         let full_path = Path::new(dir).join(path);
         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 9203a558f64..a182405f3b2 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -232,7 +232,6 @@ pub struct Build {
     miri_info: channel::GitInfo,
     rustfmt_info: channel::GitInfo,
     in_tree_llvm_info: channel::GitInfo,
-    emscripten_llvm_info: channel::GitInfo,
     local_rebuild: bool,
     fail_fast: bool,
     doc_tests: DocTests,
@@ -351,7 +350,6 @@ impl Build {
 
         // we always try to use git for LLVM builds
         let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project"));
-        let emscripten_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-emscripten"));
 
         let mut build = Build {
             initial_rustc: config.initial_rustc.clone(),
@@ -376,7 +374,6 @@ impl Build {
             miri_info,
             rustfmt_info,
             in_tree_llvm_info,
-            emscripten_llvm_info,
             cc: HashMap::new(),
             cxx: HashMap::new(),
             ar: HashMap::new(),
@@ -553,10 +550,6 @@ impl Build {
         self.out.join(&*target).join("llvm")
     }
 
-    fn emscripten_llvm_out(&self, target: Interned<String>) -> PathBuf {
-        self.out.join(&*target).join("llvm-emscripten")
-    }
-
     fn lld_out(&self, target: Interned<String>) -> PathBuf {
         self.out.join(&*target).join("lld")
     }
@@ -1126,7 +1119,7 @@ impl Build {
         }
 
         let mut paths = Vec::new();
-        let contents = t!(fs::read(stamp));
+        let contents = t!(fs::read(stamp), &stamp);
         // This is the method we use for extracting paths from the stamp file passed to us. See
         // run_cargo for more information (in compile.rs).
         for part in contents.split(|b| *b == 0) {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 7bf9ea2688f..97cdd256801 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -28,7 +28,6 @@ use crate::GitRepo;
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
     pub target: Interned<String>,
-    pub emscripten: bool,
 }
 
 impl Step for Llvm {
@@ -40,46 +39,35 @@ impl Step for Llvm {
         run.path("src/llvm-project")
             .path("src/llvm-project/llvm")
             .path("src/llvm")
-            .path("src/llvm-emscripten")
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let emscripten = run.path.ends_with("llvm-emscripten");
         run.builder.ensure(Llvm {
             target: run.target,
-            emscripten,
         });
     }
 
     /// Compile LLVM for `target`.
     fn run(self, builder: &Builder<'_>) -> PathBuf {
         let target = self.target;
-        let emscripten = self.emscripten;
 
         // If we're using a custom LLVM bail out here, but we can only use a
         // custom LLVM for the build triple.
-        if !self.emscripten {
-            if let Some(config) = builder.config.target_config.get(&target) {
-                if let Some(ref s) = config.llvm_config {
-                    check_llvm_version(builder, s);
-                    return s.to_path_buf()
-                }
+        if let Some(config) = builder.config.target_config.get(&target) {
+            if let Some(ref s) = config.llvm_config {
+                check_llvm_version(builder, s);
+                return s.to_path_buf()
             }
         }
 
-        let (llvm_info, root, out_dir, llvm_config_ret_dir) = if emscripten {
-            let info = &builder.emscripten_llvm_info;
-            let dir = builder.emscripten_llvm_out(target);
-            let config_dir = dir.join("bin");
-            (info, "src/llvm-emscripten", dir, config_dir)
-        } else {
-            let info = &builder.in_tree_llvm_info;
-            let mut dir = builder.llvm_out(builder.config.build);
-            if !builder.config.build.contains("msvc") || builder.config.ninja {
-                dir.push("build");
-            }
-            (info, "src/llvm-project/llvm", builder.llvm_out(target), dir.join("bin"))
-        };
+        let llvm_info = &builder.in_tree_llvm_info;
+        let root = "src/llvm-project/llvm";
+        let out_dir = builder.llvm_out(target);
+        let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
+        if !builder.config.build.contains("msvc") || builder.config.ninja {
+            llvm_config_ret_dir.push("build");
+        }
+        llvm_config_ret_dir.push("bin");
 
         let build_llvm_config = llvm_config_ret_dir
             .join(exe("llvm-config", &*builder.config.build));
@@ -107,8 +95,7 @@ impl Step for Llvm {
             }
         }
 
-        let descriptor = if emscripten { "Emscripten " } else { "" };
-        builder.info(&format!("Building {}LLVM for {}", descriptor, target));
+        builder.info(&format!("Building LLVM for {}", target));
         let _time = util::timeit(&builder);
         t!(fs::create_dir_all(&out_dir));
 
@@ -123,23 +110,15 @@ impl Step for Llvm {
 
         // NOTE: remember to also update `config.toml.example` when changing the
         // defaults!
-        let llvm_targets = if self.emscripten {
-            "JSBackend"
-        } else {
-            match builder.config.llvm_targets {
-                Some(ref s) => s,
-                None => "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
-                         Sparc;SystemZ;WebAssembly;X86",
-            }
+        let llvm_targets = match &builder.config.llvm_targets {
+            Some(s) => s,
+            None => "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
+                     Sparc;SystemZ;WebAssembly;X86",
         };
 
-        let llvm_exp_targets = if self.emscripten {
-            ""
-        } else {
-            match builder.config.llvm_experimental_targets {
-                Some(ref s) => s,
-                None => "",
-            }
+        let llvm_exp_targets = match builder.config.llvm_experimental_targets {
+            Some(ref s) => s,
+            None => "",
         };
 
         let assertions = if builder.config.llvm_assertions {"ON"} else {"OFF"};
@@ -157,39 +136,29 @@ impl Step for Llvm {
            .define("WITH_POLLY", "OFF")
            .define("LLVM_ENABLE_TERMINFO", "OFF")
            .define("LLVM_ENABLE_LIBEDIT", "OFF")
+           .define("LLVM_ENABLE_BINDINGS", "OFF")
            .define("LLVM_ENABLE_Z3_SOLVER", "OFF")
            .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
            .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
            .define("LLVM_DEFAULT_TARGET_TRIPLE", target);
 
-        if builder.config.llvm_thin_lto && !emscripten {
+        if builder.config.llvm_thin_lto {
             cfg.define("LLVM_ENABLE_LTO", "Thin");
             if !target.contains("apple") {
                cfg.define("LLVM_ENABLE_LLD", "ON");
             }
         }
 
-        // By default, LLVM will automatically find OCaml and, if it finds it,
-        // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults
-        // to /usr/bin/ocaml.
-        // This causes problem for non-root builds of Rust. Side-step the issue
-        // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs
-        // in the prefix.
-        cfg.define("LLVM_OCAML_INSTALL_PATH",
-            env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into()));
-
-        let want_lldb = builder.config.lldb_enabled && !self.emscripten;
-
         // This setting makes the LLVM tools link to the dynamic LLVM library,
         // which saves both memory during parallel links and overall disk space
         // for the tools. We don't do this on every platform as it doesn't work
         // equally well everywhere.
-        if builder.llvm_link_tools_dynamically(target) && !emscripten {
+        if builder.llvm_link_tools_dynamically(target) {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
         // For distribution we want the LLVM tools to be *statically* linked to libstdc++
-        if builder.config.llvm_tools_enabled || want_lldb {
+        if builder.config.llvm_tools_enabled || builder.config.lldb_enabled {
             if !target.contains("windows") {
                 if target.contains("apple") {
                     cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++");
@@ -217,7 +186,7 @@ impl Step for Llvm {
             enabled_llvm_projects.push("compiler-rt");
         }
 
-        if want_lldb {
+        if builder.config.lldb_enabled {
             enabled_llvm_projects.push("clang");
             enabled_llvm_projects.push("lldb");
             // For the time being, disable code signing.
@@ -242,10 +211,9 @@ impl Step for Llvm {
         }
 
         // http://llvm.org/docs/HowToCrossCompileLLVM.html
-        if target != builder.config.build && !emscripten {
+        if target != builder.config.build {
             builder.ensure(Llvm {
                 target: builder.config.build,
-                emscripten: false,
             });
             // FIXME: if the llvm root for the build triple is overridden then we
             //        should use llvm-tblgen from there, also should verify that it
@@ -489,7 +457,6 @@ impl Step for Lld {
 
         let llvm_config = builder.ensure(Llvm {
             target: self.target,
-            emscripten: false,
         });
 
         let out_dir = builder.lld_out(target);
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index b7ce9c7b397..7ed67c6c7c5 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -427,7 +427,7 @@ impl Step for Miri {
             // (We do this separately from the above so that when the setup actually
             // happens we get some output.)
             // We re-use the `cargo` from above.
-            cargo.arg("--env");
+            cargo.arg("--print-sysroot");
 
             // FIXME: Is there a way in which we can re-use the usual `run` helpers?
             let miri_sysroot = if builder.config.dry_run {
@@ -437,13 +437,11 @@ impl Step for Miri {
                 let out = cargo.output()
                     .expect("We already ran `cargo miri setup` before and that worked");
                 assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
-                // Output is "MIRI_SYSROOT=<str>\n".
+                // Output is "<sysroot>\n".
                 let stdout = String::from_utf8(out.stdout)
                     .expect("`cargo miri setup` stdout is not valid UTF-8");
-                let stdout = stdout.trim();
-                builder.verbose(&format!("`cargo miri setup --env` returned: {:?}", stdout));
-                let sysroot = stdout.splitn(2, '=')
-                    .nth(1).expect("`cargo miri setup` stdout did not contain '='");
+                let sysroot = stdout.trim_end();
+                builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
                 sysroot.to_owned()
             };
 
@@ -1047,10 +1045,11 @@ impl Step for Compiletest {
         // Also provide `rust_test_helpers` for the host.
         builder.ensure(native::TestHelpers { target: compiler.host });
 
-        // wasm32 can't build the test helpers
-        if !target.contains("wasm32") {
+        // As well as the target, except for plain wasm32, which can't build it
+        if !target.contains("wasm32") || target.contains("emscripten") {
             builder.ensure(native::TestHelpers { target });
         }
+
         builder.ensure(RemoteCopyLibs { compiler, target });
 
         let mut cmd = builder.tool_cmd(Tool::Compiletest);
@@ -1164,7 +1163,7 @@ impl Step for Compiletest {
                     }).to_string()
             })
         };
-        let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
+        let lldb_exe = if builder.config.lldb_enabled {
             // Test against the lldb that was just built.
             builder.llvm_out(target).join("bin").join("lldb")
         } else {
@@ -1233,7 +1232,6 @@ impl Step for Compiletest {
         if builder.config.llvm_enabled() {
             let llvm_config = builder.ensure(native::Llvm {
                 target: builder.config.build,
-                emscripten: false,
             });
             if !builder.config.dry_run {
                 let llvm_version = output(Command::new(&llvm_config).arg("--version"));
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index f035a711918..bb94fb2b755 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -21,6 +21,13 @@ macro_rules! t {
             Err(e) => panic!("{} failed with {}", stringify!($e), e),
         }
     };
+    // it can show extra info in the second parameter
+    ($e:expr, $extra:expr) => {
+        match $e {
+            Ok(e) => e,
+            Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra),
+        }
+    };
 }
 
 // Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml
index 5f776129709..4442afc98e4 100644
--- a/src/ci/azure-pipelines/auto.yml
+++ b/src/ci/azure-pipelines/auto.yml
@@ -124,14 +124,14 @@ jobs:
         IMAGE: dist-x86_64-netbsd
         DEPLOY: 1
 
-      asmjs:
-        IMAGE: asmjs
       i686-gnu:
         IMAGE: i686-gnu
       i686-gnu-nopt:
         IMAGE: i686-gnu-nopt
       test-various:
         IMAGE: test-various
+      wasm32:
+        IMAGE: wasm32
       x86_64-gnu:
         IMAGE: x86_64-gnu
       x86_64-gnu-full-bootstrap:
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 367e4384992..a2d83eca24b 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -165,8 +165,7 @@ For targets: `arm-unknown-linux-gnueabihf`
 For targets: `armv7-unknown-linux-gnueabihf`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Patches origin = Bundled only
 - Target options > Target Architecture = arm
 - Target options > Suffix to the arch-part = v7
 - Target options > Architecture level = armv7-a -- (+)
@@ -174,9 +173,9 @@ For targets: `armv7-unknown-linux-gnueabihf`
 - Target options > Floating point = hardware (FPU) -- (\*)
 - Target options > Default instruction set mode = thumb -- (\*)
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 3.2.72 -- Precise kernel
-- C-library > glibc version = 2.16.0
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- C-library > glibc version = 2.17.0
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 (\*) These options have been selected to match the configuration of the arm
diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile
deleted file mode 100644
index 3abaab6b34e..00000000000
--- a/src/ci/docker/asmjs/Dockerfile
+++ /dev/null
@@ -1,47 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils
-
-COPY scripts/emscripten.sh /scripts/
-RUN bash /scripts/emscripten.sh
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV PATH=$PATH:/emsdk-portable
-ENV PATH=$PATH:/emsdk-portable/clang/e1.38.15_64bit/
-ENV PATH=$PATH:/emsdk-portable/emscripten/1.38.15/
-ENV PATH=$PATH:/emsdk-portable/node/8.9.1_64bit/bin/
-ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.38.15/
-ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.38.15_64bit/binaryen/
-ENV EM_CONFIG=/emsdk-portable/.emscripten
-
-ENV TARGETS=asmjs-unknown-emscripten
-
-ENV RUST_CONFIGURE_ARGS --enable-emscripten --disable-optimize-tests
-
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
-  src/test/ui \
-  src/test/run-fail \
-  src/libstd \
-  src/liballoc \
-  src/libcore
-
-# Debug assertions in rustc are largely covered by other builders, and LLVM
-# assertions cause this builder to slow down by quite a large amount and don't
-# buy us a huge amount over other builders (not sure if we've ever seen an
-# asmjs-specific backend assertion trip), so disable assertions for these
-# tests.
-ENV NO_LLVM_ASSERTIONS=1
-ENV NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/disabled/asmjs/Dockerfile b/src/ci/docker/disabled/asmjs/Dockerfile
new file mode 100644
index 00000000000..e27a2a529a8
--- /dev/null
+++ b/src/ci/docker/disabled/asmjs/Dockerfile
@@ -0,0 +1,41 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  bzip2
+
+COPY scripts/emscripten.sh /scripts/
+RUN bash /scripts/emscripten.sh
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV PATH=$PATH:/emsdk-portable
+ENV PATH=$PATH:/emsdk-portable/upstream/emscripten/
+ENV PATH=$PATH:/emsdk-portable/node/12.9.1_64bit/bin/
+ENV BINARYEN_ROOT=/emsdk-portable/upstream/
+
+ENV TARGETS=asmjs-unknown-emscripten
+
+# Use -O1 optimizations in the link step to reduce time spent optimizing JS.
+ENV EMCC_CFLAGS=-O1
+
+# Emscripten installation is user-specific
+ENV NO_CHANGE_USER=1
+
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS
+
+# This is almost identical to the wasm32-unknown-emscripten target, so
+# running with assertions again is not useful
+ENV NO_DEBUG_ASSERTIONS=1
+ENV NO_LLVM_ASSERTIONS=1
diff --git a/src/ci/docker/disabled/wasm32-exp/Dockerfile b/src/ci/docker/disabled/wasm32-exp/Dockerfile
deleted file mode 100644
index 420d47b314c..00000000000
--- a/src/ci/docker/disabled/wasm32-exp/Dockerfile
+++ /dev/null
@@ -1,35 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils \
-  jq \
-  bzip2
-
-# emscripten
-COPY scripts/emscripten-wasm.sh /scripts/
-COPY wasm32-exp/node.sh /usr/local/bin/node
-RUN bash /scripts/emscripten-wasm.sh
-
-# cache
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# env
-ENV PATH=/wasm-install/emscripten:/wasm-install/bin:$PATH
-ENV EM_CONFIG=/root/.emscripten
-
-ENV TARGETS=wasm32-experimental-emscripten
-
-ENV RUST_CONFIGURE_ARGS --experimental-targets=WebAssembly
-
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS
diff --git a/src/ci/docker/disabled/wasm32-exp/node.sh b/src/ci/docker/disabled/wasm32-exp/node.sh
deleted file mode 100755
index aa938971c70..00000000000
--- a/src/ci/docker/disabled/wasm32-exp/node.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-path="$(dirname $1)"
-file="$(basename $1)"
-
-shift
-
-cd "$path"
-exec /node-v8.0.0-linux-x64/bin/node "$file" "$@"
diff --git a/src/ci/docker/disabled/wasm32/Dockerfile b/src/ci/docker/disabled/wasm32/Dockerfile
deleted file mode 100644
index 0d2bd39303e..00000000000
--- a/src/ci/docker/disabled/wasm32/Dockerfile
+++ /dev/null
@@ -1,32 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  make \
-  file \
-  curl \
-  ca-certificates \
-  python \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  xz-utils
-
-# emscripten
-COPY scripts/emscripten.sh /scripts/
-RUN bash /scripts/emscripten.sh
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV PATH=$PATH:/emsdk-portable
-ENV PATH=$PATH:/emsdk-portable/clang/e1.38.15_64bit/
-ENV PATH=$PATH:/emsdk-portable/emscripten/1.38.15/
-ENV PATH=$PATH:/emsdk-portable/node/8.9.1_64bit/bin/
-ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.38.15/
-ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.38.15_64bit/binaryen/
-ENV EM_CONFIG=/emsdk-portable/.emscripten
-
-ENV TARGETS=wasm32-unknown-emscripten
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS
diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile
index 170b8134d3e..417171a861d 100644
--- a/src/ci/docker/dist-armv7-linux/Dockerfile
+++ b/src/ci/docker/dist-armv7-linux/Dockerfile
@@ -3,12 +3,7 @@ FROM ubuntu:16.04
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
+COPY dist-armv7-linux/crosstool-ng.sh /scripts/
 RUN sh /scripts/crosstool-ng.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
@@ -16,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY dist-armv7-linux/patches/ /tmp/patches/
 COPY dist-armv7-linux/build-toolchains.sh dist-armv7-linux/armv7-linux-gnueabihf.config /tmp/
 RUN ./build-toolchains.sh
 
diff --git a/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config
index 5cccfd8444d..81b3d7477ec 100644
--- a/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config
+++ b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config
@@ -1,9 +1,32 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_dtc=y
+CT_CONFIGURE_has_svn=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -21,40 +44,46 @@ CT_MODULES=y
 # Paths
 #
 CT_LOCAL_TARBALLS_DIR=""
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 # CT_USE_MIRROR is not set
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -90,87 +119,82 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+CT_ARCH_ARM=y
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="arm"
-CT_ARCH_SUPPORTS_BOTH_MMU=y
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ARCH=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_SUPPORTS_WITH_FPU=y
-CT_ARCH_SUPPORTS_SOFTFP=y
-CT_ARCH_DEFAULT_HAS_MMU=y
-CT_ARCH_DEFAULT_LE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ARCH="armv7-a"
+CT_ARCH_CHOICE_KSYM="ARM"
 CT_ARCH_CPU=""
 CT_ARCH_TUNE=""
-CT_ARCH_FPU="vfpv3-d16"
-# CT_ARCH_BE is not set
-CT_ARCH_LE=y
-CT_ARCH_32=y
-# CT_ARCH_64 is not set
-CT_ARCH_BITNESS=32
-CT_ARCH_FLOAT_HW=y
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-CT_ARCH_arm=y
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-# CT_ARCH_powerpc is not set
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_ARM_SHOW=y
+
+#
+# Options for arm
+#
+CT_ARCH_ARM_PKG_KSYM=""
+CT_ARCH_ARM_MODE="thumb"
+# CT_ARCH_ARM_MODE_ARM is not set
+CT_ARCH_ARM_MODE_THUMB=y
+# CT_ARCH_ARM_INTERWORKING is not set
+CT_ARCH_ARM_EABI_FORCE=y
+CT_ARCH_ARM_EABI=y
+CT_ARCH_ARM_TUPLE_USE_EABIHF=y
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX="v7"
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_SUPPORTS_BOTH_MMU=y
+CT_ARCH_DEFAULT_HAS_MMU=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_FLAT_FORMAT=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_LE=y
+# CT_ARCH_BE is not set
+CT_ARCH_LE=y
 CT_ARCH_ENDIAN="little"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=32
+CT_ARCH_32=y
+# CT_ARCH_64 is not set
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_SUPPORTS_WITH_FPU=y
+CT_ARCH_SUPPORTS_SOFTFP=y
 CT_ARCH_EXCLUSIVE_WITH_CPU=y
+CT_ARCH_ARCH="armv7-a"
+CT_ARCH_FPU="vfpv3-d16"
 # CT_ARCH_FLOAT_AUTO is not set
+CT_ARCH_FLOAT_HW=y
 # CT_ARCH_FLOAT_SOFTFP is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 CT_ARCH_FLOAT="hard"
 
 #
-# arm other options
-#
-CT_ARCH_ARM_MODE="thumb"
-# CT_ARCH_ARM_MODE_ARM is not set
-CT_ARCH_ARM_MODE_THUMB=y
-# CT_ARCH_ARM_INTERWORKING is not set
-CT_ARCH_ARM_EABI_FORCE=y
-CT_ARCH_ARM_EABI=y
-CT_ARCH_ARM_TUPLE_USE_EABIHF=y
-
-#
 # Toolchain options
 #
 
@@ -182,7 +206,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -216,126 +242,207 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="3.2.72"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-CT_KERNEL_V_3_2=y
-# CT_KERNEL_V_2_6_32 is not set
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
-CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
-CT_BINUTILS_GOLD_SUPPORT=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
+CT_BINUTILS_GOLD_SUPPORT=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 # CT_BINUTILS_LINKER_LD_GOLD is not set
-# CT_BINUTILS_LINKER_GOLD_LD is not set
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.16.0"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-CT_LIBC_GLIBC_V_2_16_0=y
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -343,100 +450,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
 #
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_GLIBC_MAY_FORCE_PORTS=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-CT_LIBC_GLIBC_USE_PORTS=y
-CT_LIBC_ADDONS_LIST=""
-
-#
-# WARNING !!!                                            
-#
-
-#
-#   For glibc >= 2.8, it can happen that the tarballs    
-#
-
-#
-#   for the addons are not available for download.       
-#
-
-#
-#   If that happens, bad luck... Try a previous version  
-#
-
-#
-#   or try again later... :-(                            
-#
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="3.2.72"
-
-#
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -465,97 +543,206 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+# CT_MPC_V_1_1 is not set
+CT_MPC_V_1_0=y
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.0.3"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_older=y
+CT_MPC_older_than_1_1_0=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_3_1=y
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="3.1.6"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_4_0_0_or_older=y
+CT_MPFR_older_than_4_0_0=y
+CT_MPFR_REQUIRE_older_than_4_0_0=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/dist-armv7-linux/crosstool-ng.sh b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh
new file mode 100644
index 00000000000..ae737d9677d
--- /dev/null
+++ b/src/ci/docker/dist-armv7-linux/crosstool-ng.sh
@@ -0,0 +1,12 @@
+set -ex
+
+# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
+url="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/crosstool-ng-1.24.0.tar.gz"
+curl -Lf $url | tar xzf -
+cd crosstool-ng-crosstool-ng-1.24.0
+./bootstrap
+./configure --prefix=/usr/local
+make -j$(nproc)
+make install
+cd ..
+rm -rf crosstool-ng-crosstool-ng-1.24.0
diff --git a/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch b/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch
deleted file mode 100644
index 871d5225c0f..00000000000
--- a/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-commit bdb24c2851fd5f0ad9b82d7ea1db911d334b02d2
-Author: Joseph Myers <joseph@codesourcery.com>
-Date:   Tue May 20 21:27:13 2014 +0000
-
-    Fix ARM build with GCC trunk.
-    
-    sysdeps/unix/sysv/linux/arm/unwind-resume.c and
-    sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c have static
-    variables that are written in C code but only read from toplevel asms.
-    Current GCC trunk now optimizes away such apparently write-only static
-    variables, so causing a build failure.  This patch marks those
-    variables with __attribute_used__ to avoid that optimization.
-    
-    Tested that this fixes the build for ARM.
-    
-            * sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c
-            (libgcc_s_resume): Use __attribute_used__.
-            * sysdeps/unix/sysv/linux/arm/unwind-resume.c (libgcc_s_resume):
-            Likewise.
-
-diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
-index 29e2c2b00b04..e848bfeffdcb 100644
---- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
-+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
-@@ -22,7 +22,8 @@
- #include <pthreadP.h>
- 
- static void *libgcc_s_handle;
--static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
-+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc)
-+  __attribute_used__;
- static _Unwind_Reason_Code (*libgcc_s_personality)
-   (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *);
- static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
-diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
-index 285b99b5ed0d..48d00fc83641 100644
---- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
-+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
-@@ -20,7 +20,8 @@
- #include <stdio.h>
- #include <unwind.h>
- 
--static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
-+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc)
-+  __attribute_used__;
- static _Unwind_Reason_Code (*libgcc_s_personality)
-   (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *);
- 
diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile
index 10579119462..fab3824a20a 100644
--- a/src/ci/docker/dist-various-1/Dockerfile
+++ b/src/ci/docker/dist-various-1/Dockerfile
@@ -139,7 +139,6 @@ ENV RUST_CONFIGURE_ARGS \
       --musl-root-aarch64=/musl-aarch64 \
       --musl-root-mips=/musl-mips \
       --musl-root-mipsel=/musl-mipsel \
-      --enable-emscripten \
       --disable-docs
 
 ENV SCRIPT \
diff --git a/src/ci/docker/scripts/cross-apt-packages.sh b/src/ci/docker/scripts/cross-apt-packages.sh
index 51945fd72ad..bb72e33def2 100644
--- a/src/ci/docker/scripts/cross-apt-packages.sh
+++ b/src/ci/docker/scripts/cross-apt-packages.sh
@@ -22,5 +22,6 @@ apt-get update && apt-get install -y --no-install-recommends \
   python2.7 \
   sudo \
   texinfo \
+  unzip \
   wget \
   xz-utils
diff --git a/src/ci/docker/scripts/emscripten-wasm.sh b/src/ci/docker/scripts/emscripten-wasm.sh
deleted file mode 100644
index e4a93d7a100..00000000000
--- a/src/ci/docker/scripts/emscripten-wasm.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-set -ex
-
-hide_output() {
-  set +x
-  on_err="
-echo ERROR: An error was encountered with the build.
-cat /tmp/build.log
-exit 1
-"
-  trap "$on_err" ERR
-  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
-  PING_LOOP_PID=$!
-  $@ &> /tmp/build.log
-  trap - ERR
-  kill $PING_LOOP_PID
-  rm -f /tmp/build.log
-  set -x
-}
-
-# Download last known good emscripten from WebAssembly waterfall
-BUILD=$(curl -fL https://storage.googleapis.com/wasm-llvm/builds/linux/lkgr.json | \
-    jq '.build | tonumber')
-curl -sL https://storage.googleapis.com/wasm-llvm/builds/linux/$BUILD/wasm-binaries.tbz2 | \
-    hide_output tar xvkj
-
-# node 8 is required to run wasm
-cd /
-curl -sL https://nodejs.org/dist/v8.0.0/node-v8.0.0-linux-x64.tar.xz | \
-    tar -xJ
-
-# Make emscripten use wasm-ready node and LLVM tools
-echo "EMSCRIPTEN_ROOT = '/wasm-install/emscripten'" >> /root/.emscripten
-echo "NODE_JS='/usr/local/bin/node'" >> /root/.emscripten
-echo "LLVM_ROOT='/wasm-install/bin'" >> /root/.emscripten
-echo "BINARYEN_ROOT = '/wasm-install'" >> /root/.emscripten
-echo "COMPILER_ENGINE = NODE_JS" >> /root/.emscripten
-echo "JS_ENGINES = [NODE_JS]" >> /root/.emscripten
diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh
index 47196e89396..1be80741594 100644
--- a/src/ci/docker/scripts/emscripten.sh
+++ b/src/ci/docker/scripts/emscripten.sh
@@ -17,22 +17,7 @@ exit 1
   set -x
 }
 
-cd /
-curl -fL https://mozilla-games.s3.amazonaws.com/emscripten/releases/emsdk-portable.tar.gz | \
-    tar -xz
-
+git clone https://github.com/emscripten-core/emsdk.git /emsdk-portable
 cd /emsdk-portable
-./emsdk update
-hide_output ./emsdk install sdk-1.38.15-64bit
-./emsdk activate sdk-1.38.15-64bit
-
-# Compile and cache libc
-source ./emsdk_env.sh
-echo "main(){}" > a.c
-HOME=/emsdk-portable/ emcc a.c
-HOME=/emsdk-portable/ emcc -s BINARYEN=1 a.c
-rm -f a.*
-
-# Make emsdk usable by any user
-cp /root/.emscripten /emsdk-portable
-chmod a+rxw -R /emsdk-portable
+hide_output ./emsdk install 1.38.46-upstream
+./emsdk activate 1.38.46-upstream
diff --git a/src/ci/docker/wasm32/Dockerfile b/src/ci/docker/wasm32/Dockerfile
new file mode 100644
index 00000000000..a0f35afd995
--- /dev/null
+++ b/src/ci/docker/wasm32/Dockerfile
@@ -0,0 +1,44 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  bzip2
+
+COPY scripts/emscripten.sh /scripts/
+RUN bash /scripts/emscripten.sh
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV PATH=$PATH:/emsdk-portable
+ENV PATH=$PATH:/emsdk-portable/upstream/emscripten/
+ENV PATH=$PATH:/emsdk-portable/node/12.9.1_64bit/bin/
+ENV BINARYEN_ROOT=/emsdk-portable/upstream/
+
+ENV TARGETS=wasm32-unknown-emscripten
+
+# Use -O1 optimizations in the link step to reduce time spent optimizing.
+ENV EMCC_CFLAGS=-O1
+
+# Emscripten installation is user-specific
+ENV NO_CHANGE_USER=1
+
+# FIXME: Re-enable these tests once https://github.com/rust-lang/cargo/pull/7476
+# is picked up by CI
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
+    --exclude src/libcore \
+    --exclude src/liballoc \
+    --exclude src/libproc_macro \
+    --exclude src/libstd \
+    --exclude src/libterm \
+    --exclude src/libtest
diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh
index c7c3b0a5fbf..92c6e546a38 100755
--- a/src/ci/init_repo.sh
+++ b/src/ci/init_repo.sh
@@ -47,7 +47,7 @@ function fetch_github_commit_archive {
     rm $cached
 }
 
-included="src/llvm-project src/llvm-emscripten src/doc/book src/doc/rust-by-example"
+included="src/llvm-project src/doc/book src/doc/rust-by-example"
 modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
 modules=($modules)
 use_git=""
diff --git a/src/doc/book b/src/doc/book
-Subproject 04806c80be0f54b1290287e3f85e84bdfc0b6ec
+Subproject 9bb8b161963fcebc9d9ccd732ba26f42108016d
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 4374786f0b4bf0606b35d5c30a9681f342e5707
+Subproject 5004ad30d69f93553ceef74439fea2159d1f769
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject a6288e7407a6c4c19ea29de6d43f40c803883f2
+Subproject 0b111eaae36cc4b4997684be853882a59e2c7ca
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 3cda8d92797..b603c7b231e 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -10,9 +10,11 @@
         - [Warn-by-default lints](lints/listing/warn-by-default.md)
         - [Deny-by-default lints](lints/listing/deny-by-default.md)
 - [Codegen options](codegen-options/index.md)
+- [JSON Output](json.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
     - [Custom Targets](targets/custom.md)
+    - [Known Issues](targets/known-issues.md)
 - [Profile-guided Optimization](profile-guided-optimization.md)
 - [Linker-plugin based LTO](linker-plugin-lto.md)
 - [Contributing to `rustc`](contributing.md)
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index e73fd43f19a..f5d5f2089d7 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -61,6 +61,8 @@ enabling or disabling a feature.
 To see the valid options and an example of use, run `rustc --print
 target-features`.
 
+Using this flag is unsafe and might result in [undefined runtime behavior](../targets/known-issues.md).
+
 ## passes
 
 This flag can be used to add extra LLVM passes to the compilation.
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 5eea9c86879..bdb3c519658 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -92,6 +92,7 @@ information about editions may be found in the [edition guide].
 [edition guide]: ../edition-guide/introduction.html
 
 ## `--emit`: specifies the types of output files to generate
+ <a id="option-emit"></a>
 
 This flag controls the types of output files generated by the compiler. It
 accepts a comma-separated list of values, and may be specified multiple times.
@@ -144,7 +145,7 @@ of print values are:
   target CPU may be selected with the `-C target-cpu=val` flag.
 - `target-features` — List of available target features for the current
   target. Target features may be enabled with the `-C target-feature=val`
-  flag.
+  flag. This flag is unsafe. See [known issues](targets/known-issues.md) for more details.
 - `relocation-models` — List of relocation models. Relocation models may be
   selected with the `-C relocation-model=val` flag.
 - `code-models` — List of code models. Code models may be selected with the
@@ -241,12 +242,13 @@ The "sysroot" is where `rustc` looks for the crates that come with the Rust
 distribution; this flag allows that to be overridden.
 
 ## `--error-format`: control how errors are produced
+ <a id="option-error-format"></a>
 
 This flag lets you control the format of messages. Messages are printed to
 stderr. The valid options are:
 
 - `human` — Human-readable output. This is the default.
-- `json` — Structured JSON output.
+- `json` — Structured JSON output. See [the JSON chapter] for more detail.
 - `short` — Short, one-line messages.
 
 ## `--color`: configure coloring of output
@@ -273,6 +275,7 @@ pathname syntax. For example `--remap-path-prefix foo=bar` will match
 `foo/lib.rs` but not `./foo/lib.rs`.
 
 ## `--json`: configure json messages printed by the compiler
+ <a id="option-json"></a>
 
 When the `--error-format=json` option is passed to rustc then all of the
 compiler's diagnostic output will be emitted in the form of JSON blobs. The
@@ -305,9 +308,13 @@ to customize the output:
 Note that it is invalid to combine the `--json` argument with the `--color`
 argument, and it is required to combine `--json` with `--error-format=json`.
 
+See [the JSON chapter] for more detail.
+
 ## `@path`: load command-line flags from a path
 
 If you specify `@path` on the command-line, then it will open `path` and read
 command line options from it. These options are one per line; a blank line indicates
 an empty option. The file can use Unix or Windows style line endings, and must be
 encoded as UTF-8.
+
+[the JSON chapter]: json.md
diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md
new file mode 100644
index 00000000000..b7378495163
--- /dev/null
+++ b/src/doc/rustc/src/json.md
@@ -0,0 +1,231 @@
+# JSON Output
+
+This chapter documents the JSON structures emitted by `rustc`. JSON may be
+enabled with the [`--error-format=json` flag][option-error-format]. Additional
+options may be specified with the [`--json` flag][option-json] which can
+change which messages are generated, and the format of the messages.
+
+JSON messages are emitted one per line to stderr.
+
+If parsing the output with Rust, the
+[`cargo_metadata`](https://crates.io/crates/cargo_metadata) crate provides
+some support for parsing the messages.
+
+When parsing, care should be taken to be forwards-compatible with future changes
+to the format. Optional values may be `null`. New fields may be added. Enumerated
+fields like "level" or "suggestion_applicability" may add new values.
+
+## Diagnostics
+
+Diagnostic messages provide errors or possible concerns generated during
+compilation. `rustc` provides detailed information about where the diagnostic
+originates, along with hints and suggestions.
+
+Diagnostics are arranged in a parent/child relationship where the parent
+diagnostic value is the core of the diagnostic, and the attached children
+provide additional context, help, and information.
+
+Diagnostics have the following format:
+
+```javascript
+{
+    /* The primary message. */
+    "message": "unused variable: `x`",
+    /* The diagnostic code.
+       Some messages may set this value to null.
+    */
+    "code": {
+        /* A unique string identifying which diagnostic triggered. */
+        "code": "unused_variables",
+        /* An optional string explaining more detail about the diagnostic code. */
+        "explanation": null
+    },
+    /* The severity of the diagnostic.
+       Values may be:
+       - "error": A fatal error that prevents compilation.
+       - "warning": A possible error or concern.
+       - "note": Additional information or context about the diagnostic.
+       - "help": A suggestion on how to resolve the diagnostic.
+       - "failure-note": A note attached to the message for further information.
+       - "error: internal compiler error": Indicates a bug within the compiler.
+    */
+    "level": "warning",
+    /* An array of source code locations to point out specific details about
+       where the diagnostic originates from. This may be empty, for example
+       for some global messages, or child messages attached to a parent.
+
+       Character offsets are offsets of Unicode Scalar Values.
+    */
+    "spans": [
+        {
+            /* The file where the span is located.
+               For spans located within a macro expansion, this will be the
+               name of the expanded macro in the format "<MACRONAME macros>".
+            */
+            "file_name": "lib.rs",
+            /* The byte offset where the span starts (0-based, inclusive). */
+            "byte_start": 21,
+            /* The byte offset where the span ends (0-based, exclusive). */
+            "byte_end": 22,
+            /* The first line number of the span (1-based, inclusive). */
+            "line_start": 2,
+            /* The last line number of the span (1-based, inclusive). */
+            "line_end": 2,
+            /* The first character offset of the line_start (1-based, inclusive). */
+            "column_start": 9,
+            /* The last character offset of the line_end (1-based, exclusive). */
+            "column_end": 10,
+            /* Whether or not this is the "primary" span.
+
+               This indicates that this span is the focal point of the
+               diagnostic.
+
+               There are rare cases where multiple spans may be marked as
+               primary. For example, "immutable borrow occurs here" and
+               "mutable borrow ends here" can be two separate primary spans.
+
+               The top (parent) message should always have at least one
+               primary span, unless it has zero spans. Child messages may have
+               zero or more primary spans.
+            */
+            "is_primary": true,
+            /* An array of objects showing the original source code for this
+               span. This shows the entire lines of text where the span is
+               located. A span across multiple lines will have a separate
+               value for each line.
+            */
+            "text": [
+                {
+                    /* The entire line of the original source code. */
+                    "text": "    let x = 123;",
+                    /* The first character offset of the line of
+                       where the span covers this line (1-based, inclusive). */
+                    "highlight_start": 9,
+                    /* The last character offset of the line of
+                       where the span covers this line (1-based, exclusive). */
+                    "highlight_end": 10
+                }
+            ],
+            /* An optional message to display at this span location.
+               This is typically null for primary spans.
+            */
+            "label": null,
+            /* An optional string of a suggested replacement for this span to
+               solve the issue. Tools may try to replace the contents of the
+               span with this text.
+            */
+            "suggested_replacement": null,
+            /* An optional string that indicates the confidence of the
+               "suggested_replacement". Tools may use this value to determine
+               whether or not suggestions should be automatically applied.
+
+               Possible values may be:
+               - "MachineApplicable": The suggestion is definitely what the
+                 user intended. This suggestion should be automatically
+                 applied.
+               - "MaybeIncorrect": The suggestion may be what the user
+                 intended, but it is uncertain. The suggestion should result
+                 in valid Rust code if it is applied.
+               - "HasPlaceholders": The suggestion contains placeholders like
+                 `(...)`. The suggestion cannot be applied automatically
+                 because it will not result in valid Rust code. The user will
+                 need to fill in the placeholders.
+               - "Unspecified": The applicability of the suggestion is unknown.
+            */
+            "suggestion_applicability": null,
+            /* An optional object indicating the expansion of a macro within
+               this span.
+
+               If a message occurs within a macro invocation, this object will
+               provide details of where within the macro expansion the message
+               is located.
+            */
+            "expansion": {
+                /* The span of the macro invocation.
+                   Uses the same span definition as the "spans" array.
+                */
+                "span": {/*...*/}
+                /* Name of the macro, such as "foo!" or "#[derive(Eq)]". */
+                "macro_decl_name": "some_macro!",
+                /* Optional span where the relevant part of the macro is
+                  defined. */
+                "def_site_span": {/*...*/},
+            }
+        }
+    ],
+    /* Array of attached diagnostic messages.
+       This is an array of objects using the same format as the parent
+       message. Children are not nested (children do not themselves
+       contain "children" definitions).
+    */
+    "children": [
+        {
+            "message": "`#[warn(unused_variables)]` on by default",
+            "code": null,
+            "level": "note",
+            "spans": [],
+            "children": [],
+            "rendered": null
+        },
+        {
+            "message": "consider prefixing with an underscore",
+            "code": null,
+            "level": "help",
+            "spans": [
+                {
+                    "file_name": "lib.rs",
+                    "byte_start": 21,
+                    "byte_end": 22,
+                    "line_start": 2,
+                    "line_end": 2,
+                    "column_start": 9,
+                    "column_end": 10,
+                    "is_primary": true,
+                    "text": [
+                        {
+                            "text": "    let x = 123;",
+                            "highlight_start": 9,
+                            "highlight_end": 10
+                        }
+                    ],
+                    "label": null,
+                    "suggested_replacement": "_x",
+                    "suggestion_applicability": "MachineApplicable",
+                    "expansion": null
+                }
+            ],
+            "children": [],
+            "rendered": null
+        }
+    ],
+    /* Optional string of the rendered version of the diagnostic as displayed
+       by rustc. Note that this may be influenced by the `--json` flag.
+    */
+    "rendered": "warning: unused variable: `x`\n --> lib.rs:2:9\n  |\n2 |     let x = 123;\n  |         ^ help: consider prefixing with an underscore: `_x`\n  |\n  = note: `#[warn(unused_variables)]` on by default\n\n"
+}
+```
+
+## Artifact notifications
+
+Artifact notifications are emitted when the [`--json=artifacts`
+flag][option-json] is used. They indicate that a file artifact has been saved
+to disk. More information about emit kinds may be found in the [`--emit`
+flag][option-emit] documentation.
+
+```javascript
+{
+    /* The filename that was generated. */
+    "artifact": "libfoo.rlib",
+    /* The kind of artifact that was generated. Possible values:
+       - "link": The generated crate as specified by the crate-type.
+       - "dep-info": The `.d` file with dependency information in a Makefile-like syntax.
+       - "metadata": The Rust `.rmeta` file containing metadata about the crate.
+       - "save-analysis": A JSON file emitted by the `-Zsave-analysis` feature.
+    */
+    "emit": "link"
+}
+```
+
+[option-emit]: command-line-arguments.md#option-emit
+[option-error-format]: command-line-arguments.md#option-error-format
+[option-json]: command-line-arguments.md#option-json
diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md
index e486240fda8..813d7c4bafe 100644
--- a/src/doc/rustc/src/lints/listing/warn-by-default.md
+++ b/src/doc/rustc/src/lints/listing/warn-by-default.md
@@ -596,30 +596,6 @@ warning: function cannot return without recursing
   |
 ```
 
-## unions-with-drop-fields
-
-This lint detects use of unions that contain fields with possibly non-trivial drop code. Some
-example code that triggers this lint:
-
-```rust
-#![feature(untagged_unions)]
-
-union U {
-    s: String,
-}
-```
-
-This will produce:
-
-```text
-warning: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
- --> src/main.rs:4:5
-  |
-4 |     s: String,
-  |     ^^^^^^^^^
-  |
-```
-
 ## unknown-lints
 
 This lint detects unrecognized lint attribute. Some
diff --git a/src/doc/rustc/src/profile-guided-optimization.md b/src/doc/rustc/src/profile-guided-optimization.md
index 38be07a6440..d066f4a9cf5 100644
--- a/src/doc/rustc/src/profile-guided-optimization.md
+++ b/src/doc/rustc/src/profile-guided-optimization.md
@@ -125,6 +125,17 @@ RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
     cargo build --release --target=x86_64-unknown-linux-gnu
 ```
 
+### Troubleshooting
+
+- It is recommended to pass `-Cllvm-args=-pgo-warn-missing-function` during the
+  `-Cprofile-use` phase. LLVM by default does not warn if it cannot find
+  profiling data for a given function. Enabling this warning will make it
+  easier to spot errors in your setup.
+
+- There is a [known issue](https://github.com/rust-lang/cargo/issues/7416) in
+  Cargo prior to version 1.39 that will prevent PGO from working correctly. Be
+  sure to use Cargo 1.39 or newer when doing PGO.
+
 ## Further Reading
 
 `rustc`'s PGO support relies entirely on LLVM's implementation of the feature
diff --git a/src/doc/rustc/src/targets/index.md b/src/doc/rustc/src/targets/index.md
index 3d63d072bef..5859df83f64 100644
--- a/src/doc/rustc/src/targets/index.md
+++ b/src/doc/rustc/src/targets/index.md
@@ -11,3 +11,9 @@ To compile to a particular target, use the `--target` flag:
 ```bash
 $ rustc src/main.rs --target=wasm32-unknown-unknown
 ```
+## Target Features
+`x86`,  and `ARMv8` are two popular CPU architectures. Their instruction sets form a common baseline across most CPUs. However, some CPUs extend these with custom instruction sets, e.g. vector (`AVX`), bitwise manipulation (`BMI`) or cryptographic (`AES`).
+
+Developers, who know on which CPUs their compiled code is going to run can choose to add (or remove) CPU specific instruction sets via the `-C target-feature=val` flag.
+
+Please note, that this flag is generally considered as unsafe. More details can be found in [this section](known-issues.md).
diff --git a/src/doc/rustc/src/targets/known-issues.md b/src/doc/rustc/src/targets/known-issues.md
new file mode 100644
index 00000000000..89fd8ea6d32
--- /dev/null
+++ b/src/doc/rustc/src/targets/known-issues.md
@@ -0,0 +1,13 @@
+# Known Issues
+This section informs you about known "gotchas". Keep in mind, that this section is (and always will be) incomplete. For suggestions and amendments, feel free to [contribute](../contributing.md) to this guide.
+
+## Target Features
+Most target-feature problems arise, when mixing code that have the target-feature _enabled_ with code that have it _disabled_. If you want to avoid undefined behavior, it is recommended to build _all code_ (including the standard library and imported crates) with a common set of target-features.
+
+By default, compiling your code with the `-C target-feature` flag will not recompile the entire standard library and/or imported crates with matching target features. Therefore, target features are generally considered as unsafe. Using `#[target_feature]` on individual functions makes the function unsafe.
+
+Examples:
+
+| Target-Feature | Issue | Seen on | Description | Details |
+| -------------- | ----- | ------- | ----------- | ------- |
+| `+soft-float` <br> and <br> `-sse` | Segfaults and ABI mismatches | `x86` and `x86-64` | The `x86` and `x86_64` architecture uses SSE registers (aka `xmm`) for floating point operations. Using software emulated floats ("soft-floats") disables usage of `xmm` registers, but parts of Rust's core libraries (e.g. `std::f32` or `std::f64`) are compiled without soft-floats and expect parameters to be passed in `xmm` registers. This leads to ABI mismatches. <br><br>  Attempting to compile with disabled SSE causes the same error, too. | [#63466](https://github.com/rust-lang/rust/issues/63466) |
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 9b5d9431ae2..567b8ea7224 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -142,6 +142,9 @@ impl<T> Box<T> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
         let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
+        if layout.size() == 0 {
+            return Box(NonNull::dangling().into())
+        }
         let ptr = unsafe {
             Global.alloc(layout)
                 .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
@@ -182,9 +185,16 @@ impl<T> Box<[T]> {
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
         let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
-        let ptr = unsafe { alloc::alloc(layout) };
-        let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
-        let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) };
+        let ptr = if layout.size() == 0 {
+            NonNull::dangling()
+        } else {
+            unsafe {
+                Global.alloc(layout)
+                    .unwrap_or_else(|_| alloc::handle_alloc_error(layout))
+                    .cast()
+            }
+        };
+        let slice = unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), len) };
         Box(Unique::from(slice))
     }
 }
diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs
index 8250fc38ccd..f0796354e00 100644
--- a/src/liballoc/collections/btree/set.rs
+++ b/src/liballoc/collections/btree/set.rs
@@ -2,7 +2,7 @@
 // to TreeMap
 
 use core::borrow::Borrow;
-use core::cmp::Ordering::{self, Less, Greater, Equal};
+use core::cmp::Ordering::{Less, Greater, Equal};
 use core::cmp::{max, min};
 use core::fmt::{self, Debug};
 use core::iter::{Peekable, FromIterator, FusedIterator};
@@ -109,6 +109,77 @@ pub struct Range<'a, T: 'a> {
     iter: btree_map::Range<'a, T, ()>,
 }
 
+/// Core of SymmetricDifference and Union.
+/// More efficient than btree.map.MergeIter,
+/// and crucially for SymmetricDifference, nexts() reports on both sides.
+#[derive(Clone)]
+struct MergeIterInner<I>
+    where I: Iterator,
+          I::Item: Copy,
+{
+    a: I,
+    b: I,
+    peeked: Option<MergeIterPeeked<I>>,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum MergeIterPeeked<I: Iterator> {
+    A(I::Item),
+    B(I::Item),
+}
+
+impl<I> MergeIterInner<I>
+    where I: ExactSizeIterator + FusedIterator,
+          I::Item: Copy + Ord,
+{
+    fn new(a: I, b: I) -> Self {
+        MergeIterInner { a, b, peeked: None }
+    }
+
+    fn nexts(&mut self) -> (Option<I::Item>, Option<I::Item>) {
+        let mut a_next = match self.peeked {
+            Some(MergeIterPeeked::A(next)) => Some(next),
+            _ => self.a.next(),
+        };
+        let mut b_next = match self.peeked {
+            Some(MergeIterPeeked::B(next)) => Some(next),
+            _ => self.b.next(),
+        };
+        let ord = match (a_next, b_next) {
+            (None, None) => Equal,
+            (_, None) => Less,
+            (None, _) => Greater,
+            (Some(a1), Some(b1)) => a1.cmp(&b1),
+        };
+        self.peeked = match ord {
+            Less => b_next.take().map(MergeIterPeeked::B),
+            Equal => None,
+            Greater => a_next.take().map(MergeIterPeeked::A),
+        };
+        (a_next, b_next)
+    }
+
+    fn lens(&self) -> (usize, usize) {
+        match self.peeked {
+            Some(MergeIterPeeked::A(_)) => (1 + self.a.len(), self.b.len()),
+            Some(MergeIterPeeked::B(_)) => (self.a.len(), 1 + self.b.len()),
+            _ => (self.a.len(), self.b.len()),
+        }
+    }
+}
+
+impl<I> Debug for MergeIterInner<I>
+    where I: Iterator + Debug,
+          I::Item: Copy + Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("MergeIterInner")
+            .field(&self.a)
+            .field(&self.b)
+            .finish()
+    }
+}
+
 /// A lazy iterator producing elements in the difference of `BTreeSet`s.
 ///
 /// This `struct` is created by the [`difference`] method on [`BTreeSet`].
@@ -120,6 +191,7 @@ pub struct Range<'a, T: 'a> {
 pub struct Difference<'a, T: 'a> {
     inner: DifferenceInner<'a, T>,
 }
+#[derive(Debug)]
 enum DifferenceInner<'a, T: 'a> {
     Stitch {
         // iterate all of self and some of other, spotting matches along the way
@@ -137,21 +209,7 @@ enum DifferenceInner<'a, T: 'a> {
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for Difference<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match &self.inner {
-            DifferenceInner::Stitch {
-                self_iter,
-                other_iter,
-            } => f
-                .debug_tuple("Difference")
-                .field(&self_iter)
-                .field(&other_iter)
-                .finish(),
-            DifferenceInner::Search {
-                self_iter,
-                other_set: _,
-            } => f.debug_tuple("Difference").field(&self_iter).finish(),
-            DifferenceInner::Iterate(iter) => f.debug_tuple("Difference").field(&iter).finish(),
-        }
+        f.debug_tuple("Difference").field(&self.inner).finish()
     }
 }
 
@@ -163,18 +221,12 @@ impl<T: fmt::Debug> fmt::Debug for Difference<'_, T> {
 /// [`BTreeSet`]: struct.BTreeSet.html
 /// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct SymmetricDifference<'a, T: 'a> {
-    a: Peekable<Iter<'a, T>>,
-    b: Peekable<Iter<'a, T>>,
-}
+pub struct SymmetricDifference<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for SymmetricDifference<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("SymmetricDifference")
-         .field(&self.a)
-         .field(&self.b)
-         .finish()
+        f.debug_tuple("SymmetricDifference").field(&self.0).finish()
     }
 }
 
@@ -189,6 +241,7 @@ impl<T: fmt::Debug> fmt::Debug for SymmetricDifference<'_, T> {
 pub struct Intersection<'a, T: 'a> {
     inner: IntersectionInner<'a, T>,
 }
+#[derive(Debug)]
 enum IntersectionInner<'a, T: 'a> {
     Stitch {
         // iterate similarly sized sets jointly, spotting matches along the way
@@ -206,23 +259,7 @@ enum IntersectionInner<'a, T: 'a> {
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for Intersection<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match &self.inner {
-            IntersectionInner::Stitch {
-                a,
-                b,
-            } => f
-                .debug_tuple("Intersection")
-                .field(&a)
-                .field(&b)
-                .finish(),
-            IntersectionInner::Search {
-                small_iter,
-                large_set: _,
-            } => f.debug_tuple("Intersection").field(&small_iter).finish(),
-            IntersectionInner::Answer(answer) => {
-                f.debug_tuple("Intersection").field(&answer).finish()
-            }
-        }
+        f.debug_tuple("Intersection").field(&self.inner).finish()
     }
 }
 
@@ -234,18 +271,12 @@ impl<T: fmt::Debug> fmt::Debug for Intersection<'_, T> {
 /// [`BTreeSet`]: struct.BTreeSet.html
 /// [`union`]: struct.BTreeSet.html#method.union
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct Union<'a, T: 'a> {
-    a: Peekable<Iter<'a, T>>,
-    b: Peekable<Iter<'a, T>>,
-}
+pub struct Union<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for Union<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Union")
-         .field(&self.a)
-         .field(&self.b)
-         .finish()
+        f.debug_tuple("Union").field(&self.0).finish()
     }
 }
 
@@ -355,19 +386,16 @@ impl<T: Ord> BTreeSet<T> {
                     self_iter.next_back();
                     DifferenceInner::Iterate(self_iter)
                 }
-                _ => {
-                    if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF {
-                        DifferenceInner::Search {
-                            self_iter: self.iter(),
-                            other_set: other,
-                        }
-                    } else {
-                        DifferenceInner::Stitch {
-                            self_iter: self.iter(),
-                            other_iter: other.iter().peekable(),
-                        }
+                _ if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF => {
+                    DifferenceInner::Search {
+                        self_iter: self.iter(),
+                        other_set: other,
                     }
                 }
+                _ => DifferenceInner::Stitch {
+                    self_iter: self.iter(),
+                    other_iter: other.iter().peekable(),
+                },
             },
         }
     }
@@ -396,10 +424,7 @@ impl<T: Ord> BTreeSet<T> {
     pub fn symmetric_difference<'a>(&'a self,
                                     other: &'a BTreeSet<T>)
                                     -> SymmetricDifference<'a, T> {
-        SymmetricDifference {
-            a: self.iter().peekable(),
-            b: other.iter().peekable(),
-        }
+        SymmetricDifference(MergeIterInner::new(self.iter(), other.iter()))
     }
 
     /// Visits the values representing the intersection,
@@ -447,24 +472,22 @@ impl<T: Ord> BTreeSet<T> {
                 (Greater, _) | (_, Less) => IntersectionInner::Answer(None),
                 (Equal, _) => IntersectionInner::Answer(Some(self_min)),
                 (_, Equal) => IntersectionInner::Answer(Some(self_max)),
-                _ => {
-                    if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF {
-                        IntersectionInner::Search {
-                            small_iter: self.iter(),
-                            large_set: other,
-                        }
-                    } else if other.len() <= self.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF {
-                        IntersectionInner::Search {
-                            small_iter: other.iter(),
-                            large_set: self,
-                        }
-                    } else {
-                        IntersectionInner::Stitch {
-                            a: self.iter(),
-                            b: other.iter(),
-                        }
+                _ if self.len() <= other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF => {
+                    IntersectionInner::Search {
+                        small_iter: self.iter(),
+                        large_set: other,
+                    }
+                }
+                _ if other.len() <= self.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF => {
+                    IntersectionInner::Search {
+                        small_iter: other.iter(),
+                        large_set: self,
                     }
                 }
+                _ => IntersectionInner::Stitch {
+                    a: self.iter(),
+                    b: other.iter(),
+                },
             },
         }
     }
@@ -489,10 +512,7 @@ impl<T: Ord> BTreeSet<T> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn union<'a>(&'a self, other: &'a BTreeSet<T>) -> Union<'a, T> {
-        Union {
-            a: self.iter().peekable(),
-            b: other.iter().peekable(),
-        }
+        Union(MergeIterInner::new(self.iter(), other.iter()))
     }
 
     /// Clears the set, removing all values.
@@ -1166,15 +1186,6 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for Range<'_, T> {}
 
-/// Compares `x` and `y`, but return `short` if x is None and `long` if y is None
-fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering {
-    match (x, y) {
-        (None, _) => short,
-        (_, None) => long,
-        (Some(x1), Some(y1)) => x1.cmp(y1),
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Difference<'_, T> {
     fn clone(&self) -> Self {
@@ -1261,10 +1272,7 @@ impl<T: Ord> FusedIterator for Difference<'_, T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for SymmetricDifference<'_, T> {
     fn clone(&self) -> Self {
-        SymmetricDifference {
-            a: self.a.clone(),
-            b: self.b.clone(),
-        }
+        SymmetricDifference(self.0.clone())
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1273,19 +1281,19 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
 
     fn next(&mut self) -> Option<&'a T> {
         loop {
-            match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
-                Less => return self.a.next(),
-                Equal => {
-                    self.a.next();
-                    self.b.next();
-                }
-                Greater => return self.b.next(),
+            let (a_next, b_next) = self.0.nexts();
+            if a_next.and(b_next).is_none() {
+                return a_next.or(b_next);
             }
         }
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (0, Some(self.a.len() + self.b.len()))
+        let (a_len, b_len) = self.0.lens();
+        // No checked_add, because even if a and b refer to the same set,
+        // and T is an empty type, the storage overhead of sets limits
+        // the number of elements to less than half the range of usize.
+        (0, Some(a_len + b_len))
     }
 }
 
@@ -1311,7 +1319,7 @@ impl<T> Clone for Intersection<'_, T> {
                     small_iter: small_iter.clone(),
                     large_set,
                 },
-                IntersectionInner::Answer(answer) => IntersectionInner::Answer(answer.clone()),
+                IntersectionInner::Answer(answer) => IntersectionInner::Answer(*answer),
             },
         }
     }
@@ -1365,10 +1373,7 @@ impl<T: Ord> FusedIterator for Intersection<'_, T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Union<'_, T> {
     fn clone(&self) -> Self {
-        Union {
-            a: self.a.clone(),
-            b: self.b.clone(),
-        }
+        Union(self.0.clone())
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1376,19 +1381,13 @@ impl<'a, T: Ord> Iterator for Union<'a, T> {
     type Item = &'a T;
 
     fn next(&mut self) -> Option<&'a T> {
-        match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
-            Less => self.a.next(),
-            Equal => {
-                self.b.next();
-                self.a.next()
-            }
-            Greater => self.b.next(),
-        }
+        let (a_next, b_next) = self.0.nexts();
+        a_next.or(b_next)
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let a_len = self.a.len();
-        let b_len = self.b.len();
+        let (a_len, b_len) = self.0.lens();
+        // No checked_add - see SymmetricDifference::size_hint.
         (max(a_len, b_len), Some(a_len + b_len))
     }
 }
diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs
index 68cbc366d7b..cbfc55233a1 100644
--- a/src/liballoc/fmt.rs
+++ b/src/liballoc/fmt.rs
@@ -80,24 +80,210 @@
 //! arguments which have names. Like with positional parameters, it is not
 //! valid to provide named parameters that are unused by the format string.
 //!
-//! ## Argument types
+//! # Formatting Parameters
+//!
+//! Each argument being formatted can be transformed by a number of formatting
+//! parameters (corresponding to `format_spec` in the syntax above). These
+//! parameters affect the string representation of what's being formatted.
+//!
+//! ## Width
+//!
+//! ```
+//! // All of these print "Hello x    !"
+//! println!("Hello {:5}!", "x");
+//! println!("Hello {:1$}!", "x", 5);
+//! println!("Hello {1:0$}!", 5, "x");
+//! println!("Hello {:width$}!", "x", width = 5);
+//! ```
+//!
+//! This is a parameter for the "minimum width" that the format should take up.
+//! If the value's string does not fill up this many characters, then the
+//! padding specified by fill/alignment will be used to take up the required
+//! space (see below).
+//!
+//! The value for the width can also be provided as a [`usize`] in the list of
+//! parameters by adding a postfix `$`, indicating that the second argument is
+//! a [`usize`] specifying the width.
+//!
+//! Referring to an argument with the dollar syntax does not affect the "next
+//! argument" counter, so it's usually a good idea to refer to arguments by
+//! position, or use named arguments.
+//!
+//! ## Fill/Alignment
+//!
+//! ```
+//! assert_eq!(format!("Hello {:<5}!", "x"),  "Hello x    !");
+//! assert_eq!(format!("Hello {:-<5}!", "x"), "Hello x----!");
+//! assert_eq!(format!("Hello {:^5}!", "x"),  "Hello   x  !");
+//! assert_eq!(format!("Hello {:>5}!", "x"),  "Hello     x!");
+//! ```
+//!
+//! The optional fill character and alignment is provided normally in conjunction with the
+//! [`width`](#width) parameter. It must be defined before `width`, right after the `:`.
+//! This indicates that if the value being formatted is smaller than
+//! `width` some extra characters will be printed around it.
+//! Filling comes in the following variants for different alignments:
+//!
+//! * `[fill]<` - the argument is left-aligned in `width` columns
+//! * `[fill]^` - the argument is center-aligned in `width` columns
+//! * `[fill]>` - the argument is right-aligned in `width` columns
+//!
+//! The default [fill/alignment](#fillalignment) for non-numerics is a space and
+//! left-aligned. The
+//! defaults for numeric formatters is also a space but with right-alignment. If
+//! the `0` flag (see below) is specified for numerics, then the implicit fill character is
+//! `0`.
+//!
+//! Note that alignment may not be implemented by some types. In particular, it
+//! is not generally implemented for the `Debug` trait.  A good way to ensure
+//! padding is applied is to format your input, then pad this resulting string
+//! to obtain your output:
+//!
+//! ```
+//! println!("Hello {:^15}!", format!("{:?}", Some("hi"))); // => "Hello   Some("hi")   !"
+//! ```
+//!
+//! ## Sign/`#`/`0`
+//!
+//! ```
+//! assert_eq!(format!("Hello {:+}!", 5), "Hello +5!");
+//! assert_eq!(format!("{:#x}!", 27), "0x1b!");
+//! assert_eq!(format!("Hello {:05}!", 5),  "Hello 00005!");
+//! assert_eq!(format!("Hello {:05}!", -5), "Hello -0005!");
+//! assert_eq!(format!("{:#010x}!", 27), "0x0000001b!");
+//! ```
+//!
+//! These are all flags altering the behavior of the formatter.
+//!
+//! * `+` - This is intended for numeric types and indicates that the sign
+//!         should always be printed. Positive signs are never printed by
+//!         default, and the negative sign is only printed by default for the
+//!         `Signed` trait. This flag indicates that the correct sign (`+` or `-`)
+//!         should always be printed.
+//! * `-` - Currently not used
+//! * `#` - This flag is indicates that the "alternate" form of printing should
+//!         be used. The alternate forms are:
+//!     * `#?` - pretty-print the [`Debug`] formatting
+//!     * `#x` - precedes the argument with a `0x`
+//!     * `#X` - precedes the argument with a `0x`
+//!     * `#b` - precedes the argument with a `0b`
+//!     * `#o` - precedes the argument with a `0o`
+//! * `0` - This is used to indicate for integer formats that the padding to `width` should
+//!         both be done with a `0` character as well as be sign-aware. A format
+//!         like `{:08}` would yield `00000001` for the integer `1`, while the
+//!         same format would yield `-0000001` for the integer `-1`. Notice that
+//!         the negative version has one fewer zero than the positive version.
+//!         Note that padding zeroes are always placed after the sign (if any)
+//!         and before the digits. When used together with the `#` flag, a similar
+//!         rule applies: padding zeroes are inserted after the prefix but before
+//!         the digits. The prefix is included in the total width.
+//!
+//! ## Precision
+//!
+//! For non-numeric types, this can be considered a "maximum width". If the resulting string is
+//! longer than this width, then it is truncated down to this many characters and that truncated
+//! value is emitted with proper `fill`, `alignment` and `width` if those parameters are set.
+//!
+//! For integral types, this is ignored.
+//!
+//! For floating-point types, this indicates how many digits after the decimal point should be
+//! printed.
+//!
+//! There are three possible ways to specify the desired `precision`:
+//!
+//! 1. An integer `.N`:
+//!
+//!    the integer `N` itself is the precision.
+//!
+//! 2. An integer or name followed by dollar sign `.N$`:
+//!
+//!    use format *argument* `N` (which must be a `usize`) as the precision.
+//!
+//! 3. An asterisk `.*`:
+//!
+//!    `.*` means that this `{...}` is associated with *two* format inputs rather than one: the
+//!    first input holds the `usize` precision, and the second holds the value to print. Note that
+//!    in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
+//!    to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
+//!
+//! For example, the following calls all print the same thing `Hello x is 0.01000`:
+//!
+//! ```
+//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
+//! println!("Hello {0} is {1:.5}", "x", 0.01);
+//!
+//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
+//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
+//!
+//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
+//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
+//!
+//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
+//! //                          specified in first of next two args (5)}
+//! println!("Hello {} is {:.*}",    "x", 5, 0.01);
+//!
+//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
+//! //                          specified in its predecessor (5)}
+//! println!("Hello {} is {2:.*}",   "x", 5, 0.01);
+//!
+//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
+//! //                          in arg "prec" (5)}
+//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
+//! ```
 //!
-//! Each argument's type is dictated by the format string.
-//! There are various parameters which require a particular type, however.
-//! An example is the `{:.*}` syntax, which sets the number of decimal places
-//! in floating-point types:
+//! While these:
 //!
 //! ```
-//! let formatted_number = format!("{:.*}", 2, 1.234567);
+//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
+//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
+//! println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
+//! ```
 //!
-//! assert_eq!("1.23", formatted_number)
+//! print two significantly different things:
+//!
+//! ```text
+//! Hello, `1234.560` has 3 fractional digits
+//! Hello, `123` has 3 characters
+//! Hello, `     123` has 3 right-aligned characters
 //! ```
 //!
-//! If this syntax is used, then the number of characters to print precedes the
-//! actual object being formatted, and the number of characters must have the
-//! type [`usize`].
+//! # Escaping
+//!
+//! The literal characters `{` and `}` may be included in a string by preceding
+//! them with the same character. For example, the `{` character is escaped with
+//! `{{` and the `}` character is escaped with `}}`.
 //!
-//! ## Formatting traits
+//! ```
+//! assert_eq!(format!("Hello {{}}"), "Hello {}");
+//! assert_eq!(format!("{{ Hello"), "{ Hello");
+//! ```
+//!
+//! # Syntax
+//!
+//! To summarize, here you can find the full grammar of format strings.
+//! The syntax for the formatting language used is drawn from other languages,
+//! so it should not be too alien. Arguments are formatted with Python-like
+//! syntax, meaning that arguments are surrounded by `{}` instead of the C-like
+//! `%`. The actual grammar for the formatting syntax is:
+//!
+//! ```text
+//! format_string := <text> [ maybe-format <text> ] *
+//! maybe-format := '{' '{' | '}' '}' | <format>
+//! format := '{' [ argument ] [ ':' format_spec ] '}'
+//! argument := integer | identifier
+//!
+//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
+//! fill := character
+//! align := '<' | '^' | '>'
+//! sign := '+' | '-'
+//! width := count
+//! precision := count | '*'
+//! type := identifier | '?' | ''
+//! count := parameter | integer
+//! parameter := argument '$'
+//! ```
+//!
+//! # Formatting traits
 //!
 //! When requesting that an argument be formatted with a particular type, you
 //! are actually requesting that an argument ascribes to a particular trait.
@@ -220,7 +406,7 @@
 //! assert_eq!(format!("{} {:?}", "foo\n", "bar\n"), "foo\n \"bar\\n\"");
 //! ```
 //!
-//! ## Related macros
+//! # Related macros
 //!
 //! There are a number of related macros in the [`format!`] family. The ones that
 //! are currently implemented are:
@@ -300,185 +486,6 @@
 //! it would internally pass around this structure until it has been determined
 //! where output should go to.
 //!
-//! # Syntax
-//!
-//! The syntax for the formatting language used is drawn from other languages,
-//! so it should not be too alien. Arguments are formatted with Python-like
-//! syntax, meaning that arguments are surrounded by `{}` instead of the C-like
-//! `%`. The actual grammar for the formatting syntax is:
-//!
-//! ```text
-//! format_string := <text> [ maybe-format <text> ] *
-//! maybe-format := '{' '{' | '}' '}' | <format>
-//! format := '{' [ argument ] [ ':' format_spec ] '}'
-//! argument := integer | identifier
-//!
-//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
-//! fill := character
-//! align := '<' | '^' | '>'
-//! sign := '+' | '-'
-//! width := count
-//! precision := count | '*'
-//! type := identifier | '?' | ''
-//! count := parameter | integer
-//! parameter := argument '$'
-//! ```
-//!
-//! # Formatting Parameters
-//!
-//! Each argument being formatted can be transformed by a number of formatting
-//! parameters (corresponding to `format_spec` in the syntax above). These
-//! parameters affect the string representation of what's being formatted.
-//!
-//! ## Fill/Alignment
-//!
-//! The fill character is provided normally in conjunction with the
-//! [`width`](#width)
-//! parameter. This indicates that if the value being formatted is smaller than
-//! `width` some extra characters will be printed around it. The extra
-//! characters are specified by `fill`, and the alignment can be one of the
-//! following options:
-//!
-//! * `<` - the argument is left-aligned in `width` columns
-//! * `^` - the argument is center-aligned in `width` columns
-//! * `>` - the argument is right-aligned in `width` columns
-//!
-//! Note that alignment may not be implemented by some types. In particular, it
-//! is not generally implemented for the `Debug` trait.  A good way to ensure
-//! padding is applied is to format your input, then use this resulting string
-//! to pad your output.
-//!
-//! ## Sign/`#`/`0`
-//!
-//! These can all be interpreted as flags for a particular formatter.
-//!
-//! * `+` - This is intended for numeric types and indicates that the sign
-//!         should always be printed. Positive signs are never printed by
-//!         default, and the negative sign is only printed by default for the
-//!         `Signed` trait. This flag indicates that the correct sign (`+` or `-`)
-//!         should always be printed.
-//! * `-` - Currently not used
-//! * `#` - This flag is indicates that the "alternate" form of printing should
-//!         be used. The alternate forms are:
-//!     * `#?` - pretty-print the [`Debug`] formatting
-//!     * `#x` - precedes the argument with a `0x`
-//!     * `#X` - precedes the argument with a `0x`
-//!     * `#b` - precedes the argument with a `0b`
-//!     * `#o` - precedes the argument with a `0o`
-//! * `0` - This is used to indicate for integer formats that the padding should
-//!         both be done with a `0` character as well as be sign-aware. A format
-//!         like `{:08}` would yield `00000001` for the integer `1`, while the
-//!         same format would yield `-0000001` for the integer `-1`. Notice that
-//!         the negative version has one fewer zero than the positive version.
-//!         Note that padding zeroes are always placed after the sign (if any)
-//!         and before the digits. When used together with the `#` flag, a similar
-//!         rule applies: padding zeroes are inserted after the prefix but before
-//!         the digits.
-//!
-//! ## Width
-//!
-//! This is a parameter for the "minimum width" that the format should take up.
-//! If the value's string does not fill up this many characters, then the
-//! padding specified by fill/alignment will be used to take up the required
-//! space.
-//!
-//! The default [fill/alignment](#fillalignment) for non-numerics is a space and
-//! left-aligned. The
-//! defaults for numeric formatters is also a space but with right-alignment. If
-//! the `0` flag is specified for numerics, then the implicit fill character is
-//! `0`.
-//!
-//! The value for the width can also be provided as a [`usize`] in the list of
-//! parameters by using the dollar syntax indicating that the second argument is
-//! a [`usize`] specifying the width, for example:
-//!
-//! ```
-//! // All of these print "Hello x    !"
-//! println!("Hello {:5}!", "x");
-//! println!("Hello {:1$}!", "x", 5);
-//! println!("Hello {1:0$}!", 5, "x");
-//! println!("Hello {:width$}!", "x", width = 5);
-//! ```
-//!
-//! Referring to an argument with the dollar syntax does not affect the "next
-//! argument" counter, so it's usually a good idea to refer to arguments by
-//! position, or use named arguments.
-//!
-//! ## Precision
-//!
-//! For non-numeric types, this can be considered a "maximum width". If the resulting string is
-//! longer than this width, then it is truncated down to this many characters and that truncated
-//! value is emitted with proper `fill`, `alignment` and `width` if those parameters are set.
-//!
-//! For integral types, this is ignored.
-//!
-//! For floating-point types, this indicates how many digits after the decimal point should be
-//! printed.
-//!
-//! There are three possible ways to specify the desired `precision`:
-//!
-//! 1. An integer `.N`:
-//!
-//!    the integer `N` itself is the precision.
-//!
-//! 2. An integer or name followed by dollar sign `.N$`:
-//!
-//!    use format *argument* `N` (which must be a `usize`) as the precision.
-//!
-//! 3. An asterisk `.*`:
-//!
-//!    `.*` means that this `{...}` is associated with *two* format inputs rather than one: the
-//!    first input holds the `usize` precision, and the second holds the value to print. Note that
-//!    in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part refers
-//!    to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
-//!
-//! For example, the following calls all print the same thing `Hello x is 0.01000`:
-//!
-//! ```
-//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
-//! println!("Hello {0} is {1:.5}", "x", 0.01);
-//!
-//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
-//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
-//!
-//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
-//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
-//!
-//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision
-//! //                          specified in first of next two args (5)}
-//! println!("Hello {} is {:.*}",    "x", 5, 0.01);
-//!
-//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision
-//! //                          specified in its predecessor (5)}
-//! println!("Hello {} is {2:.*}",   "x", 5, 0.01);
-//!
-//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
-//! //                          in arg "prec" (5)}
-//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
-//! ```
-//!
-//! While these:
-//!
-//! ```
-//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
-//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
-//! println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
-//! ```
-//!
-//! print two significantly different things:
-//!
-//! ```text
-//! Hello, `1234.560` has 3 fractional digits
-//! Hello, `123` has 3 characters
-//! Hello, `     123` has 3 right-aligned characters
-//! ```
-//!
-//! # Escaping
-//!
-//! The literal characters `{` and `}` may be included in a string by preceding
-//! them with the same character. For example, the `{` character is escaped with
-//! `{{` and the `}` character is escaped with `}}`.
-//!
 //! [`usize`]: ../../std/primitive.usize.html
 //! [`isize`]: ../../std/primitive.isize.html
 //! [`i8`]: ../../std/primitive.i8.html
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index b0651f16484..f1c4c32e116 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -3,8 +3,9 @@
 //!
 //! The type [`Rc<T>`][`Rc`] provides shared ownership of a value of type `T`,
 //! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new
-//! pointer to the same value in the heap. When the last [`Rc`] pointer to a
-//! given value is destroyed, the pointed-to value is also destroyed.
+//! pointer to the same allocation in the heap. When the last [`Rc`] pointer to a
+//! given allocation is destroyed, the value stored in that allocation (often
+//! referred to as "inner value") is also dropped.
 //!
 //! Shared references in Rust disallow mutation by default, and [`Rc`]
 //! is no exception: you cannot generally obtain a mutable reference to
@@ -21,8 +22,10 @@
 //!
 //! The [`downgrade`][downgrade] method can be used to create a non-owning
 //! [`Weak`] pointer. A [`Weak`] pointer can be [`upgrade`][upgrade]d
-//! to an [`Rc`], but this will return [`None`] if the value has
-//! already been dropped.
+//! to an [`Rc`], but this will return [`None`] if the value stored in the allocation has
+//! already been dropped. In other words, `Weak` pointers do not keep the value
+//! inside the allocation alive; however, they *do* keep the allocation
+//! (the backing store for the inner value) alive.
 //!
 //! A cycle between [`Rc`] pointers will never be deallocated. For this reason,
 //! [`Weak`] is used to break cycles. For example, a tree could have strong
@@ -41,13 +44,13 @@
 //! Rc::downgrade(&my_rc);
 //! ```
 //!
-//! [`Weak<T>`][`Weak`] does not auto-dereference to `T`, because the value may have
-//! already been destroyed.
+//! [`Weak<T>`][`Weak`] does not auto-dereference to `T`, because the inner value may have
+//! already been dropped.
 //!
 //! # Cloning references
 //!
-//! Creating a new reference from an existing reference counted pointer is done using the
-//! `Clone` trait implemented for [`Rc<T>`][`Rc`] and [`Weak<T>`][`Weak`].
+//! Creating a new reference to the same allocation as an existing reference counted pointer
+//! is done using the `Clone` trait implemented for [`Rc<T>`][`Rc`] and [`Weak<T>`][`Weak`].
 //!
 //! ```
 //! use std::rc::Rc;
@@ -93,7 +96,7 @@
 //!     );
 //!
 //!     // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc<Owner>`
-//!     // value gives us a new pointer to the same `Owner` value, incrementing
+//!     // gives us a new pointer to the same `Owner` allocation, incrementing
 //!     // the reference count in the process.
 //!     let gadget1 = Gadget {
 //!         id: 1,
@@ -110,8 +113,8 @@
 //!     // Despite dropping `gadget_owner`, we're still able to print out the name
 //!     // of the `Owner` of the `Gadget`s. This is because we've only dropped a
 //!     // single `Rc<Owner>`, not the `Owner` it points to. As long as there are
-//!     // other `Rc<Owner>` values pointing at the same `Owner`, it will remain
-//!     // allocated. The field projection `gadget1.owner.name` works because
+//!     // other `Rc<Owner>` pointing at the same `Owner` allocation, it will remain
+//!     // live. The field projection `gadget1.owner.name` works because
 //!     // `Rc<Owner>` automatically dereferences to `Owner`.
 //!     println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
 //!     println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);
@@ -124,9 +127,9 @@
 //!
 //! If our requirements change, and we also need to be able to traverse from
 //! `Owner` to `Gadget`, we will run into problems. An [`Rc`] pointer from `Owner`
-//! to `Gadget` introduces a cycle between the values. This means that their
-//! reference counts can never reach 0, and the values will remain allocated
-//! forever: a memory leak. In order to get around this, we can use [`Weak`]
+//! to `Gadget` introduces a cycle. This means that their
+//! reference counts can never reach 0, and the allocation will never be destroyed:
+//! a memory leak. In order to get around this, we can use [`Weak`]
 //! pointers.
 //!
 //! Rust actually makes it somewhat difficult to produce this loop in the first
@@ -193,10 +196,10 @@
 //!     for gadget_weak in gadget_owner.gadgets.borrow().iter() {
 //!
 //!         // `gadget_weak` is a `Weak<Gadget>`. Since `Weak` pointers can't
-//!         // guarantee the value is still allocated, we need to call
+//!         // guarantee the allocation still exists, we need to call
 //!         // `upgrade`, which returns an `Option<Rc<Gadget>>`.
 //!         //
-//!         // In this case we know the value still exists, so we simply
+//!         // In this case we know the allocation still exists, so we simply
 //!         // `unwrap` the `Option`. In a more complicated program, you might
 //!         // need graceful error handling for a `None` result.
 //!
@@ -365,7 +368,7 @@ impl<T> Rc<T> {
         unsafe { Pin::new_unchecked(Rc::new(value)) }
     }
 
-    /// Returns the contained value, if the `Rc` has exactly one strong reference.
+    /// Returns the inner value, if the `Rc` has exactly one strong reference.
     ///
     /// Otherwise, an [`Err`][result] is returned with the same `Rc` that was
     /// passed in.
@@ -446,7 +449,7 @@ impl<T> Rc<mem::MaybeUninit<T>> {
     /// # Safety
     ///
     /// As with [`MaybeUninit::assume_init`],
-    /// it is up to the caller to guarantee that the value
+    /// it is up to the caller to guarantee that the inner value
     /// really is in an initialized state.
     /// Calling this when the content is not yet fully initialized
     /// causes immediate undefined behavior.
@@ -485,7 +488,7 @@ impl<T> Rc<[mem::MaybeUninit<T>]> {
     /// # Safety
     ///
     /// As with [`MaybeUninit::assume_init`],
-    /// it is up to the caller to guarantee that the value
+    /// it is up to the caller to guarantee that the inner value
     /// really is in an initialized state.
     /// Calling this when the content is not yet fully initialized
     /// causes immediate undefined behavior.
@@ -604,7 +607,7 @@ impl<T: ?Sized> Rc<T> {
         unsafe { NonNull::new_unchecked(Rc::into_raw(this) as *mut _) }
     }
 
-    /// Creates a new [`Weak`][weak] pointer to this value.
+    /// Creates a new [`Weak`][weak] pointer to this allocation.
     ///
     /// [weak]: struct.Weak.html
     ///
@@ -625,7 +628,7 @@ impl<T: ?Sized> Rc<T> {
         Weak { ptr: this.ptr }
     }
 
-    /// Gets the number of [`Weak`][weak] pointers to this value.
+    /// Gets the number of [`Weak`][weak] pointers to this allocation.
     ///
     /// [weak]: struct.Weak.html
     ///
@@ -645,7 +648,7 @@ impl<T: ?Sized> Rc<T> {
         this.weak() - 1
     }
 
-    /// Gets the number of strong (`Rc`) pointers to this value.
+    /// Gets the number of strong (`Rc`) pointers to this allocation.
     ///
     /// # Examples
     ///
@@ -664,7 +667,7 @@ impl<T: ?Sized> Rc<T> {
     }
 
     /// Returns `true` if there are no other `Rc` or [`Weak`][weak] pointers to
-    /// this inner value.
+    /// this allocation.
     ///
     /// [weak]: struct.Weak.html
     #[inline]
@@ -672,14 +675,14 @@ impl<T: ?Sized> Rc<T> {
         Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
     }
 
-    /// Returns a mutable reference to the inner value, if there are
-    /// no other `Rc` or [`Weak`][weak] pointers to the same value.
+    /// Returns a mutable reference into the given `Rc`, if there are
+    /// no other `Rc` or [`Weak`][weak] pointers to the same allocation.
     ///
     /// Returns [`None`] otherwise, because it is not safe to
     /// mutate a shared value.
     ///
     /// See also [`make_mut`][make_mut], which will [`clone`][clone]
-    /// the inner value when it's shared.
+    /// the inner value when there are other pointers.
     ///
     /// [weak]: struct.Weak.html
     /// [`None`]: ../../std/option/enum.Option.html#variant.None
@@ -710,7 +713,7 @@ impl<T: ?Sized> Rc<T> {
         }
     }
 
-    /// Returns a mutable reference to the inner value,
+    /// Returns a mutable reference into the given `Rc`,
     /// without any check.
     ///
     /// See also [`get_mut`], which is safe and does appropriate checks.
@@ -719,7 +722,7 @@ impl<T: ?Sized> Rc<T> {
     ///
     /// # Safety
     ///
-    /// Any other `Rc` or [`Weak`] pointers to the same value must not be dereferenced
+    /// Any other `Rc` or [`Weak`] pointers to the same allocation must not be dereferenced
     /// for the duration of the returned borrow.
     /// This is trivially the case if no such pointers exist,
     /// for example immediately after `Rc::new`.
@@ -745,8 +748,8 @@ impl<T: ?Sized> Rc<T> {
 
     #[inline]
     #[stable(feature = "ptr_eq", since = "1.17.0")]
-    /// Returns `true` if the two `Rc`s point to the same value (not
-    /// just values that compare as equal).
+    /// Returns `true` if the two `Rc`s point to the same allocation
+    /// (in a vein similar to [`ptr::eq`]).
     ///
     /// # Examples
     ///
@@ -760,6 +763,8 @@ impl<T: ?Sized> Rc<T> {
     /// assert!(Rc::ptr_eq(&five, &same_five));
     /// assert!(!Rc::ptr_eq(&five, &other_five));
     /// ```
+    ///
+    /// [`ptr::eq`]: ../../std/ptr/fn.eq.html
     pub fn ptr_eq(this: &Self, other: &Self) -> bool {
         this.ptr.as_ptr() == other.ptr.as_ptr()
     }
@@ -768,12 +773,12 @@ impl<T: ?Sized> Rc<T> {
 impl<T: Clone> Rc<T> {
     /// Makes a mutable reference into the given `Rc`.
     ///
-    /// If there are other `Rc` pointers to the same value, then `make_mut` will
-    /// [`clone`] the inner value to ensure unique ownership.  This is also
+    /// If there are other `Rc` pointers to the same allocation, then `make_mut` will
+    /// [`clone`] the inner value to a new allocation to ensure unique ownership.  This is also
     /// referred to as clone-on-write.
     ///
-    /// If there are no other `Rc` pointers to this value, then [`Weak`]
-    /// pointers to this value will be disassociated.
+    /// If there are no other `Rc` pointers to this allocation, then [`Weak`]
+    /// pointers to this allocation will be disassociated.
     ///
     /// See also [`get_mut`], which will fail rather than cloning.
     ///
@@ -794,7 +799,7 @@ impl<T: Clone> Rc<T> {
     /// *Rc::make_mut(&mut data) += 1;        // Won't clone anything
     /// *Rc::make_mut(&mut other_data) *= 2;  // Won't clone anything
     ///
-    /// // Now `data` and `other_data` point to different values.
+    /// // Now `data` and `other_data` point to different allocations.
     /// assert_eq!(*data, 8);
     /// assert_eq!(*other_data, 12);
     /// ```
@@ -837,7 +842,7 @@ impl<T: Clone> Rc<T> {
         // returned is the *only* pointer that will ever be returned to T. Our
         // reference count is guaranteed to be 1 at this point, and we required
         // the `Rc<T>` itself to be `mut`, so we're returning the only possible
-        // reference to the inner value.
+        // reference to the allocation.
         unsafe {
             &mut this.ptr.as_mut().value
         }
@@ -878,7 +883,7 @@ impl Rc<dyn Any> {
 
 impl<T: ?Sized> Rc<T> {
     /// Allocates an `RcBox<T>` with sufficient space for
-    /// a possibly-unsized value where the value has the layout provided.
+    /// a possibly-unsized inner value where the value has the layout provided.
     ///
     /// The function `mem_to_rcbox` is called with the data pointer
     /// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
@@ -908,7 +913,7 @@ impl<T: ?Sized> Rc<T> {
         inner
     }
 
-    /// Allocates an `RcBox<T>` with sufficient space for an unsized value
+    /// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
         // Allocate for the `RcBox<T>` using the given value.
         Self::allocate_for_layout(
@@ -1111,7 +1116,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
 impl<T: ?Sized> Clone for Rc<T> {
     /// Makes a clone of the `Rc` pointer.
     ///
-    /// This creates another pointer to the same inner value, increasing the
+    /// This creates another pointer to the same allocation, increasing the
     /// strong reference count.
     ///
     /// # Examples
@@ -1172,6 +1177,8 @@ impl<T: ?Sized + PartialEq> RcEqIdent<T> for Rc<T> {
 /// store large values, that are slow to clone, but also heavy to check for equality, causing this
 /// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to
 /// the same value, than two `&T`s.
+///
+/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Eq> RcEqIdent<T> for Rc<T> {
     #[inline]
@@ -1189,9 +1196,11 @@ impl<T: ?Sized + Eq> RcEqIdent<T> for Rc<T> {
 impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
     /// Equality for two `Rc`s.
     ///
-    /// Two `Rc`s are equal if their inner values are equal.
+    /// Two `Rc`s are equal if their inner values are equal, even if they are
+    /// stored in different allocation.
     ///
-    /// If `T` also implements `Eq`, two `Rc`s that point to the same value are
+    /// If `T` also implements `Eq` (implying reflexivity of equality),
+    /// two `Rc`s that point to the same allocation are
     /// always equal.
     ///
     /// # Examples
@@ -1212,7 +1221,8 @@ impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
     ///
     /// Two `Rc`s are unequal if their inner values are unequal.
     ///
-    /// If `T` also implements `Eq`, two `Rc`s that point to the same value are
+    /// If `T` also implements `Eq` (implying reflexivity of equality),
+    /// two `Rc`s that point to the same allocation are
     /// never unequal.
     ///
     /// # Examples
@@ -1541,17 +1551,18 @@ impl<'a, T: 'a + Clone> RcFromIter<&'a T, slice::Iter<'a, T>> for Rc<[T]> {
 }
 
 /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the
-/// managed value. The value is accessed by calling [`upgrade`] on the `Weak`
+/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
 /// pointer, which returns an [`Option`]`<`[`Rc`]`<T>>`.
 ///
 /// Since a `Weak` reference does not count towards ownership, it will not
-/// prevent the inner value from being dropped, and `Weak` itself makes no
-/// guarantees about the value still being present and may return [`None`]
-/// when [`upgrade`]d.
+/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no
+/// guarantees about the value still being present. Thus it may return [`None`]
+/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation
+/// itself (the backing store) from being deallocated.
 ///
-/// A `Weak` pointer is useful for keeping a temporary reference to the value
-/// within [`Rc`] without extending its lifetime. It is also used to prevent
-/// circular references between [`Rc`] pointers, since mutual owning references
+/// A `Weak` pointer is useful for keeping a temporary reference to the allocation
+/// managed by [`Rc`] without preventing its inner value from being dropped. It is also used to
+/// prevent circular references between [`Rc`] pointers, since mutual owning references
 /// would never allow either [`Rc`] to be dropped. For example, a tree could
 /// have strong [`Rc`] pointers from parent nodes to children, and `Weak`
 /// pointers from children back to their parents.
@@ -1750,10 +1761,10 @@ pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
 }
 
 impl<T: ?Sized> Weak<T> {
-    /// Attempts to upgrade the `Weak` pointer to an [`Rc`], extending
-    /// the lifetime of the value if successful.
+    /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
+    /// dropping of the inner value if successful.
     ///
-    /// Returns [`None`] if the value has since been dropped.
+    /// Returns [`None`] if the inner value has since been dropped.
     ///
     /// [`Rc`]: struct.Rc.html
     /// [`None`]: ../../std/option/enum.Option.html
@@ -1787,7 +1798,7 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
-    /// Gets the number of strong (`Rc`) pointers pointing to this value.
+    /// Gets the number of strong (`Rc`) pointers pointing to this allocation.
     ///
     /// If `self` was created using [`Weak::new`], this will return 0.
     ///
@@ -1801,11 +1812,11 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
-    /// Gets the number of `Weak` pointers pointing to this value.
+    /// Gets the number of `Weak` pointers pointing to this allocation.
     ///
     /// If `self` was created using [`Weak::new`], this will return `None`. If
     /// not, the returned value is at least 1, since `self` still points to the
-    /// value.
+    /// allocation.
     ///
     /// [`Weak::new`]: #method.new
     #[unstable(feature = "weak_counts", issue = "57977")]
@@ -1830,14 +1841,14 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
-    /// Returns `true` if the two `Weak`s point to the same value (not just
-    /// values that compare as equal), or if both don't point to any value
+    /// Returns `true` if the two `Weak`s point to the same allocation (similar to
+    /// [`ptr::eq`]), or if both don't point to any allocation
     /// (because they were created with `Weak::new()`).
     ///
     /// # Notes
     ///
     /// Since this compares pointers it means that `Weak::new()` will equal each
-    /// other, even though they don't point to any value.
+    /// other, even though they don't point to any allocation.
     ///
     /// # Examples
     ///
@@ -1869,6 +1880,8 @@ impl<T: ?Sized> Weak<T> {
     /// let third = Rc::downgrade(&third_rc);
     /// assert!(!first.ptr_eq(&third));
     /// ```
+    ///
+    /// [`ptr::eq`]: ../../std/ptr/fn.eq.html
     #[inline]
     #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
@@ -1918,7 +1931,7 @@ impl<T: ?Sized> Drop for Weak<T> {
 
 #[stable(feature = "rc_weak", since = "1.4.0")]
 impl<T: ?Sized> Clone for Weak<T> {
-    /// Makes a clone of the `Weak` pointer that points to the same value.
+    /// Makes a clone of the `Weak` pointer that points to the same allocation.
     ///
     /// # Examples
     ///
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 5977e69b7fa..69f8f71197c 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -45,10 +45,10 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 ///
 /// The type `Arc<T>` provides shared ownership of a value of type `T`,
 /// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces
-/// a new `Arc` instance, which points to the same value on the heap as the
+/// a new `Arc` instance, which points to the same allocation on the heap as the
 /// source `Arc`, while increasing a reference count. When the last `Arc`
-/// pointer to a given value is destroyed, the pointed-to value is also
-/// destroyed.
+/// pointer to a given allocation is destroyed, the value stored in that allocation (often
+/// referred to as "inner value") is also dropped.
 ///
 /// Shared references in Rust disallow mutation by default, and `Arc` is no
 /// exception: you cannot generally obtain a mutable reference to something
@@ -61,7 +61,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 /// Unlike [`Rc<T>`], `Arc<T>` uses atomic operations for its reference
 /// counting. This means that it is thread-safe. The disadvantage is that
 /// atomic operations are more expensive than ordinary memory accesses. If you
-/// are not sharing reference-counted values between threads, consider using
+/// are not sharing reference-counted allocations between threads, consider using
 /// [`Rc<T>`] for lower overhead. [`Rc<T>`] is a safe default, because the
 /// compiler will catch any attempt to send an [`Rc<T>`] between threads.
 /// However, a library might choose `Arc<T>` in order to give library consumers
@@ -85,8 +85,10 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 ///
 /// The [`downgrade`][downgrade] method can be used to create a non-owning
 /// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d
-/// to an `Arc`, but this will return [`None`] if the value has already been
-/// dropped.
+/// to an `Arc`, but this will return [`None`] if the value stored in the allocation has
+/// already been dropped. In other words, `Weak` pointers do not keep the value
+/// inside the allocation alive; however, they *do* keep the allocation
+/// (the backing store for the value) alive.
 ///
 /// A cycle between `Arc` pointers will never be deallocated. For this reason,
 /// [`Weak`][weak] is used to break cycles. For example, a tree could have
@@ -121,8 +123,8 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 /// Arc::downgrade(&my_arc);
 /// ```
 ///
-/// [`Weak<T>`][weak] does not auto-dereference to `T`, because the value may have
-/// already been destroyed.
+/// [`Weak<T>`][weak] does not auto-dereference to `T`, because the inner value may have
+/// already been dropped.
 ///
 /// [arc]: struct.Arc.html
 /// [weak]: struct.Weak.html
@@ -221,17 +223,18 @@ impl<T: ?Sized> Arc<T> {
 }
 
 /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the
-/// managed value. The value is accessed by calling [`upgrade`] on the `Weak`
+/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
 /// pointer, which returns an [`Option`]`<`[`Arc`]`<T>>`.
 ///
 /// Since a `Weak` reference does not count towards ownership, it will not
-/// prevent the inner value from being dropped, and `Weak` itself makes no
-/// guarantees about the value still being present and may return [`None`]
-/// when [`upgrade`]d.
+/// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no
+/// guarantees about the value still being present. Thus it may return [`None`]
+/// when [`upgrade`]d. Note however that a `Weak` reference *does* prevent the allocation
+/// itself (the backing store) from being deallocated.
 ///
-/// A `Weak` pointer is useful for keeping a temporary reference to the value
-/// within [`Arc`] without extending its lifetime. It is also used to prevent
-/// circular references between [`Arc`] pointers, since mutual owning references
+/// A `Weak` pointer is useful for keeping a temporary reference to the allocation
+/// managed by [`Arc`] without preventing its inner value from being dropped. It is also used to
+/// prevent circular references between [`Arc`] pointers, since mutual owning references
 /// would never allow either [`Arc`] to be dropped. For example, a tree could
 /// have strong [`Arc`] pointers from parent nodes to children, and `Weak`
 /// pointers from children back to their parents.
@@ -345,7 +348,7 @@ impl<T> Arc<T> {
         unsafe { Pin::new_unchecked(Arc::new(data)) }
     }
 
-    /// Returns the contained value, if the `Arc` has exactly one strong reference.
+    /// Returns the inner value, if the `Arc` has exactly one strong reference.
     ///
     /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was
     /// passed in.
@@ -426,7 +429,7 @@ impl<T> Arc<mem::MaybeUninit<T>> {
     /// # Safety
     ///
     /// As with [`MaybeUninit::assume_init`],
-    /// it is up to the caller to guarantee that the value
+    /// it is up to the caller to guarantee that the inner value
     /// really is in an initialized state.
     /// Calling this when the content is not yet fully initialized
     /// causes immediate undefined behavior.
@@ -465,7 +468,7 @@ impl<T> Arc<[mem::MaybeUninit<T>]> {
     /// # Safety
     ///
     /// As with [`MaybeUninit::assume_init`],
-    /// it is up to the caller to guarantee that the value
+    /// it is up to the caller to guarantee that the inner value
     /// really is in an initialized state.
     /// Calling this when the content is not yet fully initialized
     /// causes immediate undefined behavior.
@@ -584,7 +587,7 @@ impl<T: ?Sized> Arc<T> {
         unsafe { NonNull::new_unchecked(Arc::into_raw(this) as *mut _) }
     }
 
-    /// Creates a new [`Weak`][weak] pointer to this value.
+    /// Creates a new [`Weak`][weak] pointer to this allocation.
     ///
     /// [weak]: struct.Weak.html
     ///
@@ -628,7 +631,7 @@ impl<T: ?Sized> Arc<T> {
         }
     }
 
-    /// Gets the number of [`Weak`][weak] pointers to this value.
+    /// Gets the number of [`Weak`][weak] pointers to this allocation.
     ///
     /// [weak]: struct.Weak.html
     ///
@@ -659,7 +662,7 @@ impl<T: ?Sized> Arc<T> {
         if cnt == usize::MAX { 0 } else { cnt - 1 }
     }
 
-    /// Gets the number of strong (`Arc`) pointers to this value.
+    /// Gets the number of strong (`Arc`) pointers to this allocation.
     ///
     /// # Safety
     ///
@@ -710,8 +713,8 @@ impl<T: ?Sized> Arc<T> {
 
     #[inline]
     #[stable(feature = "ptr_eq", since = "1.17.0")]
-    /// Returns `true` if the two `Arc`s point to the same value (not
-    /// just values that compare as equal).
+    /// Returns `true` if the two `Arc`s point to the same allocation
+    /// (in a vein similar to [`ptr::eq`]).
     ///
     /// # Examples
     ///
@@ -725,6 +728,8 @@ impl<T: ?Sized> Arc<T> {
     /// assert!(Arc::ptr_eq(&five, &same_five));
     /// assert!(!Arc::ptr_eq(&five, &other_five));
     /// ```
+    ///
+    /// [`ptr::eq`]: ../../std/ptr/fn.eq.html
     pub fn ptr_eq(this: &Self, other: &Self) -> bool {
         this.ptr.as_ptr() == other.ptr.as_ptr()
     }
@@ -732,7 +737,7 @@ impl<T: ?Sized> Arc<T> {
 
 impl<T: ?Sized> Arc<T> {
     /// Allocates an `ArcInner<T>` with sufficient space for
-    /// a possibly-unsized value where the value has the layout provided.
+    /// a possibly-unsized inner value where the value has the layout provided.
     ///
     /// The function `mem_to_arcinner` is called with the data pointer
     /// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
@@ -761,7 +766,7 @@ impl<T: ?Sized> Arc<T> {
         inner
     }
 
-    /// Allocates an `ArcInner<T>` with sufficient space for an unsized value.
+    /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value.
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
         // Allocate for the `ArcInner<T>` using the given value.
         Self::allocate_for_layout(
@@ -903,7 +908,7 @@ impl<T: Copy> ArcFromSlice<T> for Arc<[T]> {
 impl<T: ?Sized> Clone for Arc<T> {
     /// Makes a clone of the `Arc` pointer.
     ///
-    /// This creates another pointer to the same inner value, increasing the
+    /// This creates another pointer to the same allocation, increasing the
     /// strong reference count.
     ///
     /// # Examples
@@ -965,15 +970,19 @@ impl<T: ?Sized> Receiver for Arc<T> {}
 impl<T: Clone> Arc<T> {
     /// Makes a mutable reference into the given `Arc`.
     ///
-    /// If there are other `Arc` or [`Weak`][weak] pointers to the same value,
-    /// then `make_mut` will invoke [`clone`][clone] on the inner value to
-    /// ensure unique ownership. This is also referred to as clone-on-write.
+    /// If there are other `Arc` or [`Weak`][weak] pointers to the same allocation,
+    /// then `make_mut` will create a new allocation and invoke [`clone`][clone] on the inner value
+    /// to ensure unique ownership. This is also referred to as clone-on-write.
+    ///
+    /// Note that this differs from the behavior of [`Rc::make_mut`] which disassociates
+    /// any remaining `Weak` pointers.
     ///
     /// See also [`get_mut`][get_mut], which will fail rather than cloning.
     ///
     /// [weak]: struct.Weak.html
     /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
     /// [get_mut]: struct.Arc.html#method.get_mut
+    /// [`Rc::make_mut`]: ../rc/struct.Rc.html#method.make_mut
     ///
     /// # Examples
     ///
@@ -988,7 +997,7 @@ impl<T: Clone> Arc<T> {
     /// *Arc::make_mut(&mut data) += 1;         // Won't clone anything
     /// *Arc::make_mut(&mut other_data) *= 2;   // Won't clone anything
     ///
-    /// // Now `data` and `other_data` point to different values.
+    /// // Now `data` and `other_data` point to different allocations.
     /// assert_eq!(*data, 8);
     /// assert_eq!(*other_data, 12);
     /// ```
@@ -1048,14 +1057,14 @@ impl<T: Clone> Arc<T> {
 }
 
 impl<T: ?Sized> Arc<T> {
-    /// Returns a mutable reference to the inner value, if there are
-    /// no other `Arc` or [`Weak`][weak] pointers to the same value.
+    /// Returns a mutable reference into the given `Arc`, if there are
+    /// no other `Arc` or [`Weak`][weak] pointers to the same allocation.
     ///
     /// Returns [`None`][option] otherwise, because it is not safe to
     /// mutate a shared value.
     ///
     /// See also [`make_mut`][make_mut], which will [`clone`][clone]
-    /// the inner value when it's shared.
+    /// the inner value when there are other pointers.
     ///
     /// [weak]: struct.Weak.html
     /// [option]: ../../std/option/enum.Option.html
@@ -1091,7 +1100,7 @@ impl<T: ?Sized> Arc<T> {
         }
     }
 
-    /// Returns a mutable reference to the inner value,
+    /// Returns a mutable reference into the given `Arc`,
     /// without any check.
     ///
     /// See also [`get_mut`], which is safe and does appropriate checks.
@@ -1100,7 +1109,7 @@ impl<T: ?Sized> Arc<T> {
     ///
     /// # Safety
     ///
-    /// Any other `Arc` or [`Weak`] pointers to the same value must not be dereferenced
+    /// Any other `Arc` or [`Weak`] pointers to the same allocation must not be dereferenced
     /// for the duration of the returned borrow.
     /// This is trivially the case if no such pointers exist,
     /// for example immediately after `Arc::new`.
@@ -1424,10 +1433,10 @@ impl<T> Weak<T> {
 }
 
 impl<T: ?Sized> Weak<T> {
-    /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending
-    /// the lifetime of the value if successful.
+    /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying
+    /// dropping of the inner value if successful.
     ///
-    /// Returns [`None`] if the value has since been dropped.
+    /// Returns [`None`] if the inner value has since been dropped.
     ///
     /// [`Arc`]: struct.Arc.html
     /// [`None`]: ../../std/option/enum.Option.html#variant.None
@@ -1482,7 +1491,7 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
-    /// Gets the number of strong (`Arc`) pointers pointing to this value.
+    /// Gets the number of strong (`Arc`) pointers pointing to this allocation.
     ///
     /// If `self` was created using [`Weak::new`], this will return 0.
     ///
@@ -1497,17 +1506,17 @@ impl<T: ?Sized> Weak<T> {
     }
 
     /// Gets an approximation of the number of `Weak` pointers pointing to this
-    /// value.
+    /// allocation.
     ///
     /// If `self` was created using [`Weak::new`], this will return 0. If not,
     /// the returned value is at least 1, since `self` still points to the
-    /// value.
+    /// allocation.
     ///
     /// # Accuracy
     ///
     /// Due to implementation details, the returned value can be off by 1 in
     /// either direction when other threads are manipulating any `Arc`s or
-    /// `Weak`s pointing to the same value.
+    /// `Weak`s pointing to the same allocation.
     ///
     /// [`Weak::new`]: #method.new
     #[unstable(feature = "weak_counts", issue = "57977")]
@@ -1548,14 +1557,14 @@ impl<T: ?Sized> Weak<T> {
         }
     }
 
-    /// Returns `true` if the two `Weak`s point to the same value (not just
-    /// values that compare as equal), or if both don't point to any value
+    /// Returns `true` if the two `Weak`s point to the same allocation (similar to
+    /// [`ptr::eq`]), or if both don't point to any allocation
     /// (because they were created with `Weak::new()`).
     ///
     /// # Notes
     ///
     /// Since this compares pointers it means that `Weak::new()` will equal each
-    /// other, even though they don't point to any value.
+    /// other, even though they don't point to any allocation.
     ///
     /// # Examples
     ///
@@ -1587,6 +1596,8 @@ impl<T: ?Sized> Weak<T> {
     /// let third = Arc::downgrade(&third_rc);
     /// assert!(!first.ptr_eq(&third));
     /// ```
+    ///
+    /// [`ptr::eq`]: ../../std/ptr/fn.eq.html
     #[inline]
     #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
@@ -1596,7 +1607,7 @@ impl<T: ?Sized> Weak<T> {
 
 #[stable(feature = "arc_weak", since = "1.4.0")]
 impl<T: ?Sized> Clone for Weak<T> {
-    /// Makes a clone of the `Weak` pointer that points to the same value.
+    /// Makes a clone of the `Weak` pointer that points to the same allocation.
     ///
     /// # Examples
     ///
@@ -1726,6 +1737,8 @@ impl<T: ?Sized + PartialEq> ArcEqIdent<T> for Arc<T> {
 /// store large values, that are slow to clone, but also heavy to check for equality, causing this
 /// cost to pay off more easily. It's also more likely to have two `Arc` clones, that point to
 /// the same value, than two `&T`s.
+///
+/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Eq> ArcEqIdent<T> for Arc<T> {
     #[inline]
@@ -1743,10 +1756,11 @@ impl<T: ?Sized + Eq> ArcEqIdent<T> for Arc<T> {
 impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
     /// Equality for two `Arc`s.
     ///
-    /// Two `Arc`s are equal if their inner values are equal.
+    /// Two `Arc`s are equal if their inner values are equal, even if they are
+    /// stored in different allocation.
     ///
-    /// If `T` also implements `Eq`, two `Arc`s that point to the same value are
-    /// always equal.
+    /// If `T` also implements `Eq` (implying reflexivity of equality),
+    /// two `Arc`s that point to the same allocation are always equal.
     ///
     /// # Examples
     ///
@@ -1766,8 +1780,8 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
     ///
     /// Two `Arc`s are unequal if their inner values are unequal.
     ///
-    /// If `T` also implements `Eq`, two `Arc`s that point to the same value are
-    /// never unequal.
+    /// If `T` also implements `Eq` (implying reflexivity of equality),
+    /// two `Arc`s that point to the same value are never unequal.
     ///
     /// # Examples
     ///
diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs
index 0685fa943c0..b8c720264d0 100644
--- a/src/liballoc/tests/binary_heap.rs
+++ b/src/liballoc/tests/binary_heap.rs
@@ -1,10 +1,5 @@
-use std::cmp;
 use std::collections::BinaryHeap;
 use std::collections::binary_heap::{Drain, PeekMut};
-use std::panic::{self, AssertUnwindSafe};
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-use rand::{thread_rng, seq::SliceRandom};
 
 #[test]
 fn test_iterator() {
@@ -281,9 +276,15 @@ fn assert_covariance() {
 // even if the order may not be correct.
 //
 // Destructors must be called exactly once per element.
+// FIXME: re-enable emscripten once it can unwind again
 #[test]
-#[cfg(not(miri))] // Miri does not support catching panics
+#[cfg(not(any(miri, target_os = "emscripten")))] // Miri does not support catching panics
 fn panic_safe() {
+    use std::cmp;
+    use std::panic::{self, AssertUnwindSafe};
+    use std::sync::atomic::{AtomicUsize, Ordering};
+    use rand::{thread_rng, seq::SliceRandom};
+
     static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
     #[derive(Eq, PartialEq, Ord, Clone, Debug)]
diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs
new file mode 100644
index 00000000000..bc3d53bf30d
--- /dev/null
+++ b/src/liballoc/tests/boxed.rs
@@ -0,0 +1,18 @@
+use std::ptr::NonNull;
+use std::mem::MaybeUninit;
+
+#[test]
+fn unitialized_zero_size_box() {
+    assert_eq!(
+        &*Box::<()>::new_uninit() as *const _,
+        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
+    );
+    assert_eq!(
+        Box::<[()]>::new_uninit_slice(4).as_ptr(),
+        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
+    );
+    assert_eq!(
+        Box::<[String]>::new_uninit_slice(0).as_ptr(),
+        NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
+    );
+}
diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs
index 5c611fd21d2..e4883abc8b5 100644
--- a/src/liballoc/tests/btree/set.rs
+++ b/src/liballoc/tests/btree/set.rs
@@ -222,6 +222,18 @@ fn test_symmetric_difference() {
 }
 
 #[test]
+fn test_symmetric_difference_size_hint() {
+    let x: BTreeSet<i32> = [2, 4].iter().copied().collect();
+    let y: BTreeSet<i32> = [1, 2, 3].iter().copied().collect();
+    let mut iter = x.symmetric_difference(&y);
+    assert_eq!(iter.size_hint(), (0, Some(5)));
+    assert_eq!(iter.next(), Some(&1));
+    assert_eq!(iter.size_hint(), (0, Some(4)));
+    assert_eq!(iter.next(), Some(&3));
+    assert_eq!(iter.size_hint(), (0, Some(1)));
+}
+
+#[test]
 fn test_union() {
     fn check_union(a: &[i32], b: &[i32], expected: &[i32]) {
         check(a, b, expected, |x, y, f| x.union(y).all(f))
@@ -236,6 +248,18 @@ fn test_union() {
 }
 
 #[test]
+fn test_union_size_hint() {
+    let x: BTreeSet<i32> = [2, 4].iter().copied().collect();
+    let y: BTreeSet<i32> = [1, 2, 3].iter().copied().collect();
+    let mut iter = x.union(&y);
+    assert_eq!(iter.size_hint(), (3, Some(5)));
+    assert_eq!(iter.next(), Some(&1));
+    assert_eq!(iter.size_hint(), (2, Some(4)));
+    assert_eq!(iter.next(), Some(&2));
+    assert_eq!(iter.size_hint(), (1, Some(2)));
+}
+
+#[test]
 // Only tests the simple function definition with respect to intersection
 fn test_is_disjoint() {
     let one = [1].iter().collect::<BTreeSet<_>>();
@@ -244,7 +268,7 @@ fn test_is_disjoint() {
 }
 
 #[test]
-// Also tests the trivial function definition of is_superset
+// Also implicitly tests the trivial function definition of is_superset
 fn test_is_subset() {
     fn is_subset(a: &[i32], b: &[i32]) -> bool {
         let set_a = a.iter().collect::<BTreeSet<_>>();
diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs
index f2a2c80f2f7..676874c8b27 100644
--- a/src/liballoc/tests/lib.rs
+++ b/src/liballoc/tests/lib.rs
@@ -2,6 +2,7 @@
 #![feature(box_syntax)]
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
+#![feature(new_uninit)]
 #![feature(option_flattening)]
 #![feature(pattern)]
 #![feature(trusted_len)]
@@ -14,6 +15,7 @@ use std::collections::hash_map::DefaultHasher;
 
 mod arc;
 mod binary_heap;
+mod boxed;
 mod btree;
 mod cow_str;
 mod fmt;
diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs
index 4332b2e90fd..cb73c7c179c 100644
--- a/src/liballoc/tests/str.rs
+++ b/src/liballoc/tests/str.rs
@@ -483,7 +483,7 @@ mod slice_index {
     }
 
     #[test]
-    #[cfg(not(target_arch = "asmjs"))] // hits an OOM
+    #[cfg(not(target_os = "emscripten"))] // hits an OOM
     #[cfg(not(miri))] // Miri is too slow
     fn simple_big() {
         fn a_million_letter_x() -> String {
diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs
index 98d013dfa2b..80537217697 100644
--- a/src/liballoc/tests/vec.rs
+++ b/src/liballoc/tests/vec.rs
@@ -944,8 +944,10 @@ fn drain_filter_complex() {
     }
 }
 
+// Miri does not support catching panics
+// FIXME: re-enable emscripten once it can unwind again
 #[test]
-#[cfg(not(miri))] // Miri does not support catching panics
+#[cfg(not(any(miri, target_os = "emscripten")))]
 fn drain_filter_consumed_panic() {
     use std::rc::Rc;
     use std::sync::Mutex;
@@ -995,8 +997,9 @@ fn drain_filter_consumed_panic() {
     }
 }
 
+// FIXME: Re-enable emscripten once it can catch panics
 #[test]
-#[cfg(not(miri))] // Miri does not support catching panics
+#[cfg(not(any(miri, target_os = "emscripten")))] // Miri does not support catching panics
 fn drain_filter_unconsumed_panic() {
     use std::rc::Rc;
     use std::sync::Mutex;
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index f75b7a45443..e2704e807d1 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -445,6 +445,15 @@ impl TypeId {
 ///
 /// The current implementation uses the same infrastructure as compiler
 /// diagnostics and debuginfo, but this is not guaranteed.
+///
+/// # Example
+///
+/// ```rust
+/// assert_eq!(
+///     std::any::type_name::<Option<String>>(),
+///     "core::option::Option<alloc::string::String>",
+/// );
+/// ```
 #[stable(feature = "type_name", since = "1.38.0")]
 #[rustc_const_unstable(feature = "const_type_name")]
 pub const fn type_name<T: ?Sized>() -> &'static str {
diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs
index eda0e7c518c..0ea4187ccd4 100644
--- a/src/libcore/ffi.rs
+++ b/src/libcore/ffi.rs
@@ -49,8 +49,10 @@ impl fmt::Debug for c_void {
 /// Basic implementation of a `va_list`.
 // The name is WIP, using `VaListImpl` for now.
 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-              not(target_arch = "x86_64"), not(target_arch = "asmjs")),
+              not(target_arch = "x86_64")),
           all(target_arch = "aarch64", target_os = "ios"),
+          target_arch = "wasm32",
+          target_arch = "asmjs",
           windows))]
 #[repr(transparent)]
 #[unstable(feature = "c_variadic",
@@ -67,8 +69,10 @@ pub struct VaListImpl<'f> {
 }
 
 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-              not(target_arch = "x86_64"), not(target_arch = "asmjs")),
+              not(target_arch = "x86_64")),
           all(target_arch = "aarch64", target_os = "ios"),
+          target_arch = "wasm32",
+          target_arch = "asmjs",
           windows))]
 #[unstable(feature = "c_variadic",
            reason = "the `c_variadic` feature has not been properly tested on \
@@ -137,38 +141,6 @@ pub struct VaListImpl<'f> {
     _marker: PhantomData<&'f mut &'f c_void>,
 }
 
-/// asm.js ABI implementation of a `va_list`.
-// asm.js uses the PNaCl ABI, which specifies that a `va_list` is
-// an array of 4 32-bit integers, according to the old PNaCl docs at
-// https://web.archive.org/web/20130518054430/https://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Derived-Types
-// and clang does the same in `CreatePNaClABIBuiltinVaListDecl` from `lib/AST/ASTContext.cpp`
-#[cfg(all(target_arch = "asmjs", not(windows)))]
-#[repr(C)]
-#[unstable(feature = "c_variadic",
-           reason = "the `c_variadic` feature has not been properly tested on \
-                     all supported platforms",
-           issue = "44930")]
-#[lang = "va_list"]
-pub struct VaListImpl<'f> {
-    inner: [crate::mem::MaybeUninit<i32>; 4],
-    _marker: PhantomData<&'f mut &'f c_void>,
-}
-
-#[cfg(all(target_arch = "asmjs", not(windows)))]
-#[unstable(feature = "c_variadic",
-           reason = "the `c_variadic` feature has not been properly tested on \
-                     all supported platforms",
-           issue = "44930")]
-impl<'f> fmt::Debug for VaListImpl<'f> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        unsafe {
-            write!(f, "va_list* [{:#x}, {:#x}, {:#x}, {:#x}]",
-                   self.inner[0].read(), self.inner[1].read(),
-                   self.inner[2].read(), self.inner[3].read())
-        }
-    }
-}
-
 /// A wrapper for a `va_list`
 #[repr(transparent)]
 #[derive(Debug)]
@@ -178,14 +150,18 @@ impl<'f> fmt::Debug for VaListImpl<'f> {
            issue = "44930")]
 pub struct VaList<'a, 'f: 'a> {
     #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-                  not(target_arch = "x86_64"), not(target_arch = "asmjs")),
+                  not(target_arch = "x86_64")),
               all(target_arch = "aarch64", target_os = "ios"),
+              target_arch = "wasm32",
+              target_arch = "asmjs",
               windows))]
     inner: VaListImpl<'f>,
 
     #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
-                  target_arch = "x86_64", target_arch = "asmjs"),
+                  target_arch = "x86_64"),
               any(not(target_arch = "aarch64"), not(target_os = "ios")),
+              not(target_arch = "wasm32"),
+              not(target_arch = "asmjs"),
               not(windows)))]
     inner: &'a mut VaListImpl<'f>,
 
@@ -193,8 +169,10 @@ pub struct VaList<'a, 'f: 'a> {
 }
 
 #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
-              not(target_arch = "x86_64"), not(target_arch = "asmjs")),
+              not(target_arch = "x86_64")),
           all(target_arch = "aarch64", target_os = "ios"),
+          target_arch = "wasm32",
+          target_arch = "asmjs",
           windows))]
 #[unstable(feature = "c_variadic",
            reason = "the `c_variadic` feature has not been properly tested on \
@@ -212,8 +190,10 @@ impl<'f> VaListImpl<'f> {
 }
 
 #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
-              target_arch = "x86_64", target_arch = "asmjs"),
+              target_arch = "x86_64"),
           any(not(target_arch = "aarch64"), not(target_os = "ios")),
+          not(target_arch = "wasm32"),
+          not(target_arch = "asmjs"),
           not(windows)))]
 #[unstable(feature = "c_variadic",
            reason = "the `c_variadic` feature has not been properly tested on \
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs
index 15ce2277fa0..e6e3454b36f 100644
--- a/src/libcore/fmt/builders.rs
+++ b/src/libcore/fmt/builders.rs
@@ -775,10 +775,10 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
                reason = "recently added",
                issue = "62482")]
     pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
-        assert!(!self.has_key, "attempted to begin a new map entry \
-                                without completing the previous one");
-
         self.result = self.result.and_then(|_| {
+            assert!(!self.has_key, "attempted to begin a new map entry \
+                                    without completing the previous one");
+
             if self.is_pretty() {
                 if !self.has_fields {
                     self.fmt.write_str("\n")?;
@@ -839,9 +839,9 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
                reason = "recently added",
                issue = "62482")]
     pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
-        assert!(self.has_key, "attempted to format a map value before its key");
-
         self.result = self.result.and_then(|_| {
+            assert!(self.has_key, "attempted to format a map value before its key");
+
             if self.is_pretty() {
                 let mut slot = None;
                 let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
@@ -924,9 +924,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn finish(&mut self) -> fmt::Result {
-        assert!(!self.has_key, "attempted to finish a map with a partial entry");
+        self.result.and_then(|_| {
+            assert!(!self.has_key, "attempted to finish a map with a partial entry");
 
-        self.result.and_then(|_| self.fmt.write_str("}"))
+            self.fmt.write_str("}")
+        })
     }
 
     fn is_pretty(&self) -> bool {
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 5dfdd162306..8413b2e0ac4 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -108,10 +108,10 @@ pub struct Error;
 /// [`io::Write`]: ../../std/io/trait.Write.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Write {
-    /// Writes a slice of bytes into this writer, returning whether the write
+    /// Writes a string slice into this writer, returning whether the write
     /// succeeded.
     ///
-    /// This method can only succeed if the entire byte slice was successfully
+    /// This method can only succeed if the entire string slice was successfully
     /// written, and this method will not return until all data has been
     /// written or an error occurs.
     ///
diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs
index ee4be6c9151..368a2f16b28 100644
--- a/src/libcore/hint.rs
+++ b/src/libcore/hint.rs
@@ -114,24 +114,8 @@ pub fn black_box<T>(dummy: T) -> T {
     // this. LLVM's intepretation of inline assembly is that it's, well, a black
     // box. This isn't the greatest implementation since it probably deoptimizes
     // more than we want, but it's so far good enough.
-    #[cfg(not(any(
-        target_arch = "asmjs",
-        all(
-            target_arch = "wasm32",
-            target_os = "emscripten"
-        )
-    )))]
     unsafe {
         asm!("" : : "r"(&dummy));
         return dummy;
     }
-
-    // Not all platforms support inline assembly so try to do something without
-    // inline assembly which in theory still hinders at least some optimizations
-    // on those targets. This is the "best effort" scenario.
-    unsafe {
-        let ret = crate::ptr::read_volatile(&dummy);
-        crate::mem::forget(dummy);
-        ret
-    }
 }
diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs
index 25439136b85..00a86417058 100644
--- a/src/libcore/iter/traits/collect.rs
+++ b/src/libcore/iter/traits/collect.rs
@@ -167,7 +167,7 @@ pub trait FromIterator<A>: Sized {
 /// // and we'll implement IntoIterator
 /// impl IntoIterator for MyCollection {
 ///     type Item = i32;
-///     type IntoIter = ::std::vec::IntoIter<Self::Item>;
+///     type IntoIter = std::vec::IntoIter<Self::Item>;
 ///
 ///     fn into_iter(self) -> Self::IntoIter {
 ///         self.0.into_iter()
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index 23608931b1d..c7da56aad30 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -236,7 +236,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 /// ```
 ///
 /// [alignment]: ./fn.align_of.html
-#[inline]
+#[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 pub const fn size_of<T>() -> usize {
@@ -328,7 +328,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 ///
 /// assert_eq!(4, mem::align_of::<i32>());
 /// ```
-#[inline]
+#[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 pub const fn align_of<T>() -> usize {
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 998c8f81652..b4ade704144 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -1864,7 +1864,7 @@ if `self < 0`, this is equal to round towards +/- infinity.
 
 # Panics
 
-This function will panic if `rhs` is 0.
+This function will panic if `rhs` is 0 or the division results in overflow.
 
 # Examples
 
@@ -1903,7 +1903,7 @@ This is done as if by the Euclidean division algorithm -- given
 
 # Panics
 
-This function will panic if `rhs` is 0.
+This function will panic if `rhs` is 0 or the division results in overflow.
 
 # Examples
 
@@ -3694,6 +3694,10 @@ Since, for the positive integers, all common
 definitions of division are equal, this
 is exactly equal to `self / rhs`.
 
+# Panics
+
+This function will panic if `rhs` is 0.
+
 # Examples
 
 Basic usage:
@@ -3719,6 +3723,10 @@ Since, for the positive integers, all common
 definitions of division are equal, this
 is exactly equal to `self % rhs`.
 
+# Panics
+
+This function will panic if `rhs` is 0.
+
 # Examples
 
 Basic usage:
@@ -3749,8 +3757,8 @@ assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline]
-            pub fn is_power_of_two(self) -> bool {
-                (self.wrapping_sub(1)) & self == 0 && !(self == 0)
+            pub const fn is_power_of_two(self) -> bool {
+                self.count_ones() == 1
             }
         }
 
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
index 59a10ae99bb..5fe9895d8d2 100644
--- a/src/libcore/num/wrapping.rs
+++ b/src/libcore/num/wrapping.rs
@@ -437,7 +437,7 @@ assert_eq!(n.trailing_zeros(), 3);
             /// wrapping the truncated bits to the end of the resulting
             /// integer.
             ///
-            /// Please note this isn't the same operation as the `>>` shifting
+            /// Please note this isn't the same operation as the `<<` shifting
             /// operator!
             ///
             /// # Examples
@@ -463,7 +463,7 @@ assert_eq!(n.trailing_zeros(), 3);
             /// wrapping the truncated bits to the beginning of the resulting
             /// integer.
             ///
-            /// Please note this isn't the same operation as the `<<` shifting
+            /// Please note this isn't the same operation as the `>>` shifting
             /// operator!
             ///
             /// # Examples
diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs
index 8e468300846..d29147645f7 100644
--- a/src/libcore/ops/unsize.rs
+++ b/src/libcore/ops/unsize.rs
@@ -76,7 +76,7 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 /// ```
 /// # #![feature(dispatch_from_dyn, unsize)]
 /// # use std::{ops::DispatchFromDyn, marker::Unsize};
-/// # struct Rc<T: ?Sized>(::std::rc::Rc<T>);
+/// # struct Rc<T: ?Sized>(std::rc::Rc<T>);
 /// impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T>
 /// where
 ///     T: Unsize<U>,
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 47e3a0d2167..9eb29eae7f7 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -64,7 +64,7 @@
 //!
 //! fn check_optional(optional: Option<Box<i32>>) {
 //!     match optional {
-//!         Some(ref p) => println!("has value {}", p),
+//!         Some(p) => println!("has value {}", p),
 //!         None => println!("has no value"),
 //!     }
 //! }
@@ -83,7 +83,7 @@
 //! let msg = Some("howdy");
 //!
 //! // Take a reference to the contained string
-//! if let Some(ref m) = msg {
+//! if let Some(m) = &msg {
 //!     println!("{}", *m);
 //! }
 //!
@@ -395,10 +395,10 @@ impl<T> Option<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_or(self, def: T) -> T {
+    pub fn unwrap_or(self, default: T) -> T {
         match self {
             Some(x) => x,
-            None => def,
+            None => default,
         }
     }
 
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 93391918595..3cc0a1cd75e 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -188,7 +188,7 @@ unsafe fn real_drop_in_place<T: ?Sized>(to_drop: &mut T) {
 /// let p: *const i32 = ptr::null();
 /// assert!(p.is_null());
 /// ```
-#[inline]
+#[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 pub const fn null<T>() -> *const T { 0 as *const T }
@@ -203,7 +203,7 @@ pub const fn null<T>() -> *const T { 0 as *const T }
 /// let p: *mut i32 = ptr::null_mut();
 /// assert!(p.is_null());
 /// ```
-#[inline]
+#[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 885696e5acf..f67012d8f2f 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -176,7 +176,7 @@ Section: Creating a string
 /// ```
 /// fn from_utf8_lossy<F>(mut input: &[u8], mut push: F) where F: FnMut(&str) {
 ///     loop {
-///         match ::std::str::from_utf8(input) {
+///         match std::str::from_utf8(input) {
 ///             Ok(valid) => {
 ///                 push(valid);
 ///                 break
@@ -184,7 +184,7 @@ Section: Creating a string
 ///             Err(error) => {
 ///                 let (valid, after_valid) = input.split_at(error.valid_up_to());
 ///                 unsafe {
-///                     push(::std::str::from_utf8_unchecked(valid))
+///                     push(std::str::from_utf8_unchecked(valid))
 ///                 }
 ///                 push("\u{FFFD}");
 ///
diff --git a/src/libcore/tests/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs
index 200659b91bb..25572443281 100644
--- a/src/libcore/tests/fmt/builders.rs
+++ b/src/libcore/tests/fmt/builders.rs
@@ -320,6 +320,46 @@ mod debug_map {
     }
 
     #[test]
+    fn test_entry_err() {
+        // Ensure errors in a map entry don't trigger panics (#65231)
+        use std::fmt::Write;
+
+        struct ErrorFmt;
+
+        impl fmt::Debug for ErrorFmt {
+            fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+                Err(fmt::Error)
+            }
+        }
+
+        struct KeyValue<K, V>(usize, K, V);
+
+        impl<K, V> fmt::Debug for KeyValue<K, V>
+        where
+            K: fmt::Debug,
+            V: fmt::Debug,
+        {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                let mut map = fmt.debug_map();
+
+                for _ in 0..self.0 {
+                    map.entry(&self.1, &self.2);
+                }
+
+                map.finish()
+            }
+        }
+
+        let mut buf = String::new();
+
+        assert!(write!(&mut buf, "{:?}", KeyValue(1, ErrorFmt, "bar")).is_err());
+        assert!(write!(&mut buf, "{:?}", KeyValue(1, "foo", ErrorFmt)).is_err());
+
+        assert!(write!(&mut buf, "{:?}", KeyValue(2, ErrorFmt, "bar")).is_err());
+        assert!(write!(&mut buf, "{:?}", KeyValue(2, "foo", ErrorFmt)).is_err());
+    }
+
+    #[test]
     #[should_panic]
     fn test_invalid_key_when_entry_is_incomplete() {
         struct Foo;
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 9b3609eca3e..93274ef0c92 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -29,11 +29,12 @@ rustc_index = { path = "../librustc_index" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
 backtrace = "0.3.3"
 parking_lot = "0.9"
 byteorder = { version = "1.3" }
 chalk-engine = { version = "0.9.0", default-features=false }
 rustc_fs_util = { path = "../librustc_fs_util" }
-smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
+smallvec = { version = "0.6.8", features = ["union", "may_dangle"] }
 measureme = "0.3"
diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs
index 5a5919d7866..3daf0fc9df7 100644
--- a/src/librustc/arena.rs
+++ b/src/librustc/arena.rs
@@ -98,7 +98,6 @@ macro_rules! arena_types {
                 rustc::hir::def_id::DefId,
             >,
             [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes,
-            [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>,
             [few] lint_levels: rustc::lint::LintLevelMap,
             [few] stability_index: rustc::middle::stability::Index<'tcx>,
             [few] features: syntax::feature_gate::Features,
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 25cbf8c88de..0104507f702 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -3,7 +3,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::vec::{Idx, IndexVec};
 use smallvec::SmallVec;
-use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering};
+use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, AtomicU64, Ordering};
+use rustc_data_structures::sharded::{self, Sharded};
+use std::sync::atomic::Ordering::SeqCst;
 use std::env;
 use std::hash::Hash;
 use std::collections::hash_map::Entry;
@@ -33,7 +35,7 @@ impl DepNodeIndex {
     pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(PartialEq)]
 pub enum DepNodeColor {
     Red,
     Green(DepNodeIndex)
@@ -53,7 +55,7 @@ struct DepGraphData {
     /// tracking. The `current` field is the dependency graph of only the
     /// current compilation session: We don't merge the previous dep-graph into
     /// current one anymore.
-    current: Lock<CurrentDepGraph>,
+    current: CurrentDepGraph,
 
     /// The dep-graph from the previous compilation session. It contains all
     /// nodes and edges as well as all fingerprints of nodes that have them.
@@ -95,7 +97,7 @@ impl DepGraph {
             data: Some(Lrc::new(DepGraphData {
                 previous_work_products: prev_work_products,
                 dep_node_debug: Default::default(),
-                current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)),
+                current: CurrentDepGraph::new(prev_graph_node_count),
                 emitting_diagnostics: Default::default(),
                 emitting_diagnostics_cond_var: Condvar::new(),
                 previous: prev_graph,
@@ -117,13 +119,12 @@ impl DepGraph {
     }
 
     pub fn query(&self) -> DepGraphQuery {
-        let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
-        let nodes: Vec<_> = current_dep_graph.data.iter().map(|n| n.node).collect();
+        let data = self.data.as_ref().unwrap().current.data.lock();
+        let nodes: Vec<_> = data.iter().map(|n| n.node).collect();
         let mut edges = Vec::new();
-        for (from, edge_targets) in current_dep_graph.data.iter()
-                                                           .map(|d| (d.node, &d.edges)) {
+        for (from, edge_targets) in data.iter().map(|d| (d.node, &d.edges)) {
             for &edge_target in edge_targets.iter() {
-                let to = current_dep_graph.data[edge_target].node;
+                let to = data[edge_target].node;
                 edges.push((from, to));
             }
         }
@@ -202,7 +203,7 @@ impl DepGraph {
                 read_set: Default::default(),
             }),
             |data, key, fingerprint, task| {
-                data.borrow_mut().complete_task(key, task.unwrap(), fingerprint)
+                data.complete_task(key, task.unwrap(), fingerprint)
             },
             hash_result)
     }
@@ -223,7 +224,7 @@ impl DepGraph {
         self.with_task_impl(key, cx, input, true, identity_fn,
             |_| None,
             |data, key, fingerprint, _| {
-                data.borrow_mut().alloc_node(key, SmallVec::new(), fingerprint)
+                data.alloc_node(key, SmallVec::new(), fingerprint)
             },
             hash_result::<R>)
     }
@@ -236,7 +237,7 @@ impl DepGraph {
         no_tcx: bool,
         task: fn(C, A) -> R,
         create_task: fn(DepNode) -> Option<TaskDeps>,
-        finish_task_and_alloc_depnode: fn(&Lock<CurrentDepGraph>,
+        finish_task_and_alloc_depnode: fn(&CurrentDepGraph,
                                           DepNode,
                                           Fingerprint,
                                           Option<TaskDeps>) -> DepNodeIndex,
@@ -350,7 +351,6 @@ impl DepGraph {
                 (r, task_deps.into_inner())
             });
             let dep_node_index = data.current
-                                     .borrow_mut()
                                      .complete_anon_task(dep_kind, task_deps);
             (result, dep_node_index)
         } else {
@@ -374,8 +374,7 @@ impl DepGraph {
         self.with_task_impl(key, cx, arg, false, task,
             |_| None,
             |data, key, fingerprint, _| {
-                let mut current = data.borrow_mut();
-                current.alloc_node(key, smallvec![], fingerprint)
+                data.alloc_node(key, smallvec![], fingerprint)
             },
             hash_result)
     }
@@ -383,9 +382,9 @@ impl DepGraph {
     #[inline]
     pub fn read(&self, v: DepNode) {
         if let Some(ref data) = self.data {
-            let current = data.current.borrow_mut();
-            if let Some(&dep_node_index) = current.node_to_node_index.get(&v) {
-                std::mem::drop(current);
+            let map = data.current.node_to_node_index.get_shard_by_value(&v).lock();
+            if let Some(dep_node_index) = map.get(&v).copied() {
+                std::mem::drop(map);
                 data.read_index(dep_node_index);
             } else {
                 bug!("DepKind {:?} should be pre-allocated but isn't.", v.kind)
@@ -406,8 +405,9 @@ impl DepGraph {
             .as_ref()
             .unwrap()
             .current
-            .borrow_mut()
             .node_to_node_index
+            .get_shard_by_value(dep_node)
+            .lock()
             .get(dep_node)
             .cloned()
             .unwrap()
@@ -416,7 +416,11 @@ impl DepGraph {
     #[inline]
     pub fn dep_node_exists(&self, dep_node: &DepNode) -> bool {
         if let Some(ref data) = self.data {
-            data.current.borrow_mut().node_to_node_index.contains_key(dep_node)
+            data.current
+                .node_to_node_index
+                .get_shard_by_value(&dep_node)
+                .lock()
+                .contains_key(dep_node)
         } else {
             false
         }
@@ -424,8 +428,8 @@ impl DepGraph {
 
     #[inline]
     pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint {
-        let current = self.data.as_ref().expect("dep graph enabled").current.borrow_mut();
-        current.data[dep_node_index].fingerprint
+        let data = self.data.as_ref().expect("dep graph enabled").current.data.lock();
+        data[dep_node_index].fingerprint
     }
 
     pub fn prev_fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
@@ -479,32 +483,29 @@ impl DepGraph {
 
     pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> {
         if cfg!(debug_assertions) {
-            let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
+            let current_dep_graph = &self.data.as_ref().unwrap().current;
 
-            Some((current_dep_graph.total_read_count,
-                  current_dep_graph.total_duplicate_read_count))
+            Some((current_dep_graph.total_read_count.load(SeqCst),
+                  current_dep_graph.total_duplicate_read_count.load(SeqCst)))
         } else {
             None
         }
     }
 
     pub fn serialize(&self) -> SerializedDepGraph {
-        let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
+        let data = self.data.as_ref().unwrap().current.data.lock();
 
         let fingerprints: IndexVec<SerializedDepNodeIndex, _> =
-            current_dep_graph.data.iter().map(|d| d.fingerprint).collect();
+            data.iter().map(|d| d.fingerprint).collect();
         let nodes: IndexVec<SerializedDepNodeIndex, _> =
-            current_dep_graph.data.iter().map(|d| d.node).collect();
+            data.iter().map(|d| d.node).collect();
 
-        let total_edge_count: usize = current_dep_graph.data.iter()
-                                                            .map(|d| d.edges.len())
-                                                            .sum();
+        let total_edge_count: usize = data.iter().map(|d| d.edges.len()).sum();
 
         let mut edge_list_indices = IndexVec::with_capacity(nodes.len());
         let mut edge_list_data = Vec::with_capacity(total_edge_count);
 
-        for (current_dep_node_index, edges) in current_dep_graph.data.iter_enumerated()
-                                                                .map(|(i, d)| (i, &d.edges)) {
+        for (current_dep_node_index, edges) in data.iter_enumerated().map(|(i, d)| (i, &d.edges)) {
             let start = edge_list_data.len() as u32;
             // This should really just be a memcpy :/
             edge_list_data.extend(edges.iter().map(|i| SerializedDepNodeIndex::new(i.index())));
@@ -600,7 +601,11 @@ impl DepGraph {
 
         #[cfg(not(parallel_compiler))]
         {
-            debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node));
+            debug_assert!(!data.current
+                               .node_to_node_index
+                               .get_shard_by_value(dep_node)
+                               .lock()
+                               .contains_key(dep_node));
             debug_assert!(data.colors.get(prev_dep_node_index).is_none());
         }
 
@@ -733,15 +738,13 @@ impl DepGraph {
         // There may be multiple threads trying to mark the same dep node green concurrently
 
         let dep_node_index = {
-            let mut current = data.current.borrow_mut();
-
             // Copy the fingerprint from the previous graph,
             // so we don't have to recompute it
             let fingerprint = data.previous.fingerprint_by_index(prev_dep_node_index);
 
             // We allocating an entry for the node in the current dependency graph and
             // adding all the appropriate edges imported from the previous graph
-            current.intern_node(*dep_node, current_deps, fingerprint)
+            data.current.intern_node(*dep_node, current_deps, fingerprint)
         };
 
         // ... emitting any stored diagnostic ...
@@ -917,9 +920,27 @@ struct DepNodeData {
     fingerprint: Fingerprint,
 }
 
+/// `CurrentDepGraph` stores the dependency graph for the current session.
+/// It will be populated as we run queries or tasks.
+///
+/// The nodes in it are identified by an index (`DepNodeIndex`).
+/// The data for each node is stored in its `DepNodeData`, found in the `data` field.
+///
+/// We never remove nodes from the graph: they are only added.
+///
+/// This struct uses two locks internally. The `data` and `node_to_node_index` fields are
+/// locked separately. Operations that take a `DepNodeIndex` typically just access
+/// the data field.
+///
+/// The only operation that must manipulate both locks is adding new nodes, in which case
+/// we first acquire the `node_to_node_index` lock and then, once a new node is to be inserted,
+/// acquire the lock on `data.`
 pub(super) struct CurrentDepGraph {
-    data: IndexVec<DepNodeIndex, DepNodeData>,
-    node_to_node_index: FxHashMap<DepNode, DepNodeIndex>,
+    data: Lock<IndexVec<DepNodeIndex, DepNodeData>>,
+    node_to_node_index: Sharded<FxHashMap<DepNode, DepNodeIndex>>,
+
+    /// Used to trap when a specific edge is added to the graph.
+    /// This is used for debug purposes and is only active with `debug_assertions`.
     #[allow(dead_code)]
     forbidden_edge: Option<EdgeFilter>,
 
@@ -936,8 +957,10 @@ pub(super) struct CurrentDepGraph {
     /// the `DepGraph` is created.
     anon_id_seed: Fingerprint,
 
-    total_read_count: u64,
-    total_duplicate_read_count: u64,
+    /// These are simple counters that are for profiling and
+    /// debugging and only active with `debug_assertions`.
+    total_read_count: AtomicU64,
+    total_duplicate_read_count: AtomicU64,
 }
 
 impl CurrentDepGraph {
@@ -971,20 +994,20 @@ impl CurrentDepGraph {
         let new_node_count_estimate = (prev_graph_node_count * 102) / 100 + 200;
 
         CurrentDepGraph {
-            data: IndexVec::with_capacity(new_node_count_estimate),
-            node_to_node_index: FxHashMap::with_capacity_and_hasher(
-                new_node_count_estimate,
+            data: Lock::new(IndexVec::with_capacity(new_node_count_estimate)),
+            node_to_node_index: Sharded::new(|| FxHashMap::with_capacity_and_hasher(
+                new_node_count_estimate / sharded::SHARDS,
                 Default::default(),
-            ),
+            )),
             anon_id_seed: stable_hasher.finish(),
             forbidden_edge,
-            total_read_count: 0,
-            total_duplicate_read_count: 0,
+            total_read_count: AtomicU64::new(0),
+            total_duplicate_read_count: AtomicU64::new(0),
         }
     }
 
     fn complete_task(
-        &mut self,
+        &self,
         node: DepNode,
         task_deps: TaskDeps,
         fingerprint: Fingerprint
@@ -992,7 +1015,7 @@ impl CurrentDepGraph {
         self.alloc_node(node, task_deps.reads, fingerprint)
     }
 
-    fn complete_anon_task(&mut self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex {
+    fn complete_anon_task(&self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex {
         debug_assert!(!kind.is_eval_always());
 
         let mut hasher = StableHasher::new();
@@ -1017,28 +1040,30 @@ impl CurrentDepGraph {
     }
 
     fn alloc_node(
-        &mut self,
+        &self,
         dep_node: DepNode,
         edges: SmallVec<[DepNodeIndex; 8]>,
         fingerprint: Fingerprint
     ) -> DepNodeIndex {
-        debug_assert!(!self.node_to_node_index.contains_key(&dep_node));
+        debug_assert!(!self.node_to_node_index
+                           .get_shard_by_value(&dep_node)
+                           .lock()
+                           .contains_key(&dep_node));
         self.intern_node(dep_node, edges, fingerprint)
     }
 
     fn intern_node(
-        &mut self,
+        &self,
         dep_node: DepNode,
         edges: SmallVec<[DepNodeIndex; 8]>,
         fingerprint: Fingerprint
     ) -> DepNodeIndex {
-        debug_assert_eq!(self.node_to_node_index.len(), self.data.len());
-
-        match self.node_to_node_index.entry(dep_node) {
+        match self.node_to_node_index.get_shard_by_value(&dep_node).lock().entry(dep_node) {
             Entry::Occupied(entry) => *entry.get(),
             Entry::Vacant(entry) => {
-                let dep_node_index = DepNodeIndex::new(self.data.len());
-                self.data.push(DepNodeData {
+                let mut data = self.data.lock();
+                let dep_node_index = DepNodeIndex::new(data.len());
+                data.push(DepNodeData {
                     node: dep_node,
                     edges,
                     fingerprint
@@ -1057,7 +1082,7 @@ impl DepGraphData {
             if let Some(task_deps) = icx.task_deps {
                 let mut task_deps = task_deps.lock();
                 if cfg!(debug_assertions) {
-                    self.current.lock().total_read_count += 1;
+                    self.current.total_read_count.fetch_add(1, SeqCst);
                 }
                 if task_deps.read_set.insert(source) {
                     task_deps.reads.push(source);
@@ -1065,9 +1090,9 @@ impl DepGraphData {
                     #[cfg(debug_assertions)]
                     {
                         if let Some(target) = task_deps.node {
-                            let graph = self.current.lock();
-                            if let Some(ref forbidden_edge) = graph.forbidden_edge {
-                                let source = graph.data[source].node;
+                            let data = self.current.data.lock();
+                            if let Some(ref forbidden_edge) = self.current.forbidden_edge {
+                                let source = data[source].node;
                                 if forbidden_edge.test(&source, &target) {
                                     bug!("forbidden edge {:?} -> {:?} created",
                                         source,
@@ -1077,7 +1102,7 @@ impl DepGraphData {
                         }
                     }
                 } else if cfg!(debug_assertions) {
-                    self.current.lock().total_duplicate_read_count += 1;
+                    self.current.total_duplicate_read_count.fetch_add(1, SeqCst);
                 }
             }
         })
diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs
index 50b6ef57b55..122ae4a6cf6 100644
--- a/src/librustc/error_codes.rs
+++ b/src/librustc/error_codes.rs
@@ -2005,6 +2005,24 @@ a (non-transparent) struct containing a single float, while `Grams` is a
 transparent wrapper around a float. This can make a difference for the ABI.
 "##,
 
+E0697: r##"
+A closure has been used as `static`.
+
+Erroneous code example:
+
+```compile_fail,E0697
+fn main() {
+    static || {}; // used as `static`
+}
+```
+
+Closures cannot be used as `static`. They "save" the environment,
+and as such a static closure would save only a static environment
+which would consist only of variables with a static lifetime. Given
+this it would be better to use a proper function. The easiest fix
+is to remove the `static` keyword.
+"##,
+
 E0698: r##"
 When using generators (or async) all type variables must be bound so a
 generator can be constructed.
@@ -2027,8 +2045,8 @@ so that a generator can then be constructed:
 async fn bar<T>() -> () {}
 
 async fn foo() {
-  bar::<String>().await;
-  //   ^^^^^^^^ specify type explicitly
+    bar::<String>().await;
+    //   ^^^^^^^^ specify type explicitly
 }
 ```
 "##,
@@ -2108,6 +2126,84 @@ static X: u32 = 42;
 ```
 "##,
 
+E0728: r##"
+[`await`] has been used outside [`async`] function or block.
+
+Erroneous code examples:
+
+```edition2018,compile_fail,E0728
+# use std::pin::Pin;
+# use std::future::Future;
+# use std::task::{Context, Poll};
+#
+# struct WakeOnceThenComplete(bool);
+#
+# fn wake_and_yield_once() -> WakeOnceThenComplete {
+#     WakeOnceThenComplete(false)
+# }
+#
+# impl Future for WakeOnceThenComplete {
+#     type Output = ();
+#     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+#         if self.0 {
+#             Poll::Ready(())
+#         } else {
+#             cx.waker().wake_by_ref();
+#             self.0 = true;
+#             Poll::Pending
+#         }
+#     }
+# }
+#
+fn foo() {
+    wake_and_yield_once().await // `await` is used outside `async` context
+}
+```
+
+[`await`] is used to suspend the current computation until the given
+future is ready to produce a value. So it is legal only within
+an [`async`] context, like an `async fn` or an `async` block.
+
+```edition2018
+# use std::pin::Pin;
+# use std::future::Future;
+# use std::task::{Context, Poll};
+#
+# struct WakeOnceThenComplete(bool);
+#
+# fn wake_and_yield_once() -> WakeOnceThenComplete {
+#     WakeOnceThenComplete(false)
+# }
+#
+# impl Future for WakeOnceThenComplete {
+#     type Output = ();
+#     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
+#         if self.0 {
+#             Poll::Ready(())
+#         } else {
+#             cx.waker().wake_by_ref();
+#             self.0 = true;
+#             Poll::Pending
+#         }
+#     }
+# }
+#
+async fn foo() {
+    wake_and_yield_once().await // `await` is used within `async` function
+}
+
+fn bar(x: u8) -> impl Future<Output = u8> {
+    async move {
+        wake_and_yield_once().await; // `await` is used within `async` block
+        x
+    }
+}
+```
+
+[`async`]: https://doc.rust-lang.org/std/keyword.async.html
+[`await`]: https://doc.rust-lang.org/std/keyword.await.html
+"##,
+
 E0734: r##"
 A stability attribute has been used outside of the standard library.
 
@@ -2191,7 +2287,6 @@ See [RFC 2091] for details on this and other limitations.
     E0657, // `impl Trait` can only capture lifetimes bound at the fn level
     E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
     E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
-    E0697, // closures cannot be static
 //  E0707, // multiple elided lifetimes used in arguments of `async fn`
     E0708, // `async` non-`move` closures with parameters are not currently
            // supported
@@ -2201,6 +2296,5 @@ See [RFC 2091] for details on this and other limitations.
 //  E0702, // replaced with a generic attribute input check
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
     E0727, // `async` generators are not yet supported
-    E0728, // `await` must be in an `async` function or block
     E0739, // invalid track_caller application/syntax
 }
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index f7d31ca06ee..a071a539e01 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -6,7 +6,7 @@ use crate::ty;
 use crate::util::nodemap::DefIdMap;
 
 use syntax::ast;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::ast::NodeId;
 use syntax_pos::Span;
 use rustc_macros::HashStable;
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 72fd054ee8a..d5287fd415b 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -64,14 +64,15 @@ use syntax::ast;
 use syntax::ptr::P as AstP;
 use syntax::ast::*;
 use syntax::errors;
-use syntax::ext::base::SpecialDerives;
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::base::SpecialDerives;
 use syntax::print::pprust;
+use syntax::parse::token::{self, Nonterminal, Token};
+use syntax::tokenstream::{TokenStream, TokenTree};
+use syntax::sess::ParseSess;
 use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned};
 use syntax::symbol::{kw, sym, Symbol};
-use syntax::tokenstream::{TokenStream, TokenTree};
-use syntax::parse::token::{self, Token};
 use syntax::visit::{self, Visitor};
+use syntax_pos::hygiene::ExpnId;
 use syntax_pos::Span;
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
@@ -86,6 +87,11 @@ pub struct LoweringContext<'a> {
 
     resolver: &'a mut dyn Resolver,
 
+    /// HACK(Centril): there is a cyclic dependency between the parser and lowering
+    /// if we don't have this function pointer. To avoid that dependency so that
+    /// librustc is independent of the parser, we use dynamic dispatch here.
+    nt_to_tokenstream: NtToTokenstream,
+
     /// The items being lowered are collected here.
     items: BTreeMap<hir::HirId, hir::Item>,
 
@@ -180,6 +186,8 @@ pub trait Resolver {
     fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool;
 }
 
+type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
+
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
 /// and if so, what meaning it has.
 #[derive(Debug)]
@@ -236,6 +244,7 @@ pub fn lower_crate(
     dep_graph: &DepGraph,
     krate: &Crate,
     resolver: &mut dyn Resolver,
+    nt_to_tokenstream: NtToTokenstream,
 ) -> hir::Crate {
     // We're constructing the HIR here; we don't care what we will
     // read, since we haven't even constructed the *input* to
@@ -249,6 +258,7 @@ pub fn lower_crate(
         sess,
         cstore,
         resolver,
+        nt_to_tokenstream,
         items: BTreeMap::new(),
         trait_items: BTreeMap::new(),
         impl_items: BTreeMap::new(),
@@ -1022,7 +1032,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_token(&mut self, token: Token) -> TokenStream {
         match token.kind {
             token::Interpolated(nt) => {
-                let tts = nt.to_tokenstream(&self.sess.parse_sess, token.span);
+                let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
                 self.lower_token_stream(tts)
             }
             _ => TokenTree::Token(token).into(),
@@ -3281,10 +3291,14 @@ impl<'a> LoweringContext<'a> {
                 let id = self.sess.next_node_id();
                 self.new_named_lifetime(id, span, hir::LifetimeName::Error)
             }
-            // This is the normal case.
-            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
-
-            AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
+            // `PassThrough` is the normal case.
+            // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
+            // is unsuitable here, as these can occur from missing lifetime parameters in a
+            // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
+            // lifetime. Instead, we simply create an implicit lifetime, which will be checked
+            // later, at which point a suitable error will be emitted.
+          | AnonymousLifetimeMode::PassThrough
+          | AnonymousLifetimeMode::ReportError => self.new_implicit_lifetime(span),
         }
     }
 
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index 548a2fedfff..73d2ac5c134 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -18,7 +18,7 @@ use smallvec::SmallVec;
 use syntax::attr;
 use syntax::ast::*;
 use syntax::visit::{self, Visitor};
-use syntax::ext::base::SpecialDerives;
+use syntax_expand::base::SpecialDerives;
 use syntax::source_map::{respan, DesugaringKind, Spanned};
 use syntax::symbol::{kw, sym};
 use syntax_pos::Span;
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 1997e2aab35..9be339be703 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -2,7 +2,7 @@ use crate::hir::map::definitions::*;
 use crate::hir::def_id::DefIndex;
 
 use syntax::ast::*;
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::hygiene::ExpnId;
 use syntax::visit;
 use syntax::symbol::{kw, sym};
 use syntax::parse::token::{self, Token};
@@ -90,7 +90,7 @@ impl<'a> DefCollector<'a> {
         }
     }
 
-    pub fn visit_macro_invoc(&mut self, id: NodeId) {
+    fn visit_macro_invoc(&mut self, id: NodeId) {
         self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
     }
 }
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 71bf230e37d..d95637c3b98 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -17,7 +17,7 @@ use std::borrow::Borrow;
 use std::fmt::Write;
 use std::hash::Hash;
 use syntax::ast;
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::hygiene::ExpnId;
 use syntax::symbol::{Symbol, sym, InternedString};
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -111,7 +111,7 @@ pub struct Definitions {
 /// A unique identifier that we can use to lookup a definition
 /// precisely. It combines the index of the definition's parent (if
 /// any) with a `DisambiguatedDefPathData`.
-#[derive(Clone, PartialEq, Debug, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub struct DefKey {
     /// The parent path.
     pub parent: Option<DefIndex>,
@@ -162,13 +162,13 @@ impl DefKey {
 /// between them. This introduces some artificial ordering dependency
 /// but means that if you have, e.g., two impls for the same type in
 /// the same module, they do get distinct `DefId`s.
-#[derive(Clone, PartialEq, Debug, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub struct DisambiguatedDefPathData {
     pub data: DefPathData,
     pub disambiguator: u32
 }
 
-#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct DefPath {
     /// The path leading from the crate root to the item.
     pub data: Vec<DisambiguatedDefPathData>,
@@ -599,7 +599,6 @@ macro_rules! define_global_metadata_kind {
     (pub enum GlobalMetaDataKind {
         $($variant:ident),*
     }) => (
-        #[derive(Clone, Copy, Debug, Hash, RustcEncodable, RustcDecodable)]
         pub enum GlobalMetaDataKind {
             $($variant),*
         }
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 16c4ab7187d..f839087ec02 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::svh::Svh;
 use rustc_index::vec::IndexVec;
 use syntax::ast::{self, Name, NodeId};
 use syntax::source_map::Spanned;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax_pos::{Span, DUMMY_SP};
 
 pub mod blocks;
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 7350f89018b..364a8ace1aa 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -669,6 +669,12 @@ impl WhereClause {
             Some(self.span)
         }
     }
+
+    /// The `WhereClause` under normal circumstances points at either the predicates or the empty
+    /// space where the `where` clause should be. Only of use for diagnostic suggestions.
+    pub fn span_for_predicates_or_empty_place(&self) -> Span {
+        self.span
+    }
 }
 
 /// A single predicate in a where-clause.
@@ -989,6 +995,15 @@ pub enum RangeEnd {
     Excluded,
 }
 
+impl fmt::Display for RangeEnd {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match self {
+            RangeEnd::Included => "..=",
+            RangeEnd::Excluded => "..",
+        })
+    }
+}
+
 #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum PatKind {
     /// Represents a wildcard pattern (i.e., `_`).
@@ -1062,7 +1077,7 @@ impl Mutability {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Hash, HashStable)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum BinOpKind {
     /// The `+` operator (addition).
     Add,
@@ -1196,7 +1211,7 @@ impl Into<ast::BinOpKind> for BinOpKind {
 
 pub type BinOp = Spanned<BinOpKind>;
 
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Hash, HashStable)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub enum UnOp {
     /// The `*` operator (deferencing).
     UnDeref,
@@ -1373,8 +1388,7 @@ impl Body {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
-         RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable, Debug, Copy)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1397,8 +1411,7 @@ impl fmt::Display for GeneratorKind {
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
-         RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable, Debug, Copy)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 6cffaa8a494..b852098d4ce 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1,10 +1,10 @@
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::source_map::{SourceMap, Spanned};
-use syntax::parse::ParseSess;
 use syntax::print::pp::{self, Breaks};
 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
 use syntax::print::pprust::{self, Comments, PrintState};
+use syntax::sess::ParseSess;
 use syntax::symbol::kw;
 use syntax::util::parser::{self, AssocOp, Fixity};
 use syntax_pos::{self, BytePos, FileName};
diff --git a/src/librustc/hir/ptr.rs b/src/librustc/hir/ptr.rs
index 8cdcf5202fc..7ee461a859b 100644
--- a/src/librustc/hir/ptr.rs
+++ b/src/librustc/hir/ptr.rs
@@ -11,7 +11,7 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
 
 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 /// An owned smart pointer.
-#[derive(Hash, PartialEq, Eq)]
+#[derive(PartialEq, Eq)]
 pub struct P<T: ?Sized> {
     ptr: Box<T>
 }
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 3e6b271b834..14d0673ecc0 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -13,7 +13,7 @@ use std::cell::RefCell;
 
 use syntax::ast;
 use syntax::source_map::SourceMap;
-use syntax::ext::hygiene::SyntaxContext;
+use syntax_expand::hygiene::SyntaxContext;
 use syntax::symbol::Symbol;
 use syntax::tokenstream::DelimSpan;
 use syntax_pos::{Span, DUMMY_SP};
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 23a2f115e05..defc3fb25bc 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -59,7 +59,7 @@ impl_stable_hash_for!(enum ::syntax::ast::AsmDialect {
     Intel
 });
 
-impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind {
+impl_stable_hash_for!(enum ::syntax_expand::base::MacroKind {
     Bang,
     Attr,
     Derive,
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index b9474f869ee..49a2c90bdbf 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -468,7 +468,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             ConstValue::Infer(InferConst::Fresh(_)) => {
                 bug!("encountered a fresh const during canonicalization")
             }
-            ConstValue::Infer(InferConst::Canonical(debruijn, _)) => {
+            ConstValue::Bound(debruijn, _) => {
                 if debruijn >= self.binder_index {
                     bug!("escaping bound type during canonicalization")
                 } else {
@@ -700,8 +700,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             let var = self.canonical_var(info, const_var.into());
             self.tcx().mk_const(
                 ty::Const {
-                    val: ConstValue::Infer(InferConst::Canonical(self.binder_index, var.into())),
-                    ty: const_var.ty,
+                    val: ConstValue::Bound(self.binder_index, var.into()),
+                    ty: self.fold_ty(const_var.ty),
                 }
             )
         }
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index 562a463ded8..d833feeeb09 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -33,7 +33,7 @@ use std::ops::Index;
 use syntax::source_map::Span;
 use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, InferConst, Lift, List, Region, TyCtxt};
+use crate::ty::{self, BoundVar, Lift, List, Region, TyCtxt};
 
 mod canonicalizer;
 
@@ -73,7 +73,7 @@ pub struct CanonicalVarValues<'tcx> {
 /// various parts of it with canonical variables. This struct stores
 /// those replaced bits to remember for when we process the query
 /// result.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Debug)]
 pub struct OriginalQueryValues<'tcx> {
     /// Map from the universes that appear in the query to the
     /// universes in the caller context. For the time being, we only
@@ -510,9 +510,7 @@ impl<'tcx> CanonicalVarValues<'tcx> {
                     GenericArgKind::Const(ct) => {
                         tcx.mk_const(ty::Const {
                             ty: ct.ty,
-                            val: ConstValue::Infer(
-                                InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from_u32(i))
-                            ),
+                            val: ConstValue::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
                         }).into()
                     }
                 })
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index 95b6a8bc843..7ad6006012f 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -26,7 +26,7 @@ use crate::traits::TraitEngine;
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, BoundVar, InferConst, Ty, TyCtxt};
+use crate::ty::{self, BoundVar, Ty, TyCtxt};
 use crate::util::captures::Captures;
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
@@ -493,10 +493,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                     }
                 }
                 GenericArgKind::Const(result_value) => {
-                    if let ty::Const {
-                        val: ConstValue::Infer(InferConst::Canonical(debrujin, b)),
-                        ..
-                    } = result_value {
+                    if let ty::Const { val: ConstValue::Bound(debrujin, b), .. } = result_value {
                         // ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
 
                         // We only allow a `ty::INNERMOST` index in substitutions.
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 6f73275d455..f06dbc72cd9 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -53,7 +53,7 @@ pub struct CombineFields<'infcx, 'tcx> {
     pub obligations: PredicateObligations<'tcx>,
 }
 
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, Debug)]
 pub enum RelationDir {
     SubtypeOf, SupertypeOf, EqTo
 }
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 8f2fa3067a2..51ae789b32e 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -200,7 +200,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 {
                     sp = param.span;
                 }
-                (format!("the lifetime {} as defined on", br.name), sp)
+                (format!("the lifetime `{}` as defined on", br.name), sp)
             }
             ty::ReFree(ty::FreeRegion {
                 bound_region: ty::BoundRegion::BrNamed(_, name),
@@ -213,7 +213,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 {
                     sp = param.span;
                 }
-                (format!("the lifetime {} as defined on", name), sp)
+                (format!("the lifetime `{}` as defined on", name), sp)
             }
             ty::ReFree(ref fr) => match fr.bound_region {
                 ty::BrAnon(idx) => (
@@ -221,7 +221,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     self.hir().span(node),
                 ),
                 _ => (
-                    format!("the lifetime {} as defined on", region),
+                    format!("the lifetime `{}` as defined on", region),
                     cm.def_span(self.hir().span(node)),
                 ),
             },
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 9e9220cc3d8..1841bd9ea64 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -252,7 +252,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
                 return ct;
             }
 
-            ConstValue::Infer(ty::InferConst::Canonical(..)) |
+            ConstValue::Bound(..) |
             ConstValue::Placeholder(_) => {
                 bug!("unexpected const {:?}", ct)
             }
diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs
index f11f94c428e..f30f19d4150 100644
--- a/src/librustc/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc/infer/lexical_region_resolve/mod.rs
@@ -19,8 +19,8 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
 };
+use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
-use smallvec::SmallVec;
 use std::fmt;
 use syntax_pos::Span;
 
@@ -304,8 +304,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     }
 
     fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
-        self.iterate_until_fixed_point("Expansion", |constraint| {
-            debug!("expansion: constraint={:?}", constraint);
+        let mut process_constraint = |constraint: &Constraint<'tcx>| {
             let (a_region, b_vid, b_data, retain) = match *constraint {
                 Constraint::RegSubVar(a_region, b_vid) => {
                     let b_data = var_values.value_mut(b_vid);
@@ -331,7 +330,33 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
 
             let changed = self.expand_node(a_region, b_vid, b_data);
             (changed, retain)
-        })
+        };
+
+        // Using bitsets to track the remaining elements is faster than using a
+        // `Vec` by itself (which requires removing elements, which requires
+        // element shuffling, which is slow).
+        let constraints: Vec<_> = self.data.constraints.keys().collect();
+        let mut live_indices: BitSet<usize> = BitSet::new_filled(constraints.len());
+        let mut killed_indices: BitSet<usize> = BitSet::new_empty(constraints.len());
+        let mut changed = true;
+        while changed {
+            changed = false;
+            for index in live_indices.iter() {
+                let constraint = constraints[index];
+                let (edge_changed, retain) = process_constraint(constraint);
+                if edge_changed {
+                    changed = true;
+                }
+                if !retain {
+                    let changed = killed_indices.insert(index);
+                    debug_assert!(changed);
+                }
+            }
+            live_indices.subtract(&killed_indices);
+
+            // We could clear `killed_indices` here, but we don't need to and
+            // it's cheaper not to.
+        }
     }
 
     // This function is very hot in some workloads. There's a single callsite
@@ -360,13 +385,21 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         match *b_data {
             VarValue::Value(cur_region) => {
                 // Identical scopes can show up quite often, if the fixed point
-                // iteration converges slowly, skip them
+                // iteration converges slowly. Skip them. This is purely an
+                // optimization.
                 if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) {
                     if a_scope == cur_scope {
                         return false;
                     }
                 }
 
+                // This is a specialized version of the `lub_concrete_regions`
+                // check below for a common case, here purely as an
+                // optimization.
+                if let ReEmpty = a_region {
+                    return false;
+                }
+
                 let mut lub = self.lub_concrete_regions(a_region, cur_region);
                 if lub == cur_region {
                     return false;
@@ -407,8 +440,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
 
     /// Returns the smallest region `c` such that `a <= c` and `b <= c`.
     fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
-        let tcx = self.tcx();
-
         match (a, b) {
             (&ty::ReClosureBound(..), _)
             | (_, &ty::ReClosureBound(..))
@@ -468,7 +499,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
 
                 // otherwise, we don't know what the free region is,
                 // so we must conservatively say the LUB is static:
-                tcx.lifetimes.re_static
+                self.tcx().lifetimes.re_static
             }
 
             (&ReScope(a_id), &ReScope(b_id)) => {
@@ -476,7 +507,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 // subtype of the region corresponding to an inner
                 // block.
                 let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id);
-                tcx.mk_region(ReScope(lub))
+                self.tcx().mk_region(ReScope(lub))
             }
 
             (&ReEarlyBound(_), &ReEarlyBound(_))
@@ -490,7 +521,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 if a == b {
                     a
                 } else {
-                    tcx.lifetimes.re_static
+                    self.tcx().lifetimes.re_static
                 }
             }
         }
@@ -860,29 +891,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         }
     }
 
-    fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
-    where
-        F: FnMut(&Constraint<'tcx>) -> (bool, bool),
-    {
-        let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect();
-        let mut iteration = 0;
-        let mut changed = true;
-        while changed {
-            changed = false;
-            iteration += 1;
-            debug!("---- {} Iteration {}{}", "#", tag, iteration);
-            constraints.retain(|constraint| {
-                let (edge_changed, retain) = body(constraint);
-                if edge_changed {
-                    debug!("updated due to constraint {:?}", constraint);
-                    changed = true;
-                }
-                retain
-            });
-        }
-        debug!("---- {} Complete after {} iteration(s)", tag, iteration);
-    }
-
     fn bound_is_met(
         &self,
         bound: &VerifyBound<'tcx>,
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index af74d135724..f4ed7dac1f7 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -407,7 +407,7 @@ pub enum RegionVariableOrigin {
     NLL(NLLRegionVariableOrigin),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug)]
 pub enum NLLRegionVariableOrigin {
     /// During NLL region processing, we create variables for free
     /// regions that we encounter in the function signature and
diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs
index 4649f3f9567..64ef0421808 100644
--- a/src/librustc/infer/nll_relate/mod.rs
+++ b/src/librustc/infer/nll_relate/mod.rs
@@ -27,12 +27,12 @@ use crate::ty::error::TypeError;
 use crate::ty::fold::{TypeFoldable, TypeVisitor};
 use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use crate::ty::subst::GenericArg;
-use crate::ty::{self, Ty, TyCtxt, InferConst};
+use crate::ty::{self, Ty, TyCtxt};
 use crate::mir::interpret::ConstValue;
 use rustc_data_structures::fx::FxHashMap;
 use std::fmt::Debug;
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq)]
 pub enum NormalizationStrategy {
     Lazy,
     Eager,
@@ -618,7 +618,7 @@ where
         a: &'tcx ty::Const<'tcx>,
         b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a {
+        if let ty::Const { val: ConstValue::Bound(..), .. } = a {
             // FIXME(const_generics): I'm unsure how this branch should actually be handled,
             // so this is probably not correct.
             self.infcx.super_combine_consts(self, a, b)
@@ -993,7 +993,7 @@ where
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
         debug!("TypeGeneralizer::consts(a={:?})", a);
 
-        if let ty::Const { val: ConstValue::Infer(InferConst::Canonical(_, _)), .. } = a {
+        if let ty::Const { val: ConstValue::Bound(..), .. } = a {
             bug!(
                 "unexpected inference variable encountered in NLL generalization: {:?}",
                 a
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index b4b4d1fe3e1..8c6a7c9a376 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -116,7 +116,7 @@ pub struct RegionConstraintData<'tcx> {
 }
 
 /// Represents a constraint that influences the inference process.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)]
 pub enum Constraint<'tcx> {
     /// A region variable is a subregion of another.
     VarSubVar(RegionVid, RegionVid),
diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs
index 2db18674e2f..7c3a338366c 100644
--- a/src/librustc/infer/resolve.rs
+++ b/src/librustc/infer/resolve.rs
@@ -1,7 +1,7 @@
 use super::{InferCtxt, FixupError, FixupResult, Span};
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::mir::interpret::ConstValue;
-use crate::ty::{self, Ty, Const, TyCtxt, TypeFoldable, InferConst, TypeFlags};
+use crate::ty::{self, Ty, Const, TyCtxt, TypeFoldable, InferConst};
 use crate::ty::fold::{TypeFolder, TypeVisitor};
 
 ///////////////////////////////////////////////////////////////////////////
@@ -29,7 +29,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.has_infer_types() {
+        if !t.has_infer_types() && !t.has_infer_consts() {
             t // micro-optimize -- if there is nothing in this type that this fold affects...
         } else {
             let t = self.infcx.shallow_resolve(t);
@@ -38,7 +38,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
     }
 
     fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
-        if !ct.has_type_flags(TypeFlags::HAS_CT_INFER) {
+        if !ct.has_infer_consts() {
             ct // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
             let ct = self.infcx.shallow_resolve(ct);
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 197ca191a5d..3b0ac9ada8f 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -43,6 +43,7 @@
 #![feature(nll)]
 #![feature(non_exhaustive)]
 #![feature(optin_builtin_traits)]
+#![feature(option_expect_none)]
 #![feature(range_is_empty)]
 #![feature(slice_patterns)]
 #![feature(specialization)]
@@ -56,7 +57,7 @@
 #![feature(test)]
 #![feature(in_band_lifetimes)]
 #![feature(crate_visibility_modifier)]
-#![feature(proc_macro_hygiene)]
+#![cfg_attr(bootstrap, feature(proc_macro_hygiene))]
 #![feature(log_syntax)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 983e3a9922e..4c28f6372fe 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -81,6 +81,12 @@ declare_lint! {
 }
 
 declare_lint! {
+    pub OVERLAPPING_PATTERNS,
+    Warn,
+    "detects overlapping patterns"
+}
+
+declare_lint! {
     pub UNUSED_MACROS,
     Warn,
     "detects macros that were not used"
@@ -423,6 +429,7 @@ declare_lint_pass! {
         DEAD_CODE,
         UNREACHABLE_CODE,
         UNREACHABLE_PATTERNS,
+        OVERLAPPING_PATTERNS,
         UNUSED_MACROS,
         WARNINGS,
         UNUSED_FEATURES,
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 28afe9730a0..8ed06cbdc76 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -12,6 +12,7 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHa
 use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate;
+use syntax::print::pprust;
 use syntax::source_map::MultiSpan;
 use syntax::symbol::{Symbol, sym};
 
@@ -201,11 +202,7 @@ impl<'a> LintLevelsBuilder<'a> {
             let meta = unwrap_or!(attr.meta(), continue);
             attr::mark_used(attr);
 
-            let mut metas = if let Some(metas) = meta.meta_item_list() {
-                metas
-            } else {
-                continue;
-            };
+            let mut metas = unwrap_or!(meta.meta_item_list(), continue);
 
             if metas.is_empty() {
                 // FIXME (#55112): issue unused-attributes lint for `#[level()]`
@@ -285,7 +282,7 @@ impl<'a> LintLevelsBuilder<'a> {
                             tool_ident.span,
                             E0710,
                             "an unknown tool name found in scoped lint: `{}`",
-                            meta_item.path
+                            pprust::path_to_string(&meta_item.path),
                         );
                         continue;
                     }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index b31efc24e52..7443cca822a 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -39,7 +39,7 @@ use syntax::ast;
 use syntax::source_map::{MultiSpan, ExpnKind, DesugaringKind};
 use syntax::early_buffered_lints::BufferedEarlyLintId;
 use syntax::edition::Edition;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 065959ed09f..ec1e32988a6 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -32,6 +32,12 @@ pub struct CrateSource {
     pub rmeta: Option<(PathBuf, PathKind)>,
 }
 
+impl CrateSource {
+    pub fn paths(&self) -> impl Iterator<Item = &PathBuf> {
+        self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0)
+    }
+}
+
 #[derive(RustcEncodable, RustcDecodable, Copy, Clone,
          Ord, PartialOrd, Eq, PartialEq, Debug, HashStable)]
 pub enum DepKind {
@@ -111,7 +117,7 @@ pub struct NativeLibrary {
     pub wasm_import_module: Option<Symbol>,
 }
 
-#[derive(Clone, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
 pub struct ForeignModule {
     pub foreign_items: Vec<DefId>,
     pub def_id: DefId,
@@ -208,7 +214,6 @@ pub trait CrateStore {
     fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
     fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
-    fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
     fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
     fn postorder_cnums_untracked(&self) -> Vec<CrateNum>;
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 8f79b8aa295..cbf336fdbe2 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -102,7 +102,7 @@ pub struct Upvar {
 }
 
 // different kinds of pointers:
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub enum PointerKind<'tcx> {
     /// `Box<T>`
     Unique,
@@ -116,7 +116,7 @@ pub enum PointerKind<'tcx> {
 
 // We use the term "interior" to mean "something reachable from the
 // base without a pointer dereference", e.g., a field
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq)]
 pub enum InteriorKind {
     InteriorField(FieldIndex),
     InteriorElement(InteriorOffsetKind),
@@ -139,13 +139,13 @@ impl Hash for FieldIndex {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq)]
 pub enum InteriorOffsetKind {
     Index,   // e.g., `array_expr[index_expr]`
     Pattern, // e.g., `fn foo([_, a, _, _]: [A; 4]) { ... }`
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Debug)]
 pub enum MutabilityCategory {
     McImmutable, // Immutable.
     McDeclared,  // Directly declared as mutable.
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 31d250fa082..a122d84a5aa 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -708,15 +708,22 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
                             let (name, reg) = Region::early(&self.tcx.hir(), &mut index, &param);
+                            let def_id = if let Region::EarlyBound(_ ,def_id , _) = reg {
+                                def_id
+                            } else {
+                                bug!();
+                            };
                             if let hir::ParamName::Plain(param_name) = name {
                                 if param_name.name == kw::UnderscoreLifetime {
                                     // Pick the elided lifetime "definition" if one exists
                                     // and use it to make an elision scope.
+                                    self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many);
                                     elision = Some(reg);
                                 } else {
                                     lifetimes.insert(name, reg);
                                 }
                             } else {
+                                self.lifetime_uses.insert(def_id.clone(), LifetimeUseSet::Many);
                                 lifetimes.insert(name, reg);
                             }
                         }
@@ -1615,7 +1622,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                         _ => None,
                     } {
                         debug!("id = {:?} span = {:?} name = {:?}", id, span, name);
-
                         if name.name == kw::UnderscoreLifetime {
                             continue;
                         }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 302c11f309d..e65f17c7949 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -25,7 +25,7 @@ use crate::util::nodemap::{FxHashSet, FxHashMap};
 use std::mem::replace;
 use std::cmp::Ordering;
 
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)]
+#[derive(PartialEq, Clone, Copy, Debug)]
 pub enum StabilityLevel {
     Unstable,
     Stable,
@@ -905,11 +905,10 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
             // Warn if the user has enabled an already-stable lang feature.
             unnecessary_stable_feature_lint(tcx, span, feature, since);
         }
-        if lang_features.contains(&feature) {
+        if !lang_features.insert(feature) {
             // Warn if the user enables a lang feature multiple times.
             duplicate_feature_err(tcx.sess, span, feature);
         }
-        lang_features.insert(feature);
     }
 
     let declared_lib_features = &tcx.features().declared_lib_features;
diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 15e6cb6bcab..796d293e2c6 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -245,6 +245,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// as a slice.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
+    /// on `InterpCx` instead.
     #[inline]
     pub fn get_bytes(
         &self,
@@ -275,6 +277,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// so be sure to actually put data there!
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
+    /// on `InterpCx` instead.
     pub fn get_bytes_mut(
         &mut self,
         cx: &impl HasDataLayout,
@@ -297,6 +301,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
 impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached
     /// before a `0` is found.
+    ///
+    /// Most likely, you want to call `Memory::read_c_str` instead of this method.
     pub fn read_c_str(
         &self,
         cx: &impl HasDataLayout,
@@ -342,33 +348,22 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Writes `src` to the memory starting at `ptr.offset`.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to call `Memory::write_bytes` instead of this method.
     pub fn write_bytes(
         &mut self,
         cx: &impl HasDataLayout,
         ptr: Pointer<Tag>,
-        src: &[u8],
+        src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>,
     ) -> InterpResult<'tcx>
     {
+        let mut src = src.into_iter();
         let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?;
-        bytes.clone_from_slice(src);
-        Ok(())
-    }
-
-    /// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
-    ///
-    /// It is the caller's responsibility to check bounds and alignment beforehand.
-    pub fn write_repeat(
-        &mut self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        val: u8,
-        count: Size
-    ) -> InterpResult<'tcx>
-    {
-        let bytes = self.get_bytes_mut(cx, ptr, count)?;
-        for b in bytes {
-            *b = val;
+        // `zip` would stop when the first iterator ends; we want to definitely
+        // cover all of `bytes`.
+        for dest in bytes {
+            *dest = src.next().expect("iterator was shorter than it said it would be");
         }
+        src.next().expect_none("iterator was longer than it said it would be");
         Ok(())
     }
 
@@ -380,6 +375,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     ///   pointers being valid for ZSTs.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
     pub fn read_scalar(
         &self,
         cx: &impl HasDataLayout,
@@ -418,6 +414,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Reads a pointer-sized scalar.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
     pub fn read_ptr_sized(
         &self,
         cx: &impl HasDataLayout,
@@ -435,6 +432,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     ///   pointers being valid for ZSTs.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
     pub fn write_scalar(
         &mut self,
         cx: &impl HasDataLayout,
@@ -477,6 +475,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Writes a pointer-sized scalar.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
+    /// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
     pub fn write_ptr_sized(
         &mut self,
         cx: &impl HasDataLayout,
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index 71967b513a0..d918b9ee673 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -363,6 +363,8 @@ pub enum UndefinedBehaviorInfo {
     UbExperimental(String),
     /// Unreachable code was executed.
     Unreachable,
+    /// An enum discriminant was set to a value which was outside the range of valid values.
+    InvalidDiscriminant(ScalarMaybeUndef),
 }
 
 impl fmt::Debug for UndefinedBehaviorInfo {
@@ -373,6 +375,8 @@ impl fmt::Debug for UndefinedBehaviorInfo {
                 write!(f, "{}", msg),
             Unreachable =>
                 write!(f, "entered unreachable code"),
+            InvalidDiscriminant(val) =>
+                write!(f, "encountered invalid enum discriminant {}", val),
         }
     }
 }
@@ -389,10 +393,6 @@ pub enum UnsupportedOpInfo<'tcx> {
     /// Free-form case. Only for errors that are never caught!
     Unsupported(String),
 
-    /// FIXME(#64506) Error used to work around accessing projections of
-    /// uninhabited types.
-    UninhabitedValue,
-
     // -- Everything below is not categorized yet --
     FunctionAbiMismatch(Abi, Abi),
     FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
@@ -404,7 +404,6 @@ pub enum UnsupportedOpInfo<'tcx> {
     InvalidMemoryAccess,
     InvalidFunctionPointer,
     InvalidBool,
-    InvalidDiscriminant(ScalarMaybeUndef),
     PointerOutOfBounds {
         ptr: Pointer,
         msg: CheckInAllocMsg,
@@ -489,8 +488,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
                 write!(f, "incorrect alloc info: expected size {} and align {}, \
                            got size {} and align {}",
                     size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
-            InvalidDiscriminant(val) =>
-                write!(f, "encountered invalid enum discriminant {}", val),
             InvalidMemoryAccess =>
                 write!(f, "tried to access memory through an invalid pointer"),
             DanglingPointerDeref =>
@@ -556,8 +553,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
                     not a power of two"),
             Unsupported(ref msg) =>
                 write!(f, "{}", msg),
-            UninhabitedValue =>
-                write!(f, "tried to use an uninhabited value"),
         }
     }
 }
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index bbf00cc23ae..ac16b8b884c 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -5,11 +5,12 @@ use rustc_apfloat::{Float, ieee::{Double, Single}};
 use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef};
 use crate::ty::PlaceholderConst;
 use crate::hir::def_id::DefId;
+use crate::ty::{BoundVar, DebruijnIndex};
 
 use super::{InterpResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
 
 /// Represents the result of a raw const operation, pre-validation.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash, HashStable)]
+#[derive(Clone, HashStable)]
 pub struct RawConst<'tcx> {
     // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
     // (so you can use `AllocMap::unwrap_memory`).
@@ -28,6 +29,9 @@ pub enum ConstValue<'tcx> {
     /// Infer the value of the const.
     Infer(InferConst<'tcx>),
 
+    /// Bound const variable, used only when preparing a trait query.
+    Bound(DebruijnIndex, BoundVar),
+
     /// A placeholder const - universally quantified higher-ranked const.
     Placeholder(PlaceholderConst),
 
@@ -66,8 +70,9 @@ impl<'tcx> ConstValue<'tcx> {
         match *self {
             ConstValue::Param(_) |
             ConstValue::Infer(_) |
+            ConstValue::Bound(..) |
             ConstValue::Placeholder(_) |
-            ConstValue::ByRef{ .. } |
+            ConstValue::ByRef { .. } |
             ConstValue::Unevaluated(..) |
             ConstValue::Slice { .. } => None,
             ConstValue::Scalar(val) => Some(val),
@@ -487,7 +492,7 @@ impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
     }
 }
 
-#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum ScalarMaybeUndef<Tag = (), Id = AllocId> {
     Scalar(Scalar<Tag, Id>),
     Undef,
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9ac1465cb0b..ccf64c51e13 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -468,7 +468,7 @@ impl<T: Decodable> rustc_serialize::UseSpecializedDecodable for ClearCrossCrate<
 /// Grouped information about the source code origin of a MIR entity.
 /// Intended to be inspected by diagnostics and debuginfo.
 /// Most passes can work with it as a whole, within a single function.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct SourceInfo {
     /// The source span for the AST pertaining to this MIR entity.
     pub span: Span,
@@ -608,7 +608,7 @@ pub enum LocalKind {
     ReturnPointer,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub struct VarBindingForm<'tcx> {
     /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
     pub binding_mode: ty::BindingMode,
@@ -630,7 +630,7 @@ pub struct VarBindingForm<'tcx> {
     pub pat_span: Span,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum BindingForm<'tcx> {
     /// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
     Var(VarBindingForm<'tcx>),
@@ -641,7 +641,7 @@ pub enum BindingForm<'tcx> {
 }
 
 /// Represents what type of implicit self a function has, if any.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub enum ImplicitSelfKind {
     /// Represents a `fn x(self);`.
     Imm,
@@ -2392,7 +2392,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// this does not necessarily mean that they are "==" in Rust -- in
 /// particular one must be wary of `NaN`!
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct Constant<'tcx> {
     pub span: Span,
 
@@ -2438,7 +2438,7 @@ pub struct Constant<'tcx> {
 /// The first will lead to the constraint `w: &'1 str` (for some
 /// inferred region `'1`). The second will lead to the constraint `w:
 /// &'static str`.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UserTypeProjections {
     pub(crate) contents: Vec<(UserTypeProjection, Span)>,
 }
@@ -2515,7 +2515,7 @@ impl<'tcx> UserTypeProjections {
 /// * `let (x, _): T = ...` -- here, the `projs` vector would contain
 ///   `field[0]` (aka `.0`), indicating that the type of `s` is
 ///   determined by finding the type of the `.0` field from `T`.
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UserTypeProjection {
     pub base: UserTypeAnnotationIndex,
     pub projs: Vec<ProjectionKind>,
@@ -2724,7 +2724,7 @@ impl Location {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum UnsafetyViolationKind {
     General,
     /// Permitted both in `const fn`s and regular `fn`s.
@@ -2733,7 +2733,7 @@ pub enum UnsafetyViolationKind {
     BorrowPacked(hir::HirId),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UnsafetyViolation {
     pub source_info: SourceInfo,
     pub description: InternedString,
@@ -2741,7 +2741,7 @@ pub struct UnsafetyViolation {
     pub kind: UnsafetyViolationKind,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
 pub struct UnsafetyCheckResult {
     /// Violations that are propagated *upwards* from this function.
     pub violations: Lrc<[UnsafetyViolation]>,
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index 265ac975ed7..eeb997d75ca 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -15,7 +15,7 @@ use std::fmt;
 use std::hash::Hash;
 
 /// Describes how a monomorphization will be instantiated in object files.
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
+#[derive(PartialEq)]
 pub enum InstantiationMode {
     /// There will be exactly one instance of the given MonoItem. It will have
     /// external linkage so that it can be linked to from other codegen units.
@@ -251,7 +251,7 @@ pub struct CodegenUnit<'tcx> {
     size_estimate: Option<usize>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
 pub enum Linkage {
     External,
     AvailableExternally,
@@ -280,7 +280,7 @@ impl_stable_hash_for!(enum self::Linkage {
     Common
 });
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub enum Visibility {
     Default,
     Hidden,
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index edc7922f46e..427540d7275 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -158,22 +158,7 @@ macro_rules! make_mir_visitor {
                 self.super_place_base(base, context, location);
             }
 
-            fn visit_projection(&mut self,
-                                base: & $($mutability)? PlaceBase<'tcx>,
-                                projection: & $($mutability)? [PlaceElem<'tcx>],
-                                context: PlaceContext,
-                                location: Location) {
-                self.super_projection(base, projection, context, location);
-            }
-
-            fn visit_projection_elem(&mut self,
-                                     base: & $($mutability)? PlaceBase<'tcx>,
-                                     proj_base: & $($mutability)? [PlaceElem<'tcx>],
-                                     elem: & $($mutability)? PlaceElem<'tcx>,
-                                     context: PlaceContext,
-                                     location: Location) {
-                self.super_projection_elem(base, proj_base, elem, context, location);
-            }
+            visit_place_fns!($($mutability)?);
 
             fn visit_constant(&mut self,
                               constant: & $($mutability)? Constant<'tcx>,
@@ -681,28 +666,6 @@ macro_rules! make_mir_visitor {
                 );
             }
 
-            fn super_place(&mut self,
-                            place: & $($mutability)? Place<'tcx>,
-                            context: PlaceContext,
-                            location: Location) {
-                let mut context = context;
-
-                if !place.projection.is_empty() {
-                    context = if context.is_mutating_use() {
-                        PlaceContext::MutatingUse(MutatingUseContext::Projection)
-                    } else {
-                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
-                    };
-                }
-
-                self.visit_place_base(& $($mutability)? place.base, context, location);
-
-                self.visit_projection(& $($mutability)? place.base,
-                                      & $($mutability)? place.projection,
-                                      context,
-                                      location);
-            }
-
             fn super_place_base(&mut self,
                                 place_base: & $($mutability)? PlaceBase<'tcx>,
                                 context: PlaceContext,
@@ -717,45 +680,6 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            fn super_projection(&mut self,
-                                base: & $($mutability)? PlaceBase<'tcx>,
-                                projection: & $($mutability)? [PlaceElem<'tcx>],
-                                context: PlaceContext,
-                                location: Location) {
-                let mut cursor = projection;
-                while let [proj_base @ .., elem] = cursor {
-                    cursor = proj_base;
-                    self.visit_projection_elem(base, cursor, elem, context, location);
-                }
-            }
-
-            fn super_projection_elem(&mut self,
-                                     _base: & $($mutability)? PlaceBase<'tcx>,
-                                     _proj_base: & $($mutability)? [PlaceElem<'tcx>],
-                                     elem: & $($mutability)? PlaceElem<'tcx>,
-                                     _context: PlaceContext,
-                                     location: Location) {
-                match elem {
-                    ProjectionElem::Field(_field, ty) => {
-                        self.visit_ty(ty, TyContext::Location(location));
-                    }
-                    ProjectionElem::Index(local) => {
-                        self.visit_local(
-                            local,
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
-                            location
-                        );
-                    }
-                    ProjectionElem::Deref |
-                    ProjectionElem::Subslice { from: _, to: _ } |
-                    ProjectionElem::ConstantIndex { offset: _,
-                                                    min_length: _,
-                                                    from_end: _ } |
-                    ProjectionElem::Downcast(_, _) => {
-                    }
-                }
-            }
-
             fn super_local_decl(&mut self,
                                 local: Local,
                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
@@ -858,6 +782,141 @@ macro_rules! make_mir_visitor {
     }
 }
 
+macro_rules! visit_place_fns {
+    (mut) => (
+        fn super_place(
+            &mut self,
+            place: &mut Place<'tcx>,
+            context: PlaceContext,
+            location: Location,
+        ) {
+            self.visit_place_base(&mut place.base, context, location);
+
+            if let Some(new_projection) = self.process_projection(&place.projection) {
+                place.projection = new_projection;
+            }
+        }
+
+        fn process_projection(
+            &mut self,
+            projection: &'a [PlaceElem<'tcx>],
+        ) -> Option<Box<[PlaceElem<'tcx>]>> {
+            let mut projection = Cow::Borrowed(projection);
+
+            for i in 0..projection.len() {
+                if let Some(elem) = projection.get(i) {
+                    if let Some(elem) = self.process_projection_elem(elem) {
+                        let vec = projection.to_mut();
+                        vec[i] = elem;
+                    }
+                }
+            }
+
+            match projection {
+                Cow::Borrowed(_) => None,
+                Cow::Owned(vec) => Some(vec.into_boxed_slice()),
+            }
+        }
+
+        fn process_projection_elem(
+            &mut self,
+            _elem: &PlaceElem<'tcx>,
+        ) -> Option<PlaceElem<'tcx>> {
+            None
+        }
+    );
+
+    () => (
+        fn visit_projection(
+            &mut self,
+            base: &PlaceBase<'tcx>,
+            projection: &[PlaceElem<'tcx>],
+            context: PlaceContext,
+            location: Location,
+        ) {
+            self.super_projection(base, projection, context, location);
+        }
+
+        fn visit_projection_elem(
+            &mut self,
+            base: &PlaceBase<'tcx>,
+            proj_base: &[PlaceElem<'tcx>],
+            elem: &PlaceElem<'tcx>,
+            context: PlaceContext,
+            location: Location,
+        ) {
+            self.super_projection_elem(base, proj_base, elem, context, location);
+        }
+
+        fn super_place(
+            &mut self,
+            place: &Place<'tcx>,
+            context: PlaceContext,
+            location: Location,
+        ) {
+            let mut context = context;
+
+            if !place.projection.is_empty() {
+                context = if context.is_mutating_use() {
+                    PlaceContext::MutatingUse(MutatingUseContext::Projection)
+                } else {
+                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
+                };
+            }
+
+            self.visit_place_base(&place.base, context, location);
+
+            self.visit_projection(&place.base,
+                                  &place.projection,
+                                  context,
+                                  location);
+        }
+
+        fn super_projection(
+            &mut self,
+            base: &PlaceBase<'tcx>,
+            projection: &[PlaceElem<'tcx>],
+            context: PlaceContext,
+            location: Location,
+        ) {
+            let mut cursor = projection;
+            while let [proj_base @ .., elem] = cursor {
+                cursor = proj_base;
+                self.visit_projection_elem(base, cursor, elem, context, location);
+            }
+        }
+
+        fn super_projection_elem(
+            &mut self,
+            _base: &PlaceBase<'tcx>,
+            _proj_base: &[PlaceElem<'tcx>],
+            elem: &PlaceElem<'tcx>,
+            _context: PlaceContext,
+            location: Location,
+        ) {
+            match elem {
+                ProjectionElem::Field(_field, ty) => {
+                    self.visit_ty(ty, TyContext::Location(location));
+                }
+                ProjectionElem::Index(local) => {
+                    self.visit_local(
+                        local,
+                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
+                        location
+                    );
+                }
+                ProjectionElem::Deref |
+                ProjectionElem::Subslice { from: _, to: _ } |
+                ProjectionElem::ConstantIndex { offset: _,
+                                                min_length: _,
+                                                from_end: _ } |
+                ProjectionElem::Downcast(_, _) => {
+                }
+            }
+        }
+    );
+}
+
 make_mir_visitor!(Visitor,);
 make_mir_visitor!(MutVisitor,mut);
 
@@ -888,7 +947,7 @@ impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
 
 /// Extra information passed to `visit_ty` and friends to give context
 /// about where the type etc appears.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Debug)]
 pub enum TyContext {
     LocalDecl {
         /// The index of the local variable we are visiting.
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index c95652f274e..2c407a24493 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -61,7 +61,7 @@ rustc_queries! {
         /// predicate gets in the way of some checks, which are intended
         /// to operate over only the actual where-clauses written by the
         /// user.)
-        query predicates_of(key: DefId) -> &'tcx ty::GenericPredicates<'tcx> {
+        query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
             cache_on_disk_if { key.is_local() }
         }
 
@@ -184,12 +184,10 @@ rustc_queries! {
         /// predicates (where-clauses) directly defined on it. This is
         /// equal to the `explicit_predicates_of` predicates plus the
         /// `inferred_outlives_of` predicates.
-        query predicates_defined_on(_: DefId)
-            -> &'tcx ty::GenericPredicates<'tcx> {}
+        query predicates_defined_on(_: DefId) -> ty::GenericPredicates<'tcx> {}
 
         /// Returns the predicates written explicitly by the user.
-        query explicit_predicates_of(_: DefId)
-            -> &'tcx ty::GenericPredicates<'tcx> {}
+        query explicit_predicates_of(_: DefId) -> ty::GenericPredicates<'tcx> {}
 
         /// Returns the inferred outlives predicates (e.g., for `struct
         /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
@@ -201,14 +199,13 @@ rustc_queries! {
         /// evaluate them even during type conversion, often before the
         /// full predicates are available (note that supertraits have
         /// additional acyclicity requirements).
-        query super_predicates_of(key: DefId) -> &'tcx ty::GenericPredicates<'tcx> {
+        query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
             desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) }
         }
 
         /// To avoid cycles within the predicates of a single item we compute
         /// per-type-parameter predicates for resolving `T::AssocTy`.
-        query type_param_predicates(key: (DefId, DefId))
-            -> &'tcx ty::GenericPredicates<'tcx> {
+        query type_param_predicates(key: (DefId, DefId)) -> ty::GenericPredicates<'tcx> {
             no_force
             desc { |tcx| "computing the bounds for type parameter `{}`", {
                 let id = tcx.hir().as_local_hir_id(key.1).unwrap();
@@ -231,6 +228,12 @@ rustc_queries! {
             cycle_delay_bug
         }
 
+        query trivial_dropck_outlives(ty: Ty<'tcx>) -> bool {
+            anon
+            no_force
+            desc { "checking if `{:?}` has trivial dropck", ty }
+        }
+
         query adt_dtorck_constraint(
             _: DefId
         ) -> Result<DtorckConstraint<'tcx>, NoSolution> {}
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 0facf30b627..33b9ddaa622 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -7,20 +7,16 @@ use crate::session::{early_error, early_warn, Session};
 use crate::session::search_paths::SearchPath;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
 
 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
 use rustc_target::spec::{Target, TargetTriple};
 
 use syntax;
-use syntax::ast::{self, IntTy, UintTy, MetaItemKind};
+use syntax::ast::{self, IntTy, UintTy};
 use syntax::source_map::{FileName, FilePathMapping};
 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
-use syntax::parse::{ParseSess, new_parser_from_source_str};
-use syntax::parse::token;
 use syntax::symbol::{sym, Symbol};
 use syntax::feature_gate::UnstableFeatures;
-use syntax::source_map::SourceMap;
 
 use errors::emitter::HumanReadableErrorType;
 use errors::{ColorConfig, FatalError, Handler};
@@ -66,7 +62,7 @@ impl_stable_hash_via_hash!(OptLevel);
 
 /// This is what the `LtoCli` values get mapped to after resolving defaults and
 /// and taking other command line options into account.
-#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+#[derive(Clone, PartialEq)]
 pub enum Lto {
     /// Don't do any LTO whatsoever
     No,
@@ -300,10 +296,10 @@ impl OutputTypes {
 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
 /// would break dependency tracking for command-line arguments.
-#[derive(Clone, Hash)]
+#[derive(Clone)]
 pub struct Externs(BTreeMap<String, ExternEntry>);
 
-#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
+#[derive(Clone, Debug, Default)]
 pub struct ExternEntry {
     pub locations: BTreeSet<Option<String>>,
     pub is_private_dep: bool
@@ -463,7 +459,7 @@ pub enum PrintRequest {
     NativeStaticLibs,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone)]
 pub enum BorrowckMode {
     Mir,
     Migrate,
@@ -1153,7 +1149,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select target processor (`rustc --print target-cpus` for details)"),
     target_feature: String = (String::new(), parse_string, [TRACKED],
-        "target specific attributes (`rustc --print target-features` for details)"),
+        "target specific attributes. (`rustc --print target-features` for details). \
+        This feature is unsafe."),
     passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
         "a list of extra LLVM passes to run (space separated)"),
     llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
@@ -1853,58 +1850,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
     opts
 }
 
-struct NullEmitter;
-
-impl errors::emitter::Emitter for NullEmitter {
-    fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {}
-}
-
-// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
-pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
-    syntax::with_default_globals(move || {
-        let cfg = cfgspecs.into_iter().map(|s| {
-
-            let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-            let handler = Handler::with_emitter(false, None, Box::new(NullEmitter));
-            let sess = ParseSess::with_span_handler(handler, cm);
-            let filename = FileName::cfg_spec_source_code(&s);
-            let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
-
-            macro_rules! error {($reason: expr) => {
-                early_error(ErrorOutputType::default(),
-                            &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
-            }}
-
-            match &mut parser.parse_meta_item() {
-                Ok(meta_item) if parser.token == token::Eof => {
-                    if meta_item.path.segments.len() != 1 {
-                        error!("argument key must be an identifier");
-                    }
-                    match &meta_item.kind {
-                        MetaItemKind::List(..) => {
-                            error!(r#"expected `key` or `key="value"`"#);
-                        }
-                        MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-                            error!("argument value must be a string");
-                        }
-                        MetaItemKind::NameValue(..) | MetaItemKind::Word => {
-                            let ident = meta_item.ident().expect("multi-segment cfg key");
-                            return (ident.name, meta_item.value_str());
-                        }
-                    }
-                }
-                Ok(..) => {}
-                Err(err) => err.cancel(),
-            }
-
-            error!(r#"expected `key` or `key="value"`"#);
-        }).collect::<ast::CrateConfig>();
-        cfg.into_iter().map(|(a, b)| {
-            (a.to_string(), b.map(|b| b.to_string()))
-        }).collect()
-    })
-}
-
 pub fn get_cmd_lint_options(matches: &getopts::Matches,
                             error_format: ErrorOutputType)
                             -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
@@ -2038,11 +1983,7 @@ pub fn parse_error_format(
     return error_format;
 }
 
-pub fn build_session_options_and_crate_config(
-    matches: &getopts::Matches,
-) -> (Options, FxHashSet<(String, Option<String>)>) {
-    let color = parse_color(matches);
-
+fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
     let edition = match matches.opt_str("edition") {
         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
             early_error(
@@ -2069,19 +2010,14 @@ pub fn build_session_options_and_crate_config(
         )
     }
 
-    let (json_rendered, json_artifact_notifications) = parse_json(matches);
-
-    let error_format = parse_error_format(matches, color, json_rendered);
-
-    let unparsed_crate_types = matches.opt_strs("crate-type");
-    let crate_types = parse_crate_types_from_list(unparsed_crate_types)
-        .unwrap_or_else(|e| early_error(error_format, &e[..]));
-
-
-    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
-    let mut debugging_opts = build_debugging_options(matches, error_format);
+    edition
+}
 
+fn check_debug_option_stability(
+    debugging_opts: &DebuggingOptions,
+    error_format: ErrorOutputType,
+    json_rendered: HumanReadableErrorType,
+) {
     if !debugging_opts.unstable_options {
         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
             early_error(
@@ -2097,7 +2033,13 @@ pub fn build_session_options_and_crate_config(
             );
         }
     }
+}
 
+fn parse_output_types(
+    debugging_opts: &DebuggingOptions,
+    matches: &getopts::Matches,
+    error_format: ErrorOutputType,
+) -> OutputTypes {
     let mut output_types = BTreeMap::new();
     if !debugging_opts.parse_only {
         for list in matches.opt_strs("emit") {
@@ -2122,14 +2064,19 @@ pub fn build_session_options_and_crate_config(
     if output_types.is_empty() {
         output_types.insert(OutputType::Exe, None);
     }
+    OutputTypes(output_types)
+}
 
-    let mut cg = build_codegen_options(matches, error_format);
-    let mut codegen_units = cg.codegen_units;
+fn should_override_cgus_and_disable_thinlto(
+    output_types: &OutputTypes,
+    matches: &getopts::Matches,
+    error_format: ErrorOutputType,
+    mut codegen_units: Option<usize>,
+) -> (bool, Option<usize>) {
     let mut disable_thinlto = false;
-
     // Issue #30063: if user requests LLVM-related output to one
     // particular path, disable codegen-units.
-    let incompatible: Vec<_> = output_types
+    let incompatible: Vec<_> = output_types.0
         .iter()
         .map(|ot_path| ot_path.0)
         .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
@@ -2161,29 +2108,39 @@ pub fn build_session_options_and_crate_config(
         }
     }
 
-    if debugging_opts.threads == 0 {
+    if codegen_units == Some(0) {
         early_error(
             error_format,
-            "value for threads must be a positive non-zero integer",
+            "value for codegen units must be a positive non-zero integer",
         );
     }
 
-    if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
+    (disable_thinlto, codegen_units)
+}
+
+fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
+    if debugging_opts.threads == 0 {
         early_error(
             error_format,
-            "optimization fuel is incompatible with multiple threads",
+            "value for threads must be a positive non-zero integer",
         );
     }
 
-    if codegen_units == Some(0) {
+    if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
         early_error(
             error_format,
-            "value for codegen units must be a positive non-zero integer",
+            "optimization fuel is incompatible with multiple threads",
         );
     }
+}
 
-    let incremental = match (&debugging_opts.incremental, &cg.incremental) {
-        (&Some(ref path1), &Some(ref path2)) => {
+fn select_incremental_path(
+    debugging_opts: &DebuggingOptions,
+    cg: &CodegenOptions,
+    error_format: ErrorOutputType,
+) -> Option<PathBuf> {
+    match (&debugging_opts.incremental, &cg.incremental) {
+        (Some(path1), Some(path2)) => {
             if path1 != path2 {
                 early_error(
                     error_format,
@@ -2197,25 +2154,19 @@ pub fn build_session_options_and_crate_config(
                 Some(path1)
             }
         }
-        (&Some(ref path), &None) => Some(path),
-        (&None, &Some(ref path)) => Some(path),
-        (&None, &None) => None,
-    }.map(|m| PathBuf::from(m));
-
-    if debugging_opts.profile && incremental.is_some() {
-        early_error(
-            error_format,
-            "can't instrument with gcov profiling when compiling incrementally",
-        );
-    }
-
-    if cg.profile_generate.enabled() && cg.profile_use.is_some() {
-        early_error(
-            error_format,
-            "options `-C profile-generate` and `-C profile-use` are exclusive",
-        );
-    }
+        (Some(path), None) => Some(path),
+        (None, Some(path)) => Some(path),
+        (None, None) => None,
+    }.map(|m| PathBuf::from(m))
+}
 
+fn collect_print_requests(
+    cg: &mut CodegenOptions,
+    dopts: &mut DebuggingOptions,
+    matches: &getopts::Matches,
+    is_unstable_enabled: bool,
+    error_format: ErrorOutputType,
+) -> Vec<PrintRequest> {
     let mut prints = Vec::<PrintRequest>::new();
     if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
         prints.push(PrintRequest::TargetCPUs);
@@ -2233,72 +2184,105 @@ pub fn build_session_options_and_crate_config(
         prints.push(PrintRequest::CodeModels);
         cg.code_model = None;
     }
-    if debugging_opts
+    if dopts
         .tls_model
         .as_ref()
         .map_or(false, |s| s == "help")
     {
         prints.push(PrintRequest::TlsModels);
-        debugging_opts.tls_model = None;
+        dopts.tls_model = None;
     }
 
-    let cg = cg;
+    prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
+        "crate-name" => PrintRequest::CrateName,
+        "file-names" => PrintRequest::FileNames,
+        "sysroot" => PrintRequest::Sysroot,
+        "cfg" => PrintRequest::Cfg,
+        "target-list" => PrintRequest::TargetList,
+        "target-cpus" => PrintRequest::TargetCPUs,
+        "target-features" => PrintRequest::TargetFeatures,
+        "relocation-models" => PrintRequest::RelocationModels,
+        "code-models" => PrintRequest::CodeModels,
+        "tls-models" => PrintRequest::TlsModels,
+        "native-static-libs" => PrintRequest::NativeStaticLibs,
+        "target-spec-json" => {
+            if is_unstable_enabled {
+                PrintRequest::TargetSpec
+            } else {
+                early_error(
+                    error_format,
+                    "the `-Z unstable-options` flag must also be passed to \
+                     enable the target-spec-json print option",
+                );
+            }
+        }
+        req => early_error(error_format, &format!("unknown print request `{}`", req)),
+    }));
 
-    let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
-    let target_triple = if let Some(target) = matches.opt_str("target") {
-        if target.ends_with(".json") {
+    prints
+}
+
+fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
+    match matches.opt_str("target") {
+        Some(target) if target.ends_with(".json") => {
             let path = Path::new(&target);
             TargetTriple::from_path(&path).unwrap_or_else(|_|
                 early_error(error_format, &format!("target file {:?} does not exist", path)))
+        }
+        Some(target) => TargetTriple::TargetTriple(target),
+        _ => TargetTriple::from_triple(host_triple()),
+    }
+}
+
+fn parse_opt_level(
+    matches: &getopts::Matches,
+    cg: &CodegenOptions,
+    error_format: ErrorOutputType,
+) -> OptLevel {
+    // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
+    // to use them interchangeably. However, because they're technically different flags,
+    // we need to work out manually which should take precedence if both are supplied (i.e.
+    // the rightmost flag). We do this by finding the (rightmost) position of both flags and
+    // comparing them. Note that if a flag is not found, its position will be `None`, which
+    // always compared less than `Some(_)`.
+    let max_o = matches.opt_positions("O").into_iter().max();
+    let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
+        if let Some("opt-level") = s.splitn(2, '=').next() {
+            Some(i)
         } else {
-            TargetTriple::TargetTriple(target)
+            None
         }
+    }).max();
+    if max_o > max_c {
+        OptLevel::Default
     } else {
-        TargetTriple::from_triple(host_triple())
-    };
-    let opt_level = {
-        // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
-        // to use them interchangeably. However, because they're technically different flags,
-        // we need to work out manually which should take precedence if both are supplied (i.e.
-        // the rightmost flag). We do this by finding the (rightmost) position of both flags and
-        // comparing them. Note that if a flag is not found, its position will be `None`, which
-        // always compared less than `Some(_)`.
-        let max_o = matches.opt_positions("O").into_iter().max();
-        let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
-            if let Some("opt-level") = s.splitn(2, '=').next() {
-                Some(i)
-            } else {
-                None
-            }
-        }).max();
-        if max_o > max_c {
-            OptLevel::Default
-        } else {
-            match cg.opt_level.as_ref().map(String::as_ref) {
-                None => OptLevel::No,
-                Some("0") => OptLevel::No,
-                Some("1") => OptLevel::Less,
-                Some("2") => OptLevel::Default,
-                Some("3") => OptLevel::Aggressive,
-                Some("s") => OptLevel::Size,
-                Some("z") => OptLevel::SizeMin,
-                Some(arg) => {
-                    early_error(
-                        error_format,
-                        &format!(
-                            "optimization level needs to be \
-                             between 0-3, s or z (instead was `{}`)",
-                            arg
-                        ),
-                    );
-                }
+        match cg.opt_level.as_ref().map(String::as_ref) {
+            None => OptLevel::No,
+            Some("0") => OptLevel::No,
+            Some("1") => OptLevel::Less,
+            Some("2") => OptLevel::Default,
+            Some("3") => OptLevel::Aggressive,
+            Some("s") => OptLevel::Size,
+            Some("z") => OptLevel::SizeMin,
+            Some(arg) => {
+                early_error(
+                    error_format,
+                    &format!(
+                        "optimization level needs to be \
+                            between 0-3, s or z (instead was `{}`)",
+                        arg
+                    ),
+                );
             }
         }
-    };
-    // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
-    // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
-    // for more details.
-    let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
+    }
+}
+
+fn select_debuginfo(
+    matches: &getopts::Matches,
+    cg: &CodegenOptions,
+    error_format: ErrorOutputType,
+) -> DebugInfo {
     let max_g = matches.opt_positions("g").into_iter().max();
     let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
         if let Some("debuginfo") = s.splitn(2, '=').next() {
@@ -2307,7 +2291,7 @@ pub fn build_session_options_and_crate_config(
             None
         }
     }).max();
-    let debuginfo = if max_g > max_c {
+    if max_g > max_c {
         DebugInfo::Full
     } else {
         match cg.debuginfo {
@@ -2325,14 +2309,14 @@ pub fn build_session_options_and_crate_config(
                 );
             }
         }
-    };
-
-    let mut search_paths = vec![];
-    for s in &matches.opt_strs("L") {
-        search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
     }
+}
 
-    let libs = matches
+fn parse_libs(
+    matches: &getopts::Matches,
+    error_format: ErrorOutputType,
+) -> Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> {
+    matches
         .opt_strs("l")
         .into_iter()
         .map(|s| {
@@ -2371,52 +2355,23 @@ pub fn build_session_options_and_crate_config(
             let new_name = name_parts.next();
             (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
         })
-        .collect();
-
-    let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
-    let test = matches.opt_present("test");
-
-    let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
-
-    prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
-        "crate-name" => PrintRequest::CrateName,
-        "file-names" => PrintRequest::FileNames,
-        "sysroot" => PrintRequest::Sysroot,
-        "cfg" => PrintRequest::Cfg,
-        "target-list" => PrintRequest::TargetList,
-        "target-cpus" => PrintRequest::TargetCPUs,
-        "target-features" => PrintRequest::TargetFeatures,
-        "relocation-models" => PrintRequest::RelocationModels,
-        "code-models" => PrintRequest::CodeModels,
-        "tls-models" => PrintRequest::TlsModels,
-        "native-static-libs" => PrintRequest::NativeStaticLibs,
-        "target-spec-json" => {
-            if is_unstable_enabled {
-                PrintRequest::TargetSpec
-            } else {
-                early_error(
-                    error_format,
-                    "the `-Z unstable-options` flag must also be passed to \
-                     enable the target-spec-json print option",
-                );
-            }
-        }
-        req => early_error(error_format, &format!("unknown print request `{}`", req)),
-    }));
+        .collect()
+}
 
-    let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
+fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
+    match dopts.borrowck.as_ref().map(|s| &s[..]) {
         None | Some("migrate") => BorrowckMode::Migrate,
         Some("mir") => BorrowckMode::Mir,
         Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
-    };
-
-    if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
-        early_warn(
-            error_format,
-            "-C remark requires \"-C debuginfo=n\" to show source locations",
-        );
     }
+}
 
+fn parse_externs(
+    matches: &getopts::Matches,
+    debugging_opts: &DebuggingOptions,
+    error_format: ErrorOutputType,
+    is_unstable_enabled: bool,
+) -> Externs {
     if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
         early_error(
             ErrorOutputType::default(),
@@ -2457,10 +2412,14 @@ pub fn build_session_options_and_crate_config(
         // flag
         entry.is_private_dep |= private;
     }
+    Externs(externs)
+}
 
-    let crate_name = matches.opt_str("crate-name");
-
-    let remap_path_prefix = matches
+fn parse_remap_path_prefix(
+    matches: &getopts::Matches,
+    error_format: ErrorOutputType
+) -> Vec<(PathBuf, PathBuf)> {
+    matches
         .opt_strs("remap-path-prefix")
         .into_iter()
         .map(|remap| {
@@ -2475,42 +2434,130 @@ pub fn build_session_options_and_crate_config(
                 ),
             }
         })
-        .collect();
+        .collect()
+}
 
-    (
-        Options {
-            crate_types,
-            optimize: opt_level,
-            debuginfo,
-            lint_opts,
-            lint_cap,
-            describe_lints,
-            output_types: OutputTypes(output_types),
-            search_paths,
-            maybe_sysroot: sysroot_opt,
-            target_triple,
-            test,
-            incremental,
-            debugging_opts,
-            prints,
-            borrowck_mode,
-            cg,
+pub fn build_session_options(matches: &getopts::Matches) -> Options {
+    let color = parse_color(matches);
+
+    let edition = parse_crate_edition(matches);
+
+    let (json_rendered, json_artifact_notifications) = parse_json(matches);
+
+    let error_format = parse_error_format(matches, color, json_rendered);
+
+    let unparsed_crate_types = matches.opt_strs("crate-type");
+    let crate_types = parse_crate_types_from_list(unparsed_crate_types)
+        .unwrap_or_else(|e| early_error(error_format, &e[..]));
+
+    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+
+    let mut debugging_opts = build_debugging_options(matches, error_format);
+    check_debug_option_stability(&debugging_opts, error_format, json_rendered);
+
+    let output_types = parse_output_types(&debugging_opts, matches, error_format);
+
+    let mut cg = build_codegen_options(matches, error_format);
+    let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
+        &output_types,
+        matches,
+        error_format,
+        cg.codegen_units,
+    );
+
+    check_thread_count(&debugging_opts, error_format);
+
+    let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
+
+    if debugging_opts.profile && incremental.is_some() {
+        early_error(
             error_format,
-            externs: Externs(externs),
-            crate_name,
-            alt_std_name: None,
-            libs,
-            unstable_features: UnstableFeatures::from_environment(),
-            debug_assertions,
-            actually_rustdoc: false,
-            cli_forced_codegen_units: codegen_units,
-            cli_forced_thinlto_off: disable_thinlto,
-            remap_path_prefix,
-            edition,
-            json_artifact_notifications,
-        },
-        cfg,
-    )
+            "can't instrument with gcov profiling when compiling incrementally",
+        );
+    }
+
+    if cg.profile_generate.enabled() && cg.profile_use.is_some() {
+        early_error(
+            error_format,
+            "options `-C profile-generate` and `-C profile-use` are exclusive",
+        );
+    }
+
+    let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
+    let prints = collect_print_requests(
+        &mut cg,
+        &mut debugging_opts,
+        matches,
+        is_unstable_enabled,
+        error_format,
+    );
+
+    let cg = cg;
+
+    let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
+    let target_triple = parse_target_triple(matches, error_format);
+    let opt_level = parse_opt_level(matches, &cg, error_format);
+    // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
+    // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
+    // for more details.
+    let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
+    let debuginfo = select_debuginfo(matches, &cg, error_format);
+
+    let mut search_paths = vec![];
+    for s in &matches.opt_strs("L") {
+        search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
+    }
+
+    let libs = parse_libs(matches, error_format);
+
+    let test = matches.opt_present("test");
+
+    let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
+
+    if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
+        early_warn(
+            error_format,
+            "-C remark requires \"-C debuginfo=n\" to show source locations",
+        );
+    }
+
+    let externs = parse_externs(matches, &debugging_opts, error_format, is_unstable_enabled);
+
+    let crate_name = matches.opt_str("crate-name");
+
+    let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
+
+    Options {
+        crate_types,
+        optimize: opt_level,
+        debuginfo,
+        lint_opts,
+        lint_cap,
+        describe_lints,
+        output_types,
+        search_paths,
+        maybe_sysroot: sysroot_opt,
+        target_triple,
+        test,
+        incremental,
+        debugging_opts,
+        prints,
+        borrowck_mode,
+        cg,
+        error_format,
+        externs,
+        crate_name,
+        alt_std_name: None,
+        libs,
+        unstable_features: UnstableFeatures::from_environment(),
+        debug_assertions,
+        actually_rustdoc: false,
+        cli_forced_codegen_units: codegen_units,
+        cli_forced_thinlto_off: disable_thinlto,
+        remap_path_prefix,
+        edition,
+        json_artifact_notifications,
+    }
 }
 
 pub fn make_crate_type_option() -> RustcOptGroup {
@@ -2773,6 +2820,3 @@ mod dep_tracking {
         }
     }
 }
-
-#[cfg(test)]
-mod tests;
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index fa2902e4f0e..b65bf2230b3 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -24,11 +24,11 @@ use errors::emitter::HumanReadableErrorType;
 use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter};
 use syntax::ast::{self, NodeId};
 use syntax::edition::Edition;
-use syntax::ext::allocator::AllocatorKind;
+use syntax_expand::allocator::AllocatorKind;
 use syntax::feature_gate::{self, AttributeType};
 use syntax::json::JsonEmitter;
 use syntax::source_map;
-use syntax::parse::{self, ParseSess};
+use syntax::sess::ParseSess;
 use syntax::symbol::Symbol;
 use syntax_pos::{MultiSpan, Span};
 use crate::util::profiling::{SelfProfiler, SelfProfilerRef};
@@ -1159,7 +1159,7 @@ fn build_session_(
     );
     let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
 
-    let parse_sess = parse::ParseSess::with_span_handler(
+    let parse_sess = ParseSess::with_span_handler(
         span_diagnostic,
         source_map,
     );
diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs
index 3695f0a82f4..949dad751a1 100644
--- a/src/librustc/session/search_paths.rs
+++ b/src/librustc/session/search_paths.rs
@@ -1,5 +1,4 @@
 use std::path::{Path, PathBuf};
-use rustc_macros::HashStable;
 use crate::session::{early_error, config};
 use crate::session::filesearch::make_target_lib_path;
 
@@ -10,7 +9,7 @@ pub struct SearchPath {
     pub files: Vec<PathBuf>,
 }
 
-#[derive(Eq, PartialEq, Clone, Copy, Debug, PartialOrd, Ord, Hash, HashStable)]
+#[derive(PartialEq, Clone, Copy, Debug, HashStable)]
 pub enum PathKind {
     Native,
     Crate,
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index aa376699c38..18b25a43e0c 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -715,8 +715,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                             // these notes will often be of the form
                             //     "the type `T` can't be frobnicated"
                             // which is somewhat confusing.
-                            err.help(&format!("consider adding a `where {}` bound",
-                                              trait_ref.to_predicate()));
+                            self.suggest_restricting_param_bound(
+                                &mut err,
+                                &trait_ref,
+                                obligation.cause.body_id,
+                            );
                         } else {
                             if !have_alt_message {
                                 // Can't show anything else useful, try to find similar impls.
@@ -952,6 +955,175 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         err.emit();
     }
 
+    fn suggest_restricting_param_bound(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        trait_ref: &ty::PolyTraitRef<'_>,
+        body_id: hir::HirId,
+    ) {
+        let self_ty = trait_ref.self_ty();
+        let (param_ty, projection) = match &self_ty.kind {
+            ty::Param(_) => (true, None),
+            ty::Projection(projection) => (false, Some(projection)),
+            _ => return,
+        };
+
+        let mut suggest_restriction = |generics: &hir::Generics, msg| {
+            let span = generics.where_clause.span_for_predicates_or_empty_place();
+            if !span.from_expansion() && span.desugaring_kind().is_none() {
+                err.span_suggestion(
+                    generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(),
+                    &format!("consider further restricting {}", msg),
+                    format!(
+                        "{} {} ",
+                        if !generics.where_clause.predicates.is_empty() {
+                            ","
+                        } else {
+                            " where"
+                        },
+                        trait_ref.to_predicate(),
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            }
+        };
+
+        // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
+        //        don't suggest `T: Sized + ?Sized`.
+        let mut hir_id = body_id;
+        while let Some(node) = self.tcx.hir().find(hir_id) {
+            match node {
+                hir::Node::TraitItem(hir::TraitItem {
+                    generics,
+                    kind: hir::TraitItemKind::Method(..), ..
+                }) if param_ty && self_ty == self.tcx.types.self_param => {
+                    // Restricting `Self` for a single method.
+                    suggest_restriction(&generics, "`Self`");
+                    return;
+                }
+
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Fn(_, _, generics, _), ..
+                }) |
+                hir::Node::TraitItem(hir::TraitItem {
+                    generics,
+                    kind: hir::TraitItemKind::Method(..), ..
+                }) |
+                hir::Node::ImplItem(hir::ImplItem {
+                    generics,
+                    kind: hir::ImplItemKind::Method(..), ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Trait(_, _, generics, _, _), ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Impl(_, _, _, generics, ..), ..
+                }) if projection.is_some() => {
+                    // Missing associated type bound.
+                    suggest_restriction(&generics, "the associated type");
+                    return;
+                }
+
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(_, generics), span, .. }) |
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics), span, .. }) |
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Union(_, generics), span, .. }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Trait(_, _, generics, ..), span, ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Fn(_, _, generics, _), span, ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::TyAlias(_, generics), span, ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::TraitAlias(generics, _), span, ..
+                }) |
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), span, ..
+                }) |
+                hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) |
+                hir::Node::ImplItem(hir::ImplItem { generics, span, .. })
+                if param_ty => {
+                    // Missing generic type parameter bound.
+                    let restrict_msg = "consider further restricting this bound";
+                    let param_name = self_ty.to_string();
+                    for param in generics.params.iter().filter(|p| {
+                        &param_name == std::convert::AsRef::<str>::as_ref(&p.name.ident().as_str())
+                    }) {
+                        if param_name.starts_with("impl ") {
+                            // `impl Trait` in argument:
+                            // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
+                            err.span_suggestion(
+                                param.span,
+                                restrict_msg,
+                                // `impl CurrentTrait + MissingTrait`
+                                format!("{} + {}", param.name.ident(), trait_ref),
+                                Applicability::MachineApplicable,
+                            );
+                        } else if generics.where_clause.predicates.is_empty() &&
+                                param.bounds.is_empty()
+                        {
+                            // If there are no bounds whatsoever, suggest adding a constraint
+                            // to the type parameter:
+                            // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
+                            err.span_suggestion(
+                                param.span,
+                                "consider restricting this bound",
+                                format!("{}", trait_ref.to_predicate()),
+                                Applicability::MachineApplicable,
+                            );
+                        } else if !generics.where_clause.predicates.is_empty() {
+                            // There is a `where` clause, so suggest expanding it:
+                            // `fn foo<T>(t: T) where T: Debug {}` →
+                            // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
+                            err.span_suggestion(
+                                generics.where_clause.span().unwrap().shrink_to_hi(),
+                                &format!(
+                                    "consider further restricting type parameter `{}`",
+                                    param_name,
+                                ),
+                                format!(", {}", trait_ref.to_predicate()),
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            // If there is no `where` clause lean towards constraining to the
+                            // type parameter:
+                            // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
+                            // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
+                            let sp = param.span.with_hi(span.hi());
+                            let span = self.tcx.sess.source_map()
+                                .span_through_char(sp, ':');
+                            if sp != param.span && sp != span {
+                                // Only suggest if we have high certainty that the span
+                                // covers the colon in `foo<T: Trait>`.
+                                err.span_suggestion(span, restrict_msg, format!(
+                                    "{} + ",
+                                    trait_ref.to_predicate(),
+                                ), Applicability::MachineApplicable);
+                            } else {
+                                err.span_label(param.span, &format!(
+                                    "consider adding a `where {}` bound",
+                                    trait_ref.to_predicate(),
+                                ));
+                            }
+                        }
+                        return;
+                    }
+                }
+
+                hir::Node::Crate => return,
+
+                _ => {}
+            }
+
+            hir_id = self.tcx.hir().get_parent_item(hir_id);
+        }
+    }
+
     /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
     /// suggestion to borrow the initializer in order to use have a slice instead.
     fn suggest_borrow_on_unsized_slice(
diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs
index eaf5971e459..e84c91daf29 100644
--- a/src/librustc/traits/query/dropck_outlives.rs
+++ b/src/librustc/traits/query/dropck_outlives.rs
@@ -5,6 +5,7 @@ use std::iter::FromIterator;
 use syntax::source_map::Span;
 use crate::ty::subst::GenericArg;
 use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::query::Providers;
 
 impl<'cx, 'tcx> At<'cx, 'tcx> {
     /// Given a type `ty` of some value being dropped, computes a set
@@ -33,7 +34,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
         // Quick check: there are a number of cases that we know do not require
         // any destructor.
         let tcx = self.infcx.tcx;
-        if trivial_dropck_outlives(tcx, ty) {
+        if tcx.trivial_dropck_outlives(ty) {
             return InferOk {
                 value: vec![],
                 obligations: vec![],
@@ -207,15 +208,15 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Error => true,
 
         // [T; N] and [T] have same properties as T.
-        ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
+        ty::Array(ty, _) | ty::Slice(ty) => tcx.trivial_dropck_outlives(ty),
 
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *any* of those are trivial.
-        ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
+        ty::Tuple(ref tys) => tys.iter().all(|t| tcx.trivial_dropck_outlives(t.expect_ty())),
         ty::Closure(def_id, ref substs) => substs
             .as_closure()
             .upvar_tys(def_id, tcx)
-            .all(|t| trivial_dropck_outlives(tcx, t)),
+            .all(|t| tcx.trivial_dropck_outlives(t)),
 
         ty::Adt(def, _) => {
             if Some(def.did) == tcx.lang_items().manually_drop() {
@@ -243,3 +244,10 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
     }
 }
+
+crate fn provide(p: &mut Providers<'_>) {
+    *p = Providers {
+        trivial_dropck_outlives,
+        ..*p
+    };
+}
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index 112a1d0e09c..f6ea77dc5cc 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -40,7 +40,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
 pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
     Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize<T>>>;
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug)]
 pub struct NoSolution;
 
 pub type Fallible<T> = Result<T, NoSolution>;
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
index 12a834fbda6..7aa98703411 100644
--- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -3,7 +3,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound;
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug)]
 pub struct ImpliedOutlivesBounds<'tcx> {
     pub ty: Ty<'tcx>,
 }
diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs
index 9b956f3e554..86a32d68fc0 100644
--- a/src/librustc/traits/query/type_op/outlives.rs
+++ b/src/librustc/traits/query/type_op/outlives.rs
@@ -1,5 +1,4 @@
 use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
-use crate::traits::query::dropck_outlives::trivial_dropck_outlives;
 use crate::traits::query::dropck_outlives::DropckOutlivesResult;
 use crate::traits::query::Fallible;
 use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
@@ -22,7 +21,7 @@ impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
         tcx: TyCtxt<'tcx>,
         key: &ParamEnvAnd<'tcx, Self>,
     ) -> Option<Self::QueryResponse> {
-        if trivial_dropck_outlives(tcx, key.value.dropped_ty) {
+        if tcx.trivial_dropck_outlives(key.value.dropped_ty) {
             Some(DropckOutlivesResult::default())
         } else {
             None
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 9c80ef7d4a2..c1c6eb850f5 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -419,7 +419,7 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String>
 
     // The predicates will contain default bounds like `T: Sized`. We need to
     // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
-    let predicates = &tcx.predicates_of(impl_def_id).predicates;
+    let predicates = tcx.predicates_of(impl_def_id).predicates;
     let mut pretty_predicates = Vec::with_capacity(
         predicates.len() + types_without_default_bounds.len());
 
diff --git a/src/librustc/ty/binding.rs b/src/librustc/ty/binding.rs
index 1290141b0a6..5570144489c 100644
--- a/src/librustc/ty/binding.rs
+++ b/src/librustc/ty/binding.rs
@@ -2,7 +2,7 @@ use crate::hir::BindingAnnotation::*;
 use crate::hir::BindingAnnotation;
 use crate::hir::Mutability;
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
 pub enum BindingMode {
     BindByReference(Mutability),
     BindByValue(Mutability),
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index bd4913c88fd..03cb4775bd8 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -16,6 +16,7 @@ use std::intrinsics;
 use crate::ty::{self, Ty, TyCtxt};
 use crate::ty::subst::SubstsRef;
 use crate::mir::interpret::Allocation;
+use syntax_pos::Span;
 
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
@@ -92,16 +93,16 @@ pub fn encode_with_shorthand<E, T, M>(encoder: &mut E,
     Ok(())
 }
 
-pub fn encode_predicates<'tcx, E, C>(encoder: &mut E,
-                                     predicates: &ty::GenericPredicates<'tcx>,
-                                     cache: C)
-                                     -> Result<(), E::Error>
+pub fn encode_spanned_predicates<'tcx, E, C>(
+    encoder: &mut E,
+    predicates: &'tcx [(ty::Predicate<'tcx>, Span)],
+    cache: C,
+) -> Result<(), E::Error>
     where E: TyEncoder,
           C: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<ty::Predicate<'tcx>, usize>,
 {
-    predicates.parent.encode(encoder)?;
-    predicates.predicates.len().encode(encoder)?;
-    for (predicate, span) in &predicates.predicates {
+    predicates.len().encode(encoder)?;
+    for (predicate, span) in predicates {
         encode_with_shorthand(encoder, predicate, &cache)?;
         span.encode(encoder)?;
     }
@@ -182,13 +183,15 @@ where
 }
 
 #[inline]
-pub fn decode_predicates<D>(decoder: &mut D) -> Result<ty::GenericPredicates<'tcx>, D::Error>
+pub fn decode_spanned_predicates<D>(
+    decoder: &mut D,
+) -> Result<&'tcx [(ty::Predicate<'tcx>, Span)], D::Error>
 where
     D: TyDecoder<'tcx>,
 {
-    Ok(ty::GenericPredicates {
-        parent: Decodable::decode(decoder)?,
-        predicates: (0..decoder.read_usize()?).map(|_| {
+    let tcx = decoder.tcx();
+    Ok(tcx.arena.alloc_from_iter(
+        (0..decoder.read_usize()?).map(|_| {
             // Handle shorthands first, if we have an usize > 0x80.
             let predicate = if decoder.positioned_at_shorthand() {
                 let pos = decoder.read_usize()?;
@@ -202,7 +205,7 @@ where
             Ok((predicate, Decodable::decode(decoder)?))
         })
         .collect::<Result<Vec<_>, _>>()?,
-    })
+    ))
 }
 
 #[inline]
@@ -339,6 +342,8 @@ macro_rules! implement_ty_decoder {
             use $crate::ty::subst::SubstsRef;
             use $crate::hir::def_id::{CrateNum};
 
+            use syntax_pos::Span;
+
             use super::$DecoderName;
 
             impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
@@ -393,11 +398,11 @@ macro_rules! implement_ty_decoder {
                 }
             }
 
-            impl<$($typaram),*> SpecializedDecoder<ty::GenericPredicates<'tcx>>
+            impl<$($typaram),*> SpecializedDecoder<&'tcx [(ty::Predicate<'tcx>, Span)]>
             for $DecoderName<$($typaram),*> {
                 fn specialized_decode(&mut self)
-                                      -> Result<ty::GenericPredicates<'tcx>, Self::Error> {
-                    decode_predicates(self)
+                                      -> Result<&'tcx [(ty::Predicate<'tcx>, Span)], Self::Error> {
+                    decode_spanned_predicates(self)
                 }
             }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index cd52f8fa92c..d118bef37fc 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -43,7 +43,7 @@ use crate::ty::subst::{UserSubsts, GenericArgKind};
 use crate::ty::{BoundVar, BindingMode};
 use crate::ty::CanonicalPolyFnSig;
 use crate::util::common::ErrorReported;
-use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet};
+use crate::util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap, ItemLocalSet, NodeMap};
 use crate::util::nodemap::{FxHashMap, FxHashSet};
 use crate::util::profiling::SelfProfilerRef;
 
@@ -148,10 +148,6 @@ impl<'tcx> CtxtInterners<'tcx> {
     }
 }
 
-pub struct Common<'tcx> {
-    pub empty_predicates: ty::GenericPredicates<'tcx>,
-}
-
 pub struct CommonTypes<'tcx> {
     pub unit: Ty<'tcx>,
     pub bool: Ty<'tcx>,
@@ -831,7 +827,7 @@ rustc_index::newtype_index! {
 pub type CanonicalUserTypeAnnotations<'tcx> =
     IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct CanonicalUserTypeAnnotation<'tcx> {
     pub user_ty: CanonicalUserType<'tcx>,
     pub span: Span,
@@ -886,7 +882,7 @@ impl CanonicalUserType<'tcx> {
                         },
 
                         GenericArgKind::Const(ct) => match ct.val {
-                            ConstValue::Infer(InferConst::Canonical(debruijn, b)) => {
+                            ConstValue::Bound(debruijn, b) => {
                                 // We only allow a `ty::INNERMOST` index in substitutions.
                                 assert_eq!(debruijn, ty::INNERMOST);
                                 cvar == b
@@ -903,7 +899,7 @@ impl CanonicalUserType<'tcx> {
 /// A user-given type annotation attached to a constant. These arise
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
 pub enum UserType<'tcx> {
     Ty(Ty<'tcx>),
 
@@ -1039,9 +1035,6 @@ pub struct GlobalCtxt<'tcx> {
 
     pub prof: SelfProfilerRef,
 
-    /// Common objects.
-    pub common: Common<'tcx>,
-
     /// Common types, pre-interned for your convenience.
     pub types: CommonTypes<'tcx>,
 
@@ -1051,6 +1044,9 @@ pub struct GlobalCtxt<'tcx> {
     /// Common consts, pre-interned for your convenience.
     pub consts: CommonConsts<'tcx>,
 
+    /// Resolutions of `extern crate` items produced by resolver.
+    extern_crate_map: NodeMap<CrateNum>,
+
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     trait_map: FxHashMap<DefIndex,
@@ -1210,12 +1206,6 @@ impl<'tcx> TyCtxt<'tcx> {
             s.fatal(&err);
         });
         let interners = CtxtInterners::new(&arenas.interner);
-        let common = Common {
-            empty_predicates: ty::GenericPredicates {
-                parent: None,
-                predicates: vec![],
-            },
-        };
         let common_types = CommonTypes::new(&interners);
         let common_lifetimes = CommonLifetimes::new(&interners);
         let common_consts = CommonConsts::new(&interners, &common_types);
@@ -1270,10 +1260,10 @@ impl<'tcx> TyCtxt<'tcx> {
             interners,
             dep_graph,
             prof: s.prof.clone(),
-            common,
             types: common_types,
             lifetimes: common_lifetimes,
             consts: common_consts,
+            extern_crate_map: resolutions.extern_crate_map,
             trait_map,
             export_map: resolutions.export_map.into_iter().map(|(k, v)| {
                 let exports: Vec<_> = v.into_iter().map(|e| {
@@ -2951,7 +2941,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     };
     providers.extern_mod_stmt_cnum = |tcx, id| {
         let id = tcx.hir().as_local_node_id(id).unwrap();
-        tcx.cstore.extern_mod_stmt_cnum_untracked(id)
+        tcx.extern_crate_map.get(&id).cloned()
     };
     providers.all_crate_nums = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 882f330e6c3..77613b548cf 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -51,7 +51,6 @@ pub enum TypeError<'tcx> {
     IntrinsicCast,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
 pub enum UnconstrainedNumeric {
     UnconstrainedFloat,
     UnconstrainedInt,
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 038b54f1f26..27a09b394b8 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -19,7 +19,7 @@ pub type SimplifiedType = SimplifiedTypeGen<DefId>;
 /// the non-stable but fast to construct DefId-version is the better choice.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
 pub enum SimplifiedTypeGen<D>
-    where D: Copy + Debug + Ord + Eq + Hash
+    where D: Copy + Debug + Ord + Eq
 {
     BoolSimplifiedType,
     CharSimplifiedType,
@@ -123,10 +123,10 @@ pub fn simplify_type(
     }
 }
 
-impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
+impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
     pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
         where F: Fn(D) -> U,
-              U: Copy + Debug + Ord + Eq + Hash,
+              U: Copy + Debug + Ord + Eq,
     {
         match self {
             BoolSimplifiedType => BoolSimplifiedType,
@@ -155,7 +155,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
 
 impl<'a, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D>
 where
-    D: Copy + Debug + Ord + Eq + Hash + HashStable<StableHashingContext<'a>>,
+    D: Copy + Debug + Ord + Eq + HashStable<StableHashingContext<'a>>,
 {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         mem::discriminant(self).hash_stable(hcx, hasher);
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index d3a3f51cfa4..cb1fb4f685d 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -240,10 +240,10 @@ impl FlagComputation {
                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER);
                 match infer {
                     InferConst::Fresh(_) => {}
-                    InferConst::Canonical(debruijn, _) => self.add_binder(debruijn),
                     InferConst::Var(_) => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX),
                 }
             }
+            ConstValue::Bound(debruijn, _) => self.add_binder(debruijn),
             ConstValue::Param(_) => {
                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_PARAMS);
             }
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 5192075c26e..bacf3d42f04 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -88,6 +88,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn has_infer_types(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_INFER)
     }
+    fn has_infer_consts(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_CT_INFER)
+    }
     fn has_local_value(&self) -> bool {
         self.has_type_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
     }
@@ -518,10 +521,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
     }
 
     fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const {
-            val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)),
-            ty,
-        } = *ct {
+        if let ty::Const { val: ConstValue::Bound(debruijn, bound_const), ty } = *ct {
             if debruijn == self.current_index {
                 let fld_c = &mut self.fld_c;
                 let ct = fld_c(bound_const, ty);
@@ -567,7 +567,10 @@ impl<'tcx> TyCtxt<'tcx> {
         // identity for bound types and consts
         let fld_t = |bound_ty| self.mk_ty(ty::Bound(ty::INNERMOST, bound_ty));
         let fld_c = |bound_ct, ty| {
-            self.mk_const_infer(ty::InferConst::Canonical(ty::INNERMOST, bound_ct), ty)
+            self.mk_const(ty::Const {
+                val: ConstValue::Bound(ty::INNERMOST, bound_ct),
+                ty,
+            })
         };
         self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c)
     }
@@ -718,7 +721,6 @@ impl<'tcx> TyCtxt<'tcx> {
 // vars. See comment on `shift_vars_through_binders` method in
 // `subst.rs` for more details.
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 enum Direction {
     In,
     Out,
@@ -799,10 +801,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
     }
 
     fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const {
-            val: ConstValue::Infer(ty::InferConst::Canonical(debruijn, bound_const)),
-            ty,
-        } = *ct {
+        if let ty::Const { val: ConstValue::Bound(debruijn, bound_ct), ty } = *ct {
             if self.amount == 0 || debruijn < self.current_index {
                 ct
             } else {
@@ -813,7 +812,10 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
                         debruijn.shifted_out(self.amount)
                     }
                 };
-                self.tcx.mk_const_infer(ty::InferConst::Canonical(debruijn, bound_const), ty)
+                self.tcx.mk_const(ty::Const {
+                    val: ConstValue::Bound(debruijn, bound_ct),
+                    ty,
+                })
             }
         } else {
             ct.super_fold_with(self)
@@ -917,8 +919,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
         // const, as it has types/regions embedded in a lot of other
         // places.
         match ct.val {
-            ConstValue::Infer(ty::InferConst::Canonical(debruijn, _))
-                if debruijn >= self.outer_index => true,
+            ConstValue::Bound(debruijn, _) if debruijn >= self.outer_index => true,
             _ => ct.super_visit_with(self),
         }
     }
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index ce7e1822d9a..aed9e87a168 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -824,10 +824,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     });
                     (present_variants.next(), present_variants.next())
                 };
-                if present_first.is_none() {
+                let present_first = match present_first {
+                    present_first @ Some(_) => present_first,
                     // Uninhabited because it has no variants, or only absent ones.
-                    return tcx.layout_raw(param_env.and(tcx.types.never));
-                }
+                    None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
+                    // if it's a struct, still compute a layout so that we can still compute the
+                    // field offsets
+                    None => Some(VariantIdx::new(0)),
+                };
 
                 let is_struct = !def.is_enum() ||
                     // Only one variant is present.
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3692caada57..d377b7328e8 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -28,7 +28,7 @@ use crate::ty::subst::{Subst, InternalSubsts, SubstsRef};
 use crate::ty::util::{IntTypeExt, Discr};
 use crate::ty::walk::TypeWalker;
 use crate::util::captures::Captures;
-use crate::util::nodemap::{NodeSet, DefIdMap, FxHashMap};
+use crate::util::nodemap::{NodeMap, NodeSet, DefIdMap, FxHashMap};
 use arena::SyncDroplessArena;
 use crate::session::DataTypeKind;
 
@@ -45,7 +45,7 @@ use std::{mem, ptr};
 use std::ops::Range;
 use syntax::ast::{self, Name, Ident, NodeId};
 use syntax::attr;
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::hygiene::ExpnId;
 use syntax::symbol::{kw, sym, Symbol, InternedString};
 use syntax_pos::Span;
 
@@ -121,6 +121,7 @@ mod sty;
 
 #[derive(Clone)]
 pub struct Resolutions {
+    pub extern_crate_map: NodeMap<CrateNum>,
     pub trait_map: TraitMap,
     pub maybe_unused_trait_imports: NodeSet,
     pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
@@ -158,7 +159,7 @@ impl AssocItemContainer {
 /// The "header" of an impl is everything outside the body: a Self type, a trait
 /// ref (in the case of a trait impl), and a set of predicates (from the
 /// bounds / where-clauses).
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Debug)]
 pub struct ImplHeader<'tcx> {
     pub impl_def_id: DefId,
     pub self_ty: Ty<'tcx>,
@@ -194,7 +195,7 @@ pub struct AssocItem {
     pub method_has_self_argument: bool,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
 pub enum AssocKind {
     Const,
     Method,
@@ -330,7 +331,7 @@ impl Visibility {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Hash, HashStable)]
+#[derive(Copy, Clone, PartialEq, RustcDecodable, RustcEncodable, HashStable)]
 pub enum Variance {
     Covariant,      // T<A> <: T<B> iff A <: B -- e.g., function return type
     Invariant,      // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
@@ -700,6 +701,13 @@ impl<T> Deref for List<T> {
     type Target = [T];
     #[inline(always)]
     fn deref(&self) -> &[T] {
+        self.as_ref()
+    }
+}
+
+impl<T> AsRef<[T]> for List<T> {
+    #[inline(always)]
+    fn as_ref(&self) -> &[T] {
         unsafe {
             slice::from_raw_parts(self.data.as_ptr(), self.len)
         }
@@ -744,7 +752,7 @@ pub struct UpvarId {
     pub closure_expr_id: LocalDefId,
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy, HashStable)]
+#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, HashStable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     ImmBorrow,
@@ -1010,15 +1018,12 @@ impl<'tcx> Generics {
 }
 
 /// Bounds on generics.
-#[derive(Clone, Default, Debug, HashStable)]
+#[derive(Copy, Clone, Default, Debug, RustcEncodable, RustcDecodable, HashStable)]
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
-    pub predicates: Vec<(Predicate<'tcx>, Span)>,
+    pub predicates: &'tcx [(Predicate<'tcx>, Span)],
 }
 
-impl<'tcx> rustc_serialize::UseSpecializedEncodable for GenericPredicates<'tcx> {}
-impl<'tcx> rustc_serialize::UseSpecializedDecodable for GenericPredicates<'tcx> {}
-
 impl<'tcx> GenericPredicates<'tcx> {
     pub fn instantiate(
         &self,
@@ -2313,7 +2318,7 @@ impl<'tcx> AdtDef {
     }
 
     #[inline]
-    pub fn predicates(&self, tcx: TyCtxt<'tcx>) -> &'tcx GenericPredicates<'tcx> {
+    pub fn predicates(&self, tcx: TyCtxt<'tcx>) -> GenericPredicates<'tcx> {
         tcx.predicates_of(self.did)
     }
 
@@ -2553,7 +2558,7 @@ impl<'tcx> AdtDef {
                     def_id: sized_trait,
                     substs: tcx.mk_substs_trait(ty, &[])
                 }).to_predicate();
-                let predicates = &tcx.predicates_of(self.did).predicates;
+                let predicates = tcx.predicates_of(self.did).predicates;
                 if predicates.iter().any(|(p, _)| *p == sized_predicate) {
                     vec![]
                 } else {
@@ -3395,6 +3400,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     layout::provide(providers);
     util::provide(providers);
     constness::provide(providers);
+    crate::traits::query::dropck_outlives::provide(providers);
     *providers = ty::query::Providers {
         asyncness,
         associated_item,
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index c4967f8d66d..363109a0582 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1483,7 +1483,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
         }
 
         // Replace any anonymous late-bound regions with named
-        // variants, using gensym'd identifiers, so that we can
+        // variants, using new unique 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.
diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs
index 30a3e53dddf..f61801cd232 100644
--- a/src/librustc/ty/query/keys.rs
+++ b/src/librustc/ty/query/keys.rs
@@ -8,14 +8,12 @@ use crate::ty::subst::SubstsRef;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::mir;
 
-use std::fmt::Debug;
-use std::hash::Hash;
 use syntax_pos::{Span, DUMMY_SP};
 use syntax_pos::symbol::InternedString;
 
 /// The `Key` trait controls what types can legally be used as the key
 /// for a query.
-pub(super) trait Key: Clone + Hash + Eq + Debug {
+pub(super) trait Key {
     /// Given an instance of this key, what crate is it referring to?
     /// This is used to find the provider.
     fn query_crate(&self) -> CrateNum;
@@ -201,10 +199,7 @@ impl Key for InternedString {
 
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
-impl<'tcx, T> Key for Canonical<'tcx, T>
-where
-    T: Debug + Hash + Clone + Eq,
-{
+impl<'tcx, T> Key for Canonical<'tcx, T> {
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs
index 1bba7fdd863..21a7cf00b28 100644
--- a/src/librustc/ty/query/on_disk_cache.rs
+++ b/src/librustc/ty/query/on_disk_cache.rs
@@ -882,15 +882,16 @@ where
     }
 }
 
-impl<'a, 'tcx, E> SpecializedEncoder<ty::GenericPredicates<'tcx>> for CacheEncoder<'a, 'tcx, E>
+impl<'a, 'tcx, E> SpecializedEncoder<&'tcx [(ty::Predicate<'tcx>, Span)]>
+    for CacheEncoder<'a, 'tcx, E>
 where
     E: 'a + TyEncoder,
 {
     #[inline]
     fn specialized_encode(&mut self,
-                          predicates: &ty::GenericPredicates<'tcx>)
+                          predicates: &&'tcx [(ty::Predicate<'tcx>, Span)])
                           -> Result<(), Self::Error> {
-        ty_codec::encode_predicates(self, predicates,
+        ty_codec::encode_spanned_predicates(self, predicates,
             |encoder| &mut encoder.predicate_shorthands)
     }
 }
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 7f05e553bc9..41b4883793b 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -801,7 +801,7 @@ macro_rules! define_queries_inner {
         }
 
         #[allow(nonstandard_style)]
-        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+        #[derive(Clone, Copy)]
         pub enum QueryName {
             $($name),*
         }
@@ -819,7 +819,7 @@ macro_rules! define_queries_inner {
         }
 
         #[allow(nonstandard_style)]
-        #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+        #[derive(Clone, Debug)]
         pub enum Query<$tcx> {
             $($(#[$attr])* $name($K)),*
         }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 3a5b8b57741..5d78d563e9a 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1219,12 +1219,6 @@ EnumTypeFoldableImpl! {
     }
 }
 
-BraceStructTypeFoldableImpl! {
-    impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
-        parent, predicates
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         // This code is hot enough that it's worth specializing for a list of
@@ -1387,27 +1381,23 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
 impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
-            ConstValue::ByRef { alloc, offset } =>
-                ConstValue::ByRef { alloc, offset },
             ConstValue::Infer(ic) => ConstValue::Infer(ic.fold_with(folder)),
             ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)),
-            ConstValue::Placeholder(p) => ConstValue::Placeholder(p),
-            ConstValue::Scalar(a) => ConstValue::Scalar(a),
-            ConstValue::Slice { data, start, end } => ConstValue::Slice { data, start, end },
             ConstValue::Unevaluated(did, substs)
                 => ConstValue::Unevaluated(did, substs.fold_with(folder)),
+            ConstValue::ByRef { .. } | ConstValue::Bound(..) | ConstValue::Placeholder(..)
+            | ConstValue::Scalar(..) | ConstValue::Slice { .. } => *self,
+
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
-            ConstValue::ByRef { .. } => false,
             ConstValue::Infer(ic) => ic.visit_with(visitor),
             ConstValue::Param(p) => p.visit_with(visitor),
-            ConstValue::Placeholder(_) => false,
-            ConstValue::Scalar(_) => false,
-            ConstValue::Slice { .. } => false,
             ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
+            ConstValue::ByRef { .. } | ConstValue::Bound(..) | ConstValue::Placeholder(_)
+            | ConstValue::Scalar(_) | ConstValue::Slice { .. } => false,
         }
     }
 }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 4af73fa389a..298e7989596 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -304,8 +304,7 @@ static_assert_size!(TyKind<'_>, 24);
 /// type parameters is similar, but the role of CK and CS are
 /// different. CK represents the "yield type" and CS represents the
 /// "return type" of the generator.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug,
-         RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function,
     /// concatenated with the types of the upvars.
@@ -392,8 +391,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
 }
 
 /// Similar to `ClosureSubsts`; see the above documentation for more.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug,
-         RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Copy, Clone, Debug)]
 pub struct GeneratorSubsts<'tcx> {
     pub substs: SubstsRef<'tcx>,
 }
@@ -1035,7 +1033,7 @@ impl<'tcx> ProjectionTy<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug)]
 pub struct GenSig<'tcx> {
     pub yield_ty: Ty<'tcx>,
     pub return_ty: Ty<'tcx>,
@@ -2373,6 +2371,4 @@ pub enum InferConst<'tcx> {
     Var(ConstVid<'tcx>),
     /// A fresh const variable. See `infer::freshen` for more details.
     Fresh(u32),
-    /// Canonicalized const variable, used only when preparing a trait query.
-    Canonical(DebruijnIndex, BoundVar),
 }
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 4081c02a33c..29721979099 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -2,7 +2,7 @@
 
 use crate::hir::def_id::DefId;
 use crate::infer::canonical::Canonical;
-use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst};
+use crate::ty::{self, Lift, List, Ty, TyCtxt, ParamConst};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::mir::interpret::ConstValue;
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
@@ -234,9 +234,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
 
                 ty::GenericParamDefKind::Const => {
                     tcx.mk_const(ty::Const {
-                        val: ConstValue::Infer(
-                            InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from(param.index))
-                        ),
+                        val: ConstValue::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
                         ty: tcx.type_of(def_id),
                     }).into()
                 }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 5ddf15317a3..5555dace45b 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -697,6 +697,9 @@ impl<'tcx> TyCtxt<'tcx> {
             // that type, and when we finish expanding that type we remove the
             // its DefId.
             seen_opaque_tys: FxHashSet<DefId>,
+            // Cache of all expansions we've seen so far. This is a critical
+            // optimization for some large types produced by async fn trees.
+            expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
             primary_def_id: DefId,
             found_recursion: bool,
             tcx: TyCtxt<'tcx>,
@@ -713,9 +716,16 @@ impl<'tcx> TyCtxt<'tcx> {
                 }
                 let substs = substs.fold_with(self);
                 if self.seen_opaque_tys.insert(def_id) {
-                    let generic_ty = self.tcx.type_of(def_id);
-                    let concrete_ty = generic_ty.subst(self.tcx, substs);
-                    let expanded_ty = self.fold_ty(concrete_ty);
+                    let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
+                        Some(expanded_ty) => expanded_ty,
+                        None => {
+                            let generic_ty = self.tcx.type_of(def_id);
+                            let concrete_ty = generic_ty.subst(self.tcx, substs);
+                            let expanded_ty = self.fold_ty(concrete_ty);
+                            self.expanded_cache.insert((def_id, substs), expanded_ty);
+                            expanded_ty
+                        }
+                    };
                     self.seen_opaque_tys.remove(&def_id);
                     Some(expanded_ty)
                 } else {
@@ -735,14 +745,17 @@ impl<'tcx> TyCtxt<'tcx> {
             fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                 if let ty::Opaque(def_id, substs) = t.kind {
                     self.expand_opaque_ty(def_id, substs).unwrap_or(t)
-                } else {
+                } else if t.has_projections() {
                     t.super_fold_with(self)
+                } else {
+                    t
                 }
             }
         }
 
         let mut visitor = OpaqueTypeExpander {
             seen_opaque_tys: FxHashSet::default(),
+            expanded_cache: FxHashMap::default(),
             primary_def_id: def_id,
             found_recursion: false,
             tcx: self,
@@ -805,6 +818,8 @@ impl<'tcx> ty::TyS<'tcx> {
     ///
     /// (Note that this implies that if `ty` has a destructor attached,
     /// then `needs_drop` will definitely return `true` for `ty`.)
+    ///
+    /// Note that this method is used to check eligible types in unions.
     #[inline]
     pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
         tcx.needs_drop_raw(param_env.and(self)).0
@@ -1096,6 +1111,9 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
 
         ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
 
+        // Zero-length arrays never contain anything to drop.
+        ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
+
         // Structural recursion.
         ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
 
diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml
index 98efa6a5804..867bbd22cfb 100644
--- a/src/librustc_codegen_llvm/Cargo.toml
+++ b/src/librustc_codegen_llvm/Cargo.toml
@@ -12,9 +12,3 @@ test = false
 
 [dependencies]
 rustc_llvm = { path = "../librustc_llvm" }
-
-[features]
-# This is used to convince Cargo to separately cache builds of `rustc_codegen_llvm`
-# when this option is enabled or not. That way we can build two, cache two
-# artifacts, and have nice speedy rebuilds.
-emscripten = ["rustc_llvm/emscripten"]
diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs
index f31765cea4f..8c60c030eac 100644
--- a/src/librustc_codegen_llvm/allocator.rs
+++ b/src/librustc_codegen_llvm/allocator.rs
@@ -3,7 +3,7 @@ use std::ffi::CString;
 use crate::attributes;
 use libc::c_uint;
 use rustc::ty::TyCtxt;
-use syntax::ext::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use syntax_expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
 
 use crate::ModuleLlvm;
 use crate::llvm::{self, False, True};
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 7437b1e3c8a..b3be3d09f17 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -53,9 +53,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
 
     let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| {
         if level.is_below_threshold(export_threshold) {
-            let mut bytes = Vec::with_capacity(name.len() + 1);
-            bytes.extend(name.bytes());
-            Some(CString::new(bytes).unwrap())
+            Some(CString::new(name.as_str()).unwrap())
         } else {
             None
         }
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 71a6067fd48..98be0ae4433 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -52,6 +52,7 @@ const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr();
 
 impl BackendTypes for Builder<'_, 'll, 'tcx> {
     type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
+    type Function = <CodegenCx<'ll, 'tcx> as BackendTypes>::Function;
     type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock;
     type Type = <CodegenCx<'ll, 'tcx> as BackendTypes>::Type;
     type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index 35d5107842d..08fa23f2a7c 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -33,7 +33,7 @@ pub fn get_fn(
     assert!(!instance.substs.has_param_types());
 
     let sig = instance.fn_sig(cx.tcx());
-    if let Some(&llfn) = cx.instances().borrow().get(&instance) {
+    if let Some(&llfn) = cx.instances.borrow().get(&instance) {
         return llfn;
     }
 
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 6fbea9646b8..a1a5232d588 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -2,7 +2,7 @@
 
 //! Code that is useful in various codegen modules.
 
-use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef};
+use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef, ConstantInt};
 use crate::abi;
 use crate::consts;
 use crate::type_::Type;
@@ -86,6 +86,8 @@ impl Funclet<'ll> {
 
 impl BackendTypes for CodegenCx<'ll, 'tcx> {
     type Value = &'ll Value;
+    type Function = &'ll Value;
+
     type BasicBlock = &'ll BasicBlock;
     type Type = &'ll Type;
     type Funclet = Funclet<'ll>;
@@ -243,33 +245,23 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         struct_in_context(self.llcx, elts, packed)
     }
 
-    fn const_to_uint(&self, v: &'ll Value) -> u64 {
-        unsafe {
+    fn const_to_opt_uint(&self, v: &'ll Value) -> Option<u64> {
+        try_as_const_integral(v).map(|v| unsafe {
             llvm::LLVMConstIntGetZExtValue(v)
-        }
-    }
-
-    fn is_const_integral(&self, v: &'ll Value) -> bool {
-        unsafe {
-            llvm::LLVMIsAConstantInt(v).is_some()
-        }
+        })
     }
 
     fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option<u128> {
-        unsafe {
-            if self.is_const_integral(v) {
-                let (mut lo, mut hi) = (0u64, 0u64);
-                let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
-                                                           &mut hi, &mut lo);
-                if success {
-                    Some(hi_lo_to_u128(lo, hi))
-                } else {
-                    None
-                }
+        try_as_const_integral(v).and_then(|v| unsafe {
+            let (mut lo, mut hi) = (0u64, 0u64);
+            let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
+                                                        &mut hi, &mut lo);
+            if success {
+                Some(hi_lo_to_u128(lo, hi))
             } else {
                 None
             }
-        }
+        })
     }
 
     fn scalar_to_backend(
@@ -305,7 +297,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                         }
                     }
                     Some(GlobalAlloc::Function(fn_instance)) => {
-                        self.get_fn(fn_instance)
+                        self.get_fn_addr(fn_instance)
                     }
                     Some(GlobalAlloc::Static(def_id)) => {
                         assert!(self.tcx.is_static(def_id));
@@ -386,3 +378,9 @@ pub fn struct_in_context(
 fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 {
     ((hi as u128) << 64) | (lo as u128)
 }
+
+fn try_as_const_integral(v: &'ll Value) -> Option<&'ll ConstantInt> {
+    unsafe {
+        llvm::LLVMIsAConstantInt(v)
+    }
+}
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 7ca226914a5..2da93877172 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -20,7 +20,6 @@ use rustc::ty::layout::{
 use rustc::ty::{self, Ty, TyCtxt, Instance};
 use rustc::util::nodemap::FxHashMap;
 use rustc_target::spec::{HasTargetSpec, Target};
-use rustc_codegen_ssa::callee::resolve_and_get_fn;
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use crate::callee::get_fn;
 
@@ -327,11 +326,11 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         &self.vtables
     }
 
-    fn instances(&self) -> &RefCell<FxHashMap<Instance<'tcx>, &'ll Value>> {
-        &self.instances
+    fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value {
+        get_fn(self, instance)
     }
 
-    fn get_fn(&self, instance: Instance<'tcx>) -> &'ll Value {
+    fn get_fn_addr(&self, instance: Instance<'tcx>) -> &'ll Value {
         get_fn(self, instance)
     }
 
@@ -362,7 +361,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let tcx = self.tcx;
         let llfn = match tcx.lang_items().eh_personality() {
             Some(def_id) if !wants_msvc_seh(self.sess()) => {
-                resolve_and_get_fn(self, def_id, tcx.intern_substs(&[]))
+                self.get_fn_addr(
+                    ty::Instance::resolve(
+                        tcx,
+                        ty::ParamEnv::reveal_all(),
+                        def_id,
+                        tcx.intern_substs(&[]),
+                    ).unwrap()
+                )
             }
             _ => {
                 let name = if wants_msvc_seh(self.sess()) {
@@ -390,7 +396,14 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let tcx = self.tcx;
         assert!(self.sess().target.target.options.custom_unwind_resume);
         if let Some(def_id) = tcx.lang_items().eh_unwind_resume() {
-            let llfn = resolve_and_get_fn(self, def_id, tcx.intern_substs(&[]));
+            let llfn = self.get_fn_addr(
+                ty::Instance::resolve(
+                    tcx,
+                    ty::ParamEnv::reveal_all(),
+                    def_id,
+                    tcx.intern_substs(&[]),
+                ).unwrap()
+            );
             unwresume.set(Some(llfn));
             return llfn;
         }
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 438a660b8a8..7bd82ced3c3 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -2069,11 +2069,9 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, 'tcx>,
     {
         let mut composite_types_completed =
             debug_context(cx).composite_types_completed.borrow_mut();
-        if composite_types_completed.contains(&composite_type_metadata) {
+        if !composite_types_completed.insert(&composite_type_metadata) {
             bug!("debuginfo::set_members_of_composite_type() - \
                   Already completed forward declaration re-encountered.");
-        } else {
-            composite_types_completed.insert(composite_type_metadata);
         }
     }
 
diff --git a/src/librustc_codegen_llvm/error_codes.rs b/src/librustc_codegen_llvm/error_codes.rs
deleted file mode 100644
index 042e51ed2ba..00000000000
--- a/src/librustc_codegen_llvm/error_codes.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-register_diagnostics! {
-
-E0511: r##"
-Invalid monomorphization of an intrinsic function was used. Erroneous code
-example:
-
-```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
-#![feature(platform_intrinsics)]
-
-extern "platform-intrinsic" {
-    fn simd_add<T>(a: T, b: T) -> T;
-}
-
-fn main() {
-    unsafe { simd_add(0, 1); }
-    // error: invalid monomorphization of `simd_add` intrinsic
-}
-```
-
-The generic type has to be a SIMD type. Example:
-
-```
-#![feature(repr_simd)]
-#![feature(platform_intrinsics)]
-
-#[repr(simd)]
-#[derive(Copy, Clone)]
-struct i32x2(i32, i32);
-
-extern "platform-intrinsic" {
-    fn simd_add<T>(a: T, b: T) -> T;
-}
-
-unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
-```
-"##,
-
-}
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 68d9af09c42..3df8d4c2690 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -20,9 +20,9 @@ use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc::hir;
 use syntax::ast::{self, FloatTy};
 
+use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::traits::*;
 
-use rustc::session::Session;
 use syntax_pos::Span;
 
 use std::cmp::Ordering;
@@ -1026,10 +1026,6 @@ fn get_rust_try_fn<'ll, 'tcx>(
     rust_try
 }
 
-fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
-    span_err!(a, b, E0511, "{}", c);
-}
-
 fn generic_simd_intrinsic(
     bx: &mut Builder<'a, 'll, 'tcx>,
     name: &str,
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 52797e64f7d..9b55bef0c51 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -38,7 +38,8 @@ extern crate rustc_fs_util;
 extern crate rustc_driver as _;
 
 #[macro_use] extern crate log;
-#[macro_use] extern crate syntax;
+extern crate syntax;
+extern crate syntax_expand;
 extern crate syntax_pos;
 extern crate rustc_errors as errors;
 
@@ -48,7 +49,7 @@ use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModul
 use rustc_codegen_ssa::CompiledModule;
 use errors::{FatalError, Handler};
 use rustc::dep_graph::WorkProduct;
-use syntax::ext::allocator::AllocatorKind;
+use syntax_expand::allocator::AllocatorKind;
 use syntax_pos::symbol::InternedString;
 pub use llvm_util::target_features;
 use std::any::Any;
@@ -64,8 +65,6 @@ use rustc::util::common::ErrorReported;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 
-mod error_codes;
-
 mod back {
     pub mod archive;
     pub mod bytecode;
@@ -258,10 +257,6 @@ impl CodegenBackend for LlvmCodegenBackend {
         llvm_util::print_version();
     }
 
-    fn diagnostics(&self) -> &[(&'static str, &'static str)] {
-        &error_codes::DIAGNOSTICS
-    }
-
     fn target_features(&self, sess: &Session) -> Vec<Symbol> {
         target_features(sess)
     }
@@ -271,15 +266,10 @@ impl CodegenBackend for LlvmCodegenBackend {
     }
 
     fn provide(&self, providers: &mut ty::query::Providers<'_>) {
-        rustc_codegen_utils::symbol_names::provide(providers);
-        rustc_codegen_ssa::back::symbol_export::provide(providers);
-        rustc_codegen_ssa::base::provide_both(providers);
         attributes::provide(providers);
     }
 
     fn provide_extern(&self, providers: &mut ty::query::Providers<'_>) {
-        rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
-        rustc_codegen_ssa::base::provide_both(providers);
         attributes::provide_extern(providers);
     }
 
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index b07214fdc03..c69942ef3f2 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -50,7 +50,7 @@ pub enum CallConv {
 }
 
 /// LLVMRustLinkage
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq)]
 #[repr(C)]
 pub enum Linkage {
     ExternalLinkage = 0,
@@ -67,7 +67,6 @@ pub enum Linkage {
 }
 
 // LLVMRustVisibility
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[repr(C)]
 pub enum Visibility {
     Default = 0,
@@ -510,6 +509,7 @@ extern { pub type Module; }
 extern { pub type Context; }
 extern { pub type Type; }
 extern { pub type Value; }
+extern { pub type ConstantInt; }
 extern { pub type Metadata; }
 extern { pub type BasicBlock; }
 #[repr(C)]
@@ -719,8 +719,8 @@ extern "C" {
     pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value;
     pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value;
     pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value;
-    pub fn LLVMConstIntGetZExtValue(ConstantVal: &Value) -> c_ulonglong;
-    pub fn LLVMRustConstInt128Get(ConstantVal: &Value, SExt: bool,
+    pub fn LLVMConstIntGetZExtValue(ConstantVal: &ConstantInt) -> c_ulonglong;
+    pub fn LLVMRustConstInt128Get(ConstantVal: &ConstantInt, SExt: bool,
                                   high: &mut u64, low: &mut u64) -> bool;
 
 
@@ -1666,7 +1666,7 @@ extern "C" {
     #[allow(improper_ctypes)]
     pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
 
-    pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&Value>;
+    pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
 
     pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind;
     pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 541d3d98b79..2dce9b04c9e 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -257,8 +257,7 @@ pub fn target_feature_whitelist(sess: &Session)
         "hexagon" => HEXAGON_WHITELIST,
         "mips" | "mips64" => MIPS_WHITELIST,
         "powerpc" | "powerpc64" => POWERPC_WHITELIST,
-        // wasm32 on emscripten does not support these target features
-        "wasm32" if !sess.target.target.options.is_like_emscripten => WASM_WHITELIST,
+        "wasm32" => WASM_WHITELIST,
         _ => &[],
     }
 }
diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml
index c7d09a423d5..6992f93d999 100644
--- a/src/librustc_codegen_ssa/Cargo.toml
+++ b/src/librustc_codegen_ssa/Cargo.toml
@@ -21,6 +21,7 @@ tempfile = "3.1"
 
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc = { path = "../librustc" }
 rustc_apfloat = { path = "../librustc_apfloat" }
diff --git a/src/librustc_codegen_ssa/README.md b/src/librustc_codegen_ssa/README.md
index c8bb2e7ee99..a09a0c22c1b 100644
--- a/src/librustc_codegen_ssa/README.md
+++ b/src/librustc_codegen_ssa/README.md
@@ -84,7 +84,7 @@ pub trait BuilderMethods<'a, 'tcx>:
 {
     fn new_block<'b>(
         cx: &'a Self::CodegenCx,
-        llfn: Self::Value,
+        llfn: Self::Function,
         name: &'b str
     ) -> Self;
     /* ... */
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index 9078f77f1f7..d866a10f069 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -14,7 +14,7 @@ use rustc::ty::query::Providers;
 use rustc::ty::subst::SubstsRef;
 use rustc::util::nodemap::{FxHashMap, DefIdMap};
 use rustc_index::vec::IndexVec;
-use syntax::ext::allocator::ALLOCATOR_METHODS;
+use syntax_expand::allocator::ALLOCATOR_METHODS;
 
 pub type ExportedSymbols = FxHashMap<
     CrateNum,
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 481db26e1a8..762b50f1659 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -22,11 +22,12 @@ use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry};
 use rustc::util::profiling::SelfProfilerRef;
 use rustc_fs_util::link_or_copy;
 use rustc_data_structures::svh::Svh;
-use rustc_errors::{Handler, Level, FatalError, DiagnosticId};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Handler, Level, FatalError, DiagnosticId, SourceMapperDyn};
 use rustc_errors::emitter::{Emitter};
 use rustc_target::spec::MergeFunctions;
 use syntax::attr;
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::hygiene::ExpnId;
 use syntax_pos::symbol::{Symbol, sym};
 use jobserver::{Client, Acquired};
 
@@ -142,15 +143,12 @@ impl ModuleConfig {
         // Copy what clang does by turning on loop vectorization at O2 and
         // slp vectorization at O3. Otherwise configure other optimization aspects
         // of this pass manager builder.
-        // Turn off vectorization for emscripten, as it's not very well supported.
         self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
                              (sess.opts.optimize == config::OptLevel::Default ||
-                              sess.opts.optimize == config::OptLevel::Aggressive) &&
-                             !sess.target.target.options.is_like_emscripten;
+                              sess.opts.optimize == config::OptLevel::Aggressive);
 
         self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
-                            sess.opts.optimize == config::OptLevel::Aggressive &&
-                            !sess.target.target.options.is_like_emscripten;
+                            sess.opts.optimize == config::OptLevel::Aggressive;
 
         // Some targets (namely, NVPTX) interact badly with the MergeFunctions
         // pass. This is because MergeFunctions can generate new function calls
@@ -261,7 +259,7 @@ fn generate_lto_work<B: ExtraBackendMethods>(
     needs_thin_lto: Vec<(String, B::ThinBuffer)>,
     import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>
 ) -> Vec<(WorkItem<B>, u64)> {
-    let _prof_timer = cgcx.prof.generic_activity("codegen_run_lto");
+    let _prof_timer = cgcx.prof.generic_activity("codegen_generate_lto_work");
 
     let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() {
         assert!(needs_thin_lto.is_empty());
@@ -676,11 +674,11 @@ impl<B: WriteBackendMethods> WorkItem<B> {
         }
     }
 
-    pub fn name(&self) -> String {
+    fn profiling_event_id(&self) -> &'static str {
         match *self {
-            WorkItem::Optimize(ref m) => format!("optimize: {}", m.name),
-            WorkItem::CopyPostLtoArtifacts(ref m) => format!("copy post LTO artifacts: {}", m.name),
-            WorkItem::LTO(ref m) => format!("lto: {}", m.name()),
+            WorkItem::Optimize(_) => "codegen_module_optimize",
+            WorkItem::CopyPostLtoArtifacts(_) => "codegen_copy_artifacts_from_incr_cache",
+            WorkItem::LTO(_) => "codegen_module_perform_lto",
         }
     }
 }
@@ -1589,7 +1587,7 @@ fn spawn_work<B: ExtraBackendMethods>(
         // as a diagnostic was already sent off to the main thread - just
         // surface that there was an error in this worker.
         bomb.result = {
-            let _prof_timer = cgcx.prof.generic_activity(&work.name());
+            let _prof_timer = cgcx.prof.generic_activity(work.profiling_event_id());
             execute_work_item(&cgcx, work).ok()
         };
     });
@@ -1666,13 +1664,13 @@ impl SharedEmitter {
 }
 
 impl Emitter for SharedEmitter {
-    fn emit_diagnostic(&mut self, db: &rustc_errors::Diagnostic) {
+    fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
         drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
-            msg: db.message(),
-            code: db.code.clone(),
-            lvl: db.level,
+            msg: diag.message(),
+            code: diag.code.clone(),
+            lvl: diag.level,
         })));
-        for child in &db.children {
+        for child in &diag.children {
             drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
                 msg: child.message(),
                 code: None,
@@ -1681,6 +1679,9 @@ impl Emitter for SharedEmitter {
         }
         drop(self.sender.send(SharedEmitterMessage::AbortIfErrors));
     }
+    fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
+        None
+    }
 }
 
 impl SharedEmitterMain {
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index 935087714a7..e8ffe868231 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -36,7 +36,6 @@ use crate::mir::place::PlaceRef;
 use crate::back::write::{OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm,
     submit_post_lto_module_to_llvm};
 use crate::{MemFlags, CrateInfo};
-use crate::callee;
 use crate::common::{RealPredicate, TypeKind, IntPredicate};
 use crate::meth;
 use crate::mir;
@@ -169,12 +168,6 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
             (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
         }
-        (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
-            let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty());
-            assert!(bx.cx().type_is_sized(a));
-            let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
-            (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
-        }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
 
@@ -197,6 +190,8 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             }
             let (lldata, llextra) = result.unwrap();
             // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
+            // FIXME(eddyb) move these out of this `match` arm, so they're always
+            // applied, uniformly, no matter the source/destination types.
             (bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true)),
              bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true)))
         }
@@ -213,31 +208,27 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ) {
     let src_ty = src.layout.ty;
     let dst_ty = dst.layout.ty;
-    let mut coerce_ptr = || {
-        let (base, info) = match bx.load_operand(src).val {
-            OperandValue::Pair(base, info) => {
-                // fat-ptr to fat-ptr unsize preserves the vtable
-                // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
-                // So we need to pointercast the base to ensure
-                // the types match up.
-                let thin_ptr = dst.layout.field(bx.cx(), FAT_PTR_ADDR);
-                (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
-            }
-            OperandValue::Immediate(base) => {
-                unsize_thin_ptr(bx, base, src_ty, dst_ty)
-            }
-            OperandValue::Ref(..) => bug!()
-        };
-        OperandValue::Pair(base, info).store(bx, dst);
-    };
     match (&src_ty.kind, &dst_ty.kind) {
         (&ty::Ref(..), &ty::Ref(..)) |
         (&ty::Ref(..), &ty::RawPtr(..)) |
         (&ty::RawPtr(..), &ty::RawPtr(..)) => {
-            coerce_ptr()
-        }
-        (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
-            coerce_ptr()
+            let (base, info) = match bx.load_operand(src).val {
+                OperandValue::Pair(base, info) => {
+                    // fat-ptr to fat-ptr unsize preserves the vtable
+                    // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
+                    // So we need to pointercast the base to ensure
+                    // the types match up.
+                    // FIXME(eddyb) use `scalar_pair_element_backend_type` here,
+                    // like `unsize_thin_ptr` does.
+                    let thin_ptr = dst.layout.field(bx.cx(), FAT_PTR_ADDR);
+                    (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
+                }
+                OperandValue::Immediate(base) => {
+                    unsize_thin_ptr(bx, base, src_ty, dst_ty)
+                }
+                OperandValue::Ref(..) => bug!()
+            };
+            OperandValue::Pair(base, info).store(bx, dst);
         }
 
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
@@ -377,8 +368,7 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
     let sig = instance.fn_sig(cx.tcx());
     let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
 
-    let lldecl = cx.instances().borrow().get(&instance).cloned().unwrap_or_else(||
-        bug!("Instance `{:?}` not already declared", instance));
+    let lldecl = cx.get_fn(instance);
 
     let mir = cx.tcx().instance_mir(instance.def);
     mir::codegen_mir::<Bx>(cx, lldecl, &mir, instance, sig);
@@ -400,7 +390,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
         return;
     }
 
-    let main_llfn = cx.get_fn(instance);
+    let main_llfn = cx.get_fn_addr(instance);
 
     let et = cx.tcx().entry_fn(LOCAL_CRATE).map(|e| e.1);
     match et {
@@ -416,8 +406,13 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
         rust_main_def_id: DefId,
         use_start_lang_item: bool,
     ) {
-        let llfty =
-            cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int());
+        // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
+        // depending on whether the target needs `argc` and `argv` to be passed in.
+        let llfty = if cx.sess().target.target.options.main_needs_argc_argv {
+            cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
+        } else {
+            cx.type_func(&[], cx.type_int())
+        };
 
         let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).output();
         // Given that `main()` has no arguments,
@@ -447,18 +442,17 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
 
         bx.insert_reference_to_gdb_debug_scripts_section_global();
 
-        // Params from native main() used as args for rust start function
-        let param_argc = bx.get_param(0);
-        let param_argv = bx.get_param(1);
-        let arg_argc = bx.intcast(param_argc, cx.type_isize(), true);
-        let arg_argv = param_argv;
+        let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
 
         let (start_fn, args) = if use_start_lang_item {
             let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None);
-            let start_fn = callee::resolve_and_get_fn(
-                cx,
-                start_def_id,
-                cx.tcx().intern_substs(&[main_ret_ty.into()]),
+            let start_fn = cx.get_fn_addr(
+                ty::Instance::resolve(
+                    cx.tcx(),
+                    ty::ParamEnv::reveal_all(),
+                    start_def_id,
+                    cx.tcx().intern_substs(&[main_ret_ty.into()]),
+                ).unwrap()
             );
             (start_fn, vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())),
                             arg_argc, arg_argv])
@@ -473,6 +467,27 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
     }
 }
 
+/// Obtain the `argc` and `argv` values to pass to the rust start function.
+fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    cx: &'a Bx::CodegenCx,
+    bx: &mut Bx
+) -> (Bx::Value, Bx::Value)
+{
+    if cx.sess().target.target.options.main_needs_argc_argv {
+        // Params from native `main()` used as args for rust start function
+        let param_argc = bx.get_param(0);
+        let param_argv = bx.get_param(1);
+        let arg_argc = bx.intcast(param_argc, cx.type_isize(), true);
+        let arg_argv = param_argv;
+        (arg_argc, arg_argv)
+    } else {
+        // The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
+        let arg_argc = bx.const_int(cx.type_int(), 0);
+        let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p()));
+        (arg_argc, arg_argv)
+    }
+}
+
 pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
 
 pub fn codegen_crate<B: ExtraBackendMethods>(
diff --git a/src/librustc_codegen_ssa/callee.rs b/src/librustc_codegen_ssa/callee.rs
deleted file mode 100644
index 6ba6774cbf8..00000000000
--- a/src/librustc_codegen_ssa/callee.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use crate::traits::*;
-use rustc::ty;
-use rustc::ty::subst::SubstsRef;
-use rustc::hir::def_id::DefId;
-
-pub fn resolve_and_get_fn<'tcx, Cx: CodegenMethods<'tcx>>(
-    cx: &Cx,
-    def_id: DefId,
-    substs: SubstsRef<'tcx>,
-) -> Cx::Value {
-    cx.get_fn(
-        ty::Instance::resolve(
-            cx.tcx(),
-            ty::ParamEnv::reveal_all(),
-            def_id,
-            substs
-        ).unwrap()
-    )
-}
-
-pub fn resolve_and_get_fn_for_ptr<'tcx,
-    Cx: Backend<'tcx> + MiscMethods<'tcx> + TypeMethods<'tcx>
->(
-    cx: &Cx,
-    def_id: DefId,
-    substs: SubstsRef<'tcx>,
-) -> Cx::Value {
-    cx.get_fn(
-        ty::Instance::resolve_for_fn_ptr(
-            cx.tcx(),
-            ty::ParamEnv::reveal_all(),
-            def_id,
-            substs
-        ).unwrap()
-    )
-}
-
-pub fn resolve_and_get_fn_for_vtable<'tcx,
-    Cx: Backend<'tcx> + MiscMethods<'tcx> + TypeMethods<'tcx>
->(
-    cx: &Cx,
-    def_id: DefId,
-    substs: SubstsRef<'tcx>,
-) -> Cx::Value {
-    cx.get_fn(
-        ty::Instance::resolve_for_vtable(
-            cx.tcx(),
-            ty::ParamEnv::reveal_all(),
-            def_id,
-            substs
-        ).unwrap()
-    )
-}
diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs
index e3aa35ef4eb..ac39ca98476 100644
--- a/src/librustc_codegen_ssa/common.rs
+++ b/src/librustc_codegen_ssa/common.rs
@@ -1,6 +1,7 @@
 #![allow(non_camel_case_types, non_snake_case)]
 
 use rustc::ty::{Ty, TyCtxt};
+use rustc::session::Session;
 use syntax_pos::Span;
 
 use rustc::hir::def_id::DefId;
@@ -200,3 +201,7 @@ pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
     }
 }
+
+pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
+    span_err!(a, b, E0511, "{}", c);
+}
diff --git a/src/librustc_codegen_ssa/error_codes.rs b/src/librustc_codegen_ssa/error_codes.rs
index 8ff41c275a8..02e26d8f6ec 100644
--- a/src/librustc_codegen_ssa/error_codes.rs
+++ b/src/librustc_codegen_ssa/error_codes.rs
@@ -1,5 +1,40 @@
 syntax::register_diagnostics! {
 
+E0511: r##"
+Invalid monomorphization of an intrinsic function was used. Erroneous code
+example:
+
+```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
+#![feature(platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_add<T>(a: T, b: T) -> T;
+}
+
+fn main() {
+    unsafe { simd_add(0, 1); }
+    // error: invalid monomorphization of `simd_add` intrinsic
+}
+```
+
+The generic type has to be a SIMD type. Example:
+
+```
+#![feature(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct i32x2(i32, i32);
+
+extern "platform-intrinsic" {
+    fn simd_add<T>(a: T, b: T) -> T;
+}
+
+unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
+```
+"##,
+
 E0668: r##"
 Malformed inline assembly rejected by LLVM.
 
diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs
index d700001430e..0221a04b045 100644
--- a/src/librustc_codegen_ssa/lib.rs
+++ b/src/librustc_codegen_ssa/lib.rs
@@ -27,6 +27,7 @@ use rustc::dep_graph::WorkProduct;
 use rustc::session::config::{OutputFilenames, OutputType};
 use rustc::middle::lang_items::LangItem;
 use rustc::hir::def_id::CrateNum;
+use rustc::ty::query::Providers;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::svh::Svh;
@@ -41,7 +42,6 @@ pub mod traits;
 pub mod mir;
 pub mod debuginfo;
 pub mod base;
-pub mod callee;
 pub mod glue;
 pub mod meth;
 pub mod mono_item;
@@ -156,3 +156,13 @@ pub struct CodegenResults {
     pub linker_info: back::linker::LinkerInfo,
     pub crate_info: CrateInfo,
 }
+
+pub fn provide(providers: &mut Providers<'_>) {
+    crate::back::symbol_export::provide(providers);
+    crate::base::provide_both(providers);
+}
+
+pub fn provide_extern(providers: &mut Providers<'_>) {
+    crate::back::symbol_export::provide_extern(providers);
+    crate::base::provide_both(providers);
+}
diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs
index 7fe9f5f2513..266d2e5b18d 100644
--- a/src/librustc_codegen_ssa/meth.rs
+++ b/src/librustc_codegen_ssa/meth.rs
@@ -1,6 +1,5 @@
 use rustc_target::abi::call::FnType;
 
-use crate::callee;
 use crate::traits::*;
 
 use rustc::ty::{self, Ty, Instance};
@@ -92,7 +91,14 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
 
     let methods = methods.cloned().map(|opt_mth| {
         opt_mth.map_or(nullptr, |(def_id, substs)| {
-            callee::resolve_and_get_fn_for_vtable(cx, def_id, substs)
+            cx.get_fn_addr(
+                ty::Instance::resolve_for_vtable(
+                    cx.tcx(),
+                    ty::ParamEnv::reveal_all(),
+                    def_id,
+                    substs,
+                ).unwrap()
+            )
         })
     });
 
@@ -102,7 +108,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     // `get_vtable` in rust_mir/interpret/traits.rs
     // /////////////////////////////////////////////////////////////////////////////////////////////
     let components: Vec<_> = [
-        cx.get_fn(Instance::resolve_drop_in_place(cx.tcx(), ty)),
+        cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
         cx.const_usize(layout.size.bytes()),
         cx.const_usize(layout.align.abi.bytes())
     ].iter().cloned().chain(methods).collect();
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index b0df81ba1ab..dc77d025c00 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -358,7 +358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty)
             }
             _ => {
-                (bx.get_fn(drop_fn),
+                (bx.get_fn_addr(drop_fn),
                  FnType::of_instance(&bx, drop_fn))
             }
         };
@@ -460,7 +460,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
         let instance = ty::Instance::mono(bx.tcx(), def_id);
         let fn_ty = FnType::of_instance(&bx, instance);
-        let llfn = bx.get_fn(instance);
+        let llfn = bx.get_fn_addr(instance);
 
         // Codegen the actual panic invoke/call.
         helper.do_call(self, &mut bx, fn_ty, llfn, &args, None, cleanup);
@@ -576,7 +576,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
                 let fn_ty = FnType::of_instance(&bx, instance);
-                let llfn = bx.get_fn(instance);
+                let llfn = bx.get_fn_addr(instance);
 
                 if let Some((_, target)) = destination.as_ref() {
                     helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
@@ -793,7 +793,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let fn_ptr = match (llfn, instance) {
             (Some(llfn), _) => llfn,
-            (None, Some(instance)) => bx.get_fn(instance),
+            (None, Some(instance)) => bx.get_fn_addr(instance),
             _ => span_bug!(span, "no llfn for call"),
         };
 
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index d5612d7b072..1a2e796a5b7 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -30,7 +30,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
 
     debug_context: FunctionDebugContext<Bx::DIScope>,
 
-    llfn: Bx::Value,
+    llfn: Bx::Function,
 
     cx: &'a Bx::CodegenCx,
 
@@ -183,7 +183,7 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> {
 
 pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
-    llfn: Bx::Value,
+    llfn: Bx::Function,
     mir: &'a Body<'tcx>,
     instance: Instance<'tcx>,
     sig: ty::FnSig<'tcx>,
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index daa25b2ea05..ba5e47aeede 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -79,6 +79,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
             ConstValue::Unevaluated(..) => bug!("unevaluated constant in `OperandRef::from_const`"),
             ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"),
             ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"),
+            ConstValue::Bound(..) => bug!("encountered a ConstValue::Bound in codegen"),
             ConstValue::Placeholder(_) => bug!("encountered a ConstValue::Placeholder in codegen"),
             ConstValue::Scalar(x) => {
                 let scalar = match layout.abi {
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 2d97f828f07..1d1bc2a81a2 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -394,8 +394,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         // Statically compute the offset if we can, otherwise just use the element size,
         // as this will yield the lowest alignment.
         let layout = self.layout.field(bx, 0);
-        let offset = if bx.is_const_integral(llindex) {
-            layout.size.checked_mul(bx.const_to_uint(llindex), bx).unwrap_or(layout.size)
+        let offset = if let Some(llindex) = bx.const_to_opt_uint(llindex) {
+            layout.size.checked_mul(llindex, bx).unwrap_or(layout.size)
         } else {
             layout.size
         };
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 978e7218aa7..7e662ea37db 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -10,7 +10,6 @@ use syntax::source_map::{DUMMY_SP, Span};
 
 use crate::base;
 use crate::MemFlags;
-use crate::callee;
 use crate::common::{self, RealPredicate, IntPredicate};
 
 use crate::traits::*;
@@ -95,7 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let size = bx.const_usize(dest.layout.size.bytes());
 
                     // Use llvm.memset.p0i8.* to initialize all zero arrays
-                    if bx.cx().is_const_integral(v) && bx.cx().const_to_uint(v) == 0 {
+                    if bx.cx().const_to_opt_uint(v) == Some(0) {
                         let fill = bx.cx().const_u8(0);
                         bx.memset(start, fill, size, dest.align, MemFlags::empty());
                         return bx;
@@ -190,7 +189,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     bug!("reifying a fn ptr that requires const arguments");
                                 }
                                 OperandValue::Immediate(
-                                    callee::resolve_and_get_fn_for_ptr(bx.cx(), def_id, substs))
+                                    bx.get_fn_addr(
+                                        ty::Instance::resolve_for_fn_ptr(
+                                            bx.tcx(),
+                                            ty::ParamEnv::reveal_all(),
+                                            def_id,
+                                            substs
+                                        ).unwrap()
+                                    )
+                                )
                             }
                             _ => {
                                 bug!("{} cannot be reified to a fn ptr", operand.layout.ty)
@@ -205,7 +212,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     def_id,
                                     substs,
                                     ty::ClosureKind::FnOnce);
-                                OperandValue::Immediate(bx.cx().get_fn(instance))
+                                OperandValue::Immediate(bx.cx().get_fn_addr(instance))
                             }
                             _ => {
                                 bug!("{} cannot be cast to a fn ptr", operand.layout.ty)
@@ -488,7 +495,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                 };
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let r = bx.cx().get_fn(instance);
+                let r = bx.cx().get_fn_addr(instance);
                 let call = bx.call(r, &[llsize, llalign], None);
                 let val = bx.pointercast(call, llty_ptr);
 
@@ -549,7 +556,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> Bx::Value {
         let is_float = input_ty.is_floating_point();
         let is_signed = input_ty.is_signed();
-        let is_unit = input_ty.is_unit();
         match op {
             mir::BinOp::Add => if is_float {
                 bx.fadd(lhs, rhs)
@@ -587,13 +593,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs),
             mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs),
             mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt |
-            mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_unit {
-                bx.cx().const_bool(match op {
-                    mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false,
-                    mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true,
-                    _ => unreachable!()
-                })
-            } else if is_float {
+            mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_float {
                 bx.fcmp(
                     base::bin_op_to_fcmp_predicate(op.to_hir_binop()),
                     lhs, rhs
diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs
index cb197f51460..7cae3e9ade5 100644
--- a/src/librustc_codegen_ssa/traits/backend.rs
+++ b/src/librustc_codegen_ssa/traits/backend.rs
@@ -9,11 +9,13 @@ use rustc::ty::TyCtxt;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use std::sync::Arc;
 use std::sync::mpsc;
-use syntax::ext::allocator::AllocatorKind;
+use syntax_expand::allocator::AllocatorKind;
 use syntax_pos::symbol::InternedString;
 
 pub trait BackendTypes {
     type Value: CodegenObject;
+    type Function: CodegenObject;
+
     type BasicBlock: Copy;
     type Type: CodegenObject;
     type Funclet;
diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs
index 1886701fb3a..62b5bcbb6c9 100644
--- a/src/librustc_codegen_ssa/traits/builder.rs
+++ b/src/librustc_codegen_ssa/traits/builder.rs
@@ -34,7 +34,7 @@ pub trait BuilderMethods<'a, 'tcx>:
     + HasTargetSpec
 
 {
-    fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
+    fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Function, name: &'b str) -> Self;
     fn with_cx(cx: &'a Self::CodegenCx) -> Self;
     fn build_sibling_block(&self, name: &str) -> Self;
     fn cx(&self) -> &Self::CodegenCx;
diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/src/librustc_codegen_ssa/traits/consts.rs
index e7ce03f1836..95ada60fae0 100644
--- a/src/librustc_codegen_ssa/traits/consts.rs
+++ b/src/librustc_codegen_ssa/traits/consts.rs
@@ -21,11 +21,9 @@ pub trait ConstMethods<'tcx>: BackendTypes {
 
     fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
 
-    fn const_to_uint(&self, v: Self::Value) -> u64;
+    fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
     fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
 
-    fn is_const_integral(&self, v: Self::Value) -> bool;
-
     fn scalar_to_backend(
         &self,
         cv: Scalar,
diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs
index e75f247da96..989e6cf9dca 100644
--- a/src/librustc_codegen_ssa/traits/debuginfo.rs
+++ b/src/librustc_codegen_ssa/traits/debuginfo.rs
@@ -20,7 +20,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
         &self,
         instance: Instance<'tcx>,
         sig: ty::FnSig<'tcx>,
-        llfn: Self::Value,
+        llfn: Self::Function,
         mir: &mir::Body<'_>,
     ) -> FunctionDebugContext<Self::DIScope>;
 
diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs
index 624a982b619..cd42044e48d 100644
--- a/src/librustc_codegen_ssa/traits/declare.rs
+++ b/src/librustc_codegen_ssa/traits/declare.rs
@@ -17,13 +17,13 @@ pub trait DeclareMethods<'tcx>: BackendTypes {
     ///
     /// If there’s a value with the same name already declared, the function will
     /// update the declaration and return existing Value instead.
-    fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Value;
+    fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Function;
 
     /// Declare a Rust function.
     ///
     /// If there’s a value with the same name already declared, the function will
     /// update the declaration and return existing Value instead.
-    fn declare_fn(&self, name: &str, sig: ty::PolyFnSig<'tcx>) -> Self::Value;
+    fn declare_fn(&self, name: &str, sig: ty::PolyFnSig<'tcx>) -> Self::Function;
 
     /// Declare a global with an intention to define it.
     ///
diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/src/librustc_codegen_ssa/traits/misc.rs
index 46c88a6113e..658ddd00280 100644
--- a/src/librustc_codegen_ssa/traits/misc.rs
+++ b/src/librustc_codegen_ssa/traits/misc.rs
@@ -11,14 +11,14 @@ pub trait MiscMethods<'tcx>: BackendTypes {
         &self,
     ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>;
     fn check_overflow(&self) -> bool;
-    fn instances(&self) -> &RefCell<FxHashMap<Instance<'tcx>, Self::Value>>;
-    fn get_fn(&self, instance: Instance<'tcx>) -> Self::Value;
+    fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function;
+    fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value;
     fn eh_personality(&self) -> Self::Value;
     fn eh_unwind_resume(&self) -> Self::Value;
     fn sess(&self) -> &Session;
     fn codegen_unit(&self) -> &Arc<CodegenUnit<'tcx>>;
     fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
-    fn set_frame_pointer_elimination(&self, llfn: Self::Value);
-    fn apply_target_cpu_attr(&self, llfn: Self::Value);
+    fn set_frame_pointer_elimination(&self, llfn: Self::Function);
+    fn apply_target_cpu_attr(&self, llfn: Self::Function);
     fn create_used_variable(&self);
 }
diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs
index efe4a255701..4318ef16494 100644
--- a/src/librustc_codegen_ssa/traits/mod.rs
+++ b/src/librustc_codegen_ssa/traits/mod.rs
@@ -88,6 +88,7 @@ pub trait HasCodegen<'tcx>:
     type CodegenCx: CodegenMethods<'tcx>
         + BackendTypes<
             Value = Self::Value,
+            Function = Self::Function,
             BasicBlock = Self::BasicBlock,
             Type = Self::Type,
             Funclet = Self::Funclet,
diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs
index 2e3af8431ee..1077c1f4263 100644
--- a/src/librustc_codegen_utils/codegen_backend.rs
+++ b/src/librustc_codegen_utils/codegen_backend.rs
@@ -25,7 +25,6 @@ pub trait CodegenBackend {
     fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
     fn print_passes(&self) {}
     fn print_version(&self) {}
-    fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] }
 
     fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync>;
     fn provide(&self, _providers: &mut Providers<'_>);
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index 1201446afb5..66920342ff6 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -18,6 +18,7 @@
 extern crate rustc;
 
 use rustc::ty::TyCtxt;
+use rustc::ty::query::Providers;
 use rustc::hir::def_id::LOCAL_CRATE;
 use syntax::symbol::sym;
 
@@ -37,3 +38,7 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
         }
     }
 }
+
+pub fn provide(providers: &mut Providers<'_>) {
+    crate::symbol_names::provide(providers);
+}
diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs
index c438a8558a7..9fdcea6df88 100644
--- a/src/librustc_data_structures/graph/implementation/mod.rs
+++ b/src/librustc_data_structures/graph/implementation/mod.rs
@@ -60,10 +60,10 @@ impl<N> SnapshotVecDelegate for Edge<N> {
     fn reverse(_: &mut Vec<Edge<N>>, _: ()) {}
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub struct NodeIndex(pub usize);
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Copy, Clone, PartialEq, Debug)]
 pub struct EdgeIndex(pub usize);
 
 pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX);
diff --git a/src/librustc_data_structures/sharded.rs b/src/librustc_data_structures/sharded.rs
index 31cb22098b8..2f972eeccdc 100644
--- a/src/librustc_data_structures/sharded.rs
+++ b/src/librustc_data_structures/sharded.rs
@@ -2,6 +2,7 @@ use std::hash::{Hasher, Hash};
 use std::mem;
 use std::borrow::Borrow;
 use std::collections::hash_map::RawEntryMut;
+use smallvec::SmallVec;
 use crate::fx::{FxHasher, FxHashMap};
 use crate::sync::{Lock, LockGuard};
 
@@ -18,7 +19,7 @@ const SHARD_BITS: usize = 5;
 #[cfg(not(parallel_compiler))]
 const SHARD_BITS: usize = 0;
 
-const SHARDS: usize = 1 << SHARD_BITS;
+pub const SHARDS: usize = 1 << SHARD_BITS;
 
 /// An array of cache-line aligned inner locked structures with convenience methods.
 #[derive(Clone)]
@@ -29,21 +30,36 @@ pub struct Sharded<T> {
 impl<T: Default> Default for Sharded<T> {
     #[inline]
     fn default() -> Self {
+        Self::new(|| T::default())
+    }
+}
+
+impl<T> Sharded<T> {
+    #[inline]
+    pub fn new(mut value: impl FnMut() -> T) -> Self {
+        // Create a vector of the values we want
+        let mut values: SmallVec<[_; SHARDS]> = (0..SHARDS).map(|_| {
+            CacheAligned(Lock::new(value()))
+        }).collect();
+
+        // Create an unintialized array
         let mut shards: mem::MaybeUninit<[CacheAligned<Lock<T>>; SHARDS]> =
             mem::MaybeUninit::uninit();
-        let first = shards.as_mut_ptr() as *mut CacheAligned<Lock<T>>;
+
         unsafe {
-            for i in 0..SHARDS {
-                first.add(i).write(CacheAligned(Lock::new(T::default())));
-            }
+            // Copy the values into our array
+            let first = shards.as_mut_ptr() as *mut CacheAligned<Lock<T>>;
+            values.as_ptr().copy_to_nonoverlapping(first, SHARDS);
+
+            // Ignore the content of the vector
+            values.set_len(0);
+
             Sharded {
                 shards: shards.assume_init(),
             }
         }
     }
-}
 
-impl<T> Sharded<T> {
     #[inline]
     pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
         if SHARDS == 1 {
@@ -74,7 +90,7 @@ impl<T> Sharded<T> {
 
 pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;
 
-impl<K: Eq + Hash, V> ShardedHashMap<K, V> {
+impl<K: Eq, V> ShardedHashMap<K, V> {
     pub fn len(&self) -> usize {
         self.lock_shards().iter().map(|shard| shard.len()).sum()
     }
diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs
index ce0aa07cc28..bdd3dc96656 100644
--- a/src/librustc_data_structures/snapshot_map/mod.rs
+++ b/src/librustc_data_structures/snapshot_map/mod.rs
@@ -7,7 +7,7 @@ use std::mem;
 mod tests;
 
 pub struct SnapshotMap<K, V>
-    where K: Hash + Clone + Eq
+    where K: Clone + Eq
 {
     map: FxHashMap<K, V>,
     undo_log: Vec<UndoLog<K, V>>,
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index ee4f6a5e785..092208cfe1d 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -169,7 +169,7 @@ pub trait HashStable<CTX> {
 /// example, for DefId that can be converted to a DefPathHash. This is used for
 /// bringing maps into a predictable order before hashing them.
 pub trait ToStableHashKey<HCX> {
-    type KeyType: Ord + Clone + Sized + HashStable<HCX>;
+    type KeyType: Ord + Sized + HashStable<HCX>;
     fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
 }
 
@@ -460,7 +460,7 @@ impl_stable_hash_via_hash!(::std::path::Path);
 impl_stable_hash_via_hash!(::std::path::PathBuf);
 
 impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
-    where K: ToStableHashKey<HCX> + Eq + Hash,
+    where K: ToStableHashKey<HCX> + Eq,
           V: HashStable<HCX>,
           R: BuildHasher,
 {
@@ -471,7 +471,7 @@ impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
 }
 
 impl<K, R, HCX> HashStable<HCX> for ::std::collections::HashSet<K, R>
-    where K: ToStableHashKey<HCX> + Eq + Hash,
+    where K: ToStableHashKey<HCX> + Eq,
           R: BuildHasher,
 {
     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
@@ -513,10 +513,10 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
     hasher: &mut StableHasher,
     map: &::std::collections::HashMap<K, V, R>,
     to_stable_hash_key: F)
-    where K: Eq + Hash,
+    where K: Eq,
           V: HashStable<HCX>,
           R: BuildHasher,
-          SK: HashStable<HCX> + Ord + Clone,
+          SK: HashStable<HCX> + Ord,
           F: Fn(&K, &HCX) -> SK,
 {
     let mut entries: Vec<_> = map.iter()
diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs
index 3277b85c281..f09474ff4d3 100644
--- a/src/librustc_data_structures/sync.rs
+++ b/src/librustc_data_structures/sync.rs
@@ -1,6 +1,6 @@
 //! This module defines types which are thread safe if cfg!(parallel_compiler) is true.
 //!
-//! `Lrc` is an alias of either Rc or Arc.
+//! `Lrc` is an alias of `Arc` if cfg!(parallel_compiler) is true, `Rc` otherwise.
 //!
 //! `Lock` is a mutex.
 //! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true,
@@ -12,7 +12,7 @@
 //!
 //! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false.
 //!
-//! `MTRef` is a immutable reference if cfg!(parallel_compiler), and an mutable reference otherwise.
+//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise.
 //!
 //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync
 //! depending on the value of cfg!(parallel_compiler).
@@ -23,29 +23,6 @@ use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 use crate::owning_ref::{Erased, OwningRef};
 
-pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
-    where A: FnOnce() -> RA,
-          B: FnOnce() -> RB
-{
-    (oper_a(), oper_b())
-}
-
-pub struct SerialScope;
-
-impl SerialScope {
-    pub fn spawn<F>(&self, f: F)
-        where F: FnOnce(&SerialScope)
-    {
-        f(self)
-    }
-}
-
-pub fn serial_scope<F, R>(f: F) -> R
-    where F: FnOnce(&SerialScope) -> R
-{
-    f(&SerialScope)
-}
-
 pub use std::sync::atomic::Ordering::SeqCst;
 pub use std::sync::atomic::Ordering;
 
@@ -176,8 +153,28 @@ cfg_if! {
         pub type AtomicU32 = Atomic<u32>;
         pub type AtomicU64 = Atomic<u64>;
 
-        pub use self::serial_join as join;
-        pub use self::serial_scope as scope;
+        pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+            where A: FnOnce() -> RA,
+                  B: FnOnce() -> RB
+        {
+            (oper_a(), oper_b())
+        }
+
+        pub struct SerialScope;
+
+        impl SerialScope {
+            pub fn spawn<F>(&self, f: F)
+                where F: FnOnce(&SerialScope)
+            {
+                f(self)
+            }
+        }
+
+        pub fn scope<F, R>(f: F) -> R
+            where F: FnOnce(&SerialScope) -> R
+        {
+            f(&SerialScope)
+        }
 
         #[macro_export]
         macro_rules! parallel {
@@ -741,7 +738,7 @@ impl<T: Clone> Clone for RwLock<T> {
 
 /// A type which only allows its inner value to be used in one thread.
 /// It will panic if it is used on multiple threads.
-#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)]
+#[derive(Debug)]
 pub struct OneThread<T> {
     #[cfg(parallel_compiler)]
     thread: thread::ThreadId,
diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs
index 93a8b7f525f..d97da489db8 100644
--- a/src/librustc_data_structures/thin_vec.rs
+++ b/src/librustc_data_structures/thin_vec.rs
@@ -3,7 +3,7 @@ use crate::stable_hasher::{StableHasher, HashStable};
 /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`).
 /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
 /// which uses only a single (null) pointer.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct ThinVec<T>(Option<Box<Vec<T>>>);
 
 impl<T> ThinVec<T> {
diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs
index ea771d9f20f..371f0f6fa0b 100644
--- a/src/librustc_data_structures/tiny_list.rs
+++ b/src/librustc_data_structures/tiny_list.rs
@@ -14,7 +14,7 @@
 #[cfg(test)]
 mod tests;
 
-#[derive(Clone, Hash, Debug, PartialEq)]
+#[derive(Clone)]
 pub struct TinyList<T: PartialEq> {
     head: Option<Element<T>>
 }
@@ -80,7 +80,7 @@ impl<T: PartialEq> TinyList<T> {
     }
 }
 
-#[derive(Clone, Hash, Debug, PartialEq)]
+#[derive(Clone)]
 struct Element<T: PartialEq> {
     data: T,
     next: Option<Box<Element<T>>>,
diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs
index f0a9c3afc68..a3926c15551 100644
--- a/src/librustc_data_structures/transitive_relation.rs
+++ b/src/librustc_data_structures/transitive_relation.rs
@@ -11,7 +11,7 @@ use std::mem;
 mod tests;
 
 #[derive(Clone, Debug)]
-pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash> {
+pub struct TransitiveRelation<T: Eq + Hash> {
     // List of elements. This is used to map from a T to a usize.
     elements: Vec<T>,
 
@@ -35,7 +35,7 @@ pub struct TransitiveRelation<T: Clone + Debug + Eq + Hash> {
 }
 
 // HACK(eddyb) manual impl avoids `Default` bound on `T`.
-impl<T: Clone + Debug + Eq + Hash> Default for TransitiveRelation<T> {
+impl<T: Eq + Hash> Default for TransitiveRelation<T> {
     fn default() -> Self {
         TransitiveRelation {
             elements: Default::default(),
@@ -46,7 +46,7 @@ impl<T: Clone + Debug + Eq + Hash> Default for TransitiveRelation<T> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, RustcEncodable, RustcDecodable, Debug)]
 struct Index(usize);
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index dd088b68a23..bfcbec8b78f 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -166,7 +166,8 @@ pub fn run_compiler(
         None => return Ok(()),
     };
 
-    let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+    let sopts = config::build_session_options(&matches);
+    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
 
     let mut dummy_config = |sopts, cfg, diagnostic_output| {
         let mut config = interface::Config {
@@ -615,7 +616,7 @@ impl RustcDefaultCalls {
                     let mut v = Vec::new();
                     locator::list_file_metadata(&sess.target.target,
                                                 path,
-                                                &*cstore.metadata_loader,
+                                                cstore,
                                                 &mut v)
                             .unwrap();
                     println!("{}", String::from_utf8(v).unwrap());
diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs
index 0281d10fd93..491bc2aa6a2 100644
--- a/src/librustc_errors/annotate_snippet_emitter_writer.rs
+++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs
@@ -31,24 +31,28 @@ pub struct AnnotateSnippetEmitterWriter {
 
 impl Emitter for AnnotateSnippetEmitterWriter {
     /// The entry point for the diagnostics generation
-    fn emit_diagnostic(&mut self, db: &Diagnostic) {
-        let mut children = db.children.clone();
-        let (mut primary_span, suggestions) = self.primary_span_formatted(&db);
+    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+        let mut children = diag.children.clone();
+        let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);
 
         self.fix_multispans_in_std_macros(&self.source_map,
                                           &mut primary_span,
                                           &mut children,
-                                          &db.level,
+                                          &diag.level,
                                           self.external_macro_backtrace);
 
-        self.emit_messages_default(&db.level,
-                                   db.message(),
-                                   &db.code,
+        self.emit_messages_default(&diag.level,
+                                   diag.message(),
+                                   &diag.code,
                                    &primary_span,
                                    &children,
                                    &suggestions);
     }
 
+    fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
+        self.source_map.as_ref()
+    }
+
     fn should_show_explain(&self) -> bool {
         !self.short_message
     }
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 68f933363da..e3b55a14133 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -12,8 +12,8 @@ use Destination::*;
 use syntax_pos::{SourceFile, Span, MultiSpan};
 
 use crate::{
-    Level, CodeSuggestion, Diagnostic, SubDiagnostic,
-    SuggestionStyle, SourceMapperDyn, DiagnosticId,
+    Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralise,
+    SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId,
 };
 use crate::Level::Error;
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
@@ -180,7 +180,7 @@ const ANONYMIZED_LINE_NUM: &str = "LL";
 /// Emitter trait for emitting errors.
 pub trait Emitter {
     /// Emit a structured diagnostic.
-    fn emit_diagnostic(&mut self, db: &Diagnostic);
+    fn emit_diagnostic(&mut self, diag: &Diagnostic);
 
     /// Emit a notification that an artifact has been output.
     /// This is currently only supported for the JSON format,
@@ -192,6 +192,8 @@ pub trait Emitter {
         true
     }
 
+    fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>>;
+
     /// Formats the substitutions of the primary_span
     ///
     /// The are a lot of conditions to this method, but in short:
@@ -204,10 +206,10 @@ pub trait Emitter {
     ///   we return the original `primary_span` and the original suggestions.
     fn primary_span_formatted<'a>(
         &mut self,
-        db: &'a Diagnostic
+        diag: &'a Diagnostic,
     ) -> (MultiSpan, &'a [CodeSuggestion]) {
-        let mut primary_span = db.span.clone();
-        if let Some((sugg, rest)) = db.suggestions.split_first() {
+        let mut primary_span = diag.span.clone();
+        if let Some((sugg, rest)) = diag.suggestions.split_first() {
             if rest.is_empty() &&
                // ^ if there is only one suggestion
                // don't display multi-suggestions as labels
@@ -234,7 +236,20 @@ pub trait Emitter {
                     format!("help: {}", sugg.msg)
                 } else {
                     // Show the default suggestion text with the substitution
-                    format!("help: {}: `{}`", sugg.msg, substitution)
+                    format!(
+                        "help: {}{}: `{}`",
+                        sugg.msg,
+                        if self.source_map().map(|sm| is_case_difference(
+                            &**sm,
+                            substitution,
+                            sugg.substitutions[0].parts[0].span,
+                        )).unwrap_or(false) {
+                            " (notice the capitalization)"
+                        } else {
+                            ""
+                        },
+                        substitution,
+                    )
                 };
                 primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg);
 
@@ -245,10 +260,10 @@ pub trait Emitter {
                 // to be consistent. We could try to figure out if we can
                 // make one (or the first one) inline, but that would give
                 // undue importance to a semi-random suggestion
-                (primary_span, &db.suggestions)
+                (primary_span, &diag.suggestions)
             }
         } else {
-            (primary_span, &db.suggestions)
+            (primary_span, &diag.suggestions)
         }
     }
 
@@ -382,19 +397,23 @@ pub trait Emitter {
 }
 
 impl Emitter for EmitterWriter {
-    fn emit_diagnostic(&mut self, db: &Diagnostic) {
-        let mut children = db.children.clone();
-        let (mut primary_span, suggestions) = self.primary_span_formatted(&db);
+    fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
+        self.sm.as_ref()
+    }
+
+    fn emit_diagnostic(&mut self, diag: &Diagnostic) {
+        let mut children = diag.children.clone();
+        let (mut primary_span, suggestions) = self.primary_span_formatted(&diag);
 
         self.fix_multispans_in_std_macros(&self.sm,
                                           &mut primary_span,
                                           &mut children,
-                                          &db.level,
+                                          &diag.level,
                                           self.external_macro_backtrace);
 
-        self.emit_messages_default(&db.level,
-                                   &db.styled_message(),
-                                   &db.code,
+        self.emit_messages_default(&diag.level,
+                                   &diag.styled_message(),
+                                   &diag.code,
                                    &primary_span,
                                    &children,
                                    &suggestions);
@@ -1461,7 +1480,9 @@ impl EmitterWriter {
         let suggestions = suggestion.splice_lines(&**sm);
 
         let mut row_num = 2;
-        for &(ref complete, ref parts) in suggestions.iter().take(MAX_SUGGESTIONS) {
+        let mut notice_capitalization = false;
+        for (complete, parts, only_capitalization) in suggestions.iter().take(MAX_SUGGESTIONS) {
+            notice_capitalization |= only_capitalization;
             // Only show underline if the suggestion spans a single line and doesn't cover the
             // entirety of the code output. If you have multiple replacements in the same line
             // of code, show the underline.
@@ -1551,8 +1572,12 @@ impl EmitterWriter {
             }
         }
         if suggestions.len() > MAX_SUGGESTIONS {
-            let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
-            buffer.puts(row_num, 0, &msg, Style::NoStyle);
+            let others = suggestions.len() - MAX_SUGGESTIONS;
+            let msg = format!("and {} other candidate{}", others, pluralise!(others));
+            buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
+        } else if notice_capitalization {
+            let msg = "notice the capitalization difference";
+            buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
         }
         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
         Ok(())
@@ -2034,3 +2059,18 @@ impl<'a> Drop for WritableDst<'a> {
         }
     }
 }
+
+/// Whether the original and suggested code are visually similar enough to warrant extra wording.
+pub fn is_case_difference(sm: &dyn SourceMapper, suggested: &str, sp: Span) -> bool {
+    // FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
+    let found = sm.span_to_snippet(sp).unwrap();
+    let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
+    // All the chars that differ in capitalization are confusable (above):
+    let confusable = found.chars().zip(suggested.chars()).filter(|(f, s)| f != s).all(|(f, s)| {
+        (ascii_confusables.contains(&f) || ascii_confusables.contains(&s))
+    });
+    confusable && found.to_lowercase() == suggested.to_lowercase()
+            // FIXME: We sometimes suggest the same thing we already have, which is a
+            //        bug, but be defensive against that here.
+            && found != suggested
+}
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 2fae584c153..63df052a225 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -13,7 +13,7 @@ pub use emitter::ColorConfig;
 
 use Level::*;
 
-use emitter::{Emitter, EmitterWriter};
+use emitter::{Emitter, EmitterWriter, is_case_difference};
 use registry::Registry;
 
 use rustc_data_structures::sync::{self, Lrc, Lock};
@@ -37,13 +37,16 @@ pub mod registry;
 mod styled_buffer;
 mod lock;
 
-use syntax_pos::{BytePos,
-                 Loc,
-                 FileLinesResult,
-                 SourceFile,
-                 FileName,
-                 MultiSpan,
-                 Span};
+use syntax_pos::{
+    BytePos,
+    FileLinesResult,
+    FileName,
+    Loc,
+    MultiSpan,
+    SourceFile,
+    Span,
+    SpanSnippetError,
+};
 
 /// Indicates the confidence in the correctness of a suggestion.
 ///
@@ -147,6 +150,7 @@ pub trait SourceMapper {
     fn lookup_char_pos(&self, pos: BytePos) -> Loc;
     fn span_to_lines(&self, sp: Span) -> FileLinesResult;
     fn span_to_string(&self, sp: Span) -> String;
+    fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError>;
     fn span_to_filename(&self, sp: Span) -> FileName;
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
     fn call_span_if_macro(&self, sp: Span) -> Span;
@@ -155,9 +159,12 @@ pub trait SourceMapper {
 }
 
 impl CodeSuggestion {
-    /// Returns the assembled code suggestions and whether they should be shown with an underline.
-    pub fn splice_lines(&self, cm: &SourceMapperDyn)
-                        -> Vec<(String, Vec<SubstitutionPart>)> {
+    /// Returns the assembled code suggestions, whether they should be shown with an underline
+    /// and whether the substitution only differs in capitalization.
+    pub fn splice_lines(
+        &self,
+        cm: &SourceMapperDyn,
+    ) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
         use syntax_pos::{CharPos, Pos};
 
         fn push_trailing(buf: &mut String,
@@ -232,6 +239,7 @@ impl CodeSuggestion {
                 prev_hi = cm.lookup_char_pos(part.span.hi());
                 prev_line = fm.get_line(prev_hi.line - 1);
             }
+            let only_capitalization = is_case_difference(cm, &buf, bounding_span);
             // if the replacement already ends with a newline, don't print the next line
             if !buf.ends_with('\n') {
                 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
@@ -240,7 +248,7 @@ impl CodeSuggestion {
             while buf.ends_with('\n') {
                 buf.pop();
             }
-            (buf, substitution.parts)
+            (buf, substitution.parts, only_capitalization)
         }).collect()
     }
 }
diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs
index 8c49e0dde0d..9ed5ef5a539 100644
--- a/src/librustc_index/bit_set.rs
+++ b/src/librustc_index/bit_set.rs
@@ -13,8 +13,9 @@ pub type Word = u64;
 pub const WORD_BYTES: usize = mem::size_of::<Word>();
 pub const WORD_BITS: usize = WORD_BYTES * 8;
 
-/// A fixed-size bitset type with a dense representation. It does not support
-/// resizing after creation; use `GrowableBitSet` for that.
+/// A fixed-size bitset type with a dense representation.
+///
+/// NOTE: Use [`GrowableBitSet`] if you need support for resizing after creation.
 ///
 /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
 /// just be `usize`.
@@ -22,6 +23,8 @@ pub const WORD_BITS: usize = WORD_BYTES * 8;
 /// All operations that involve an element will panic if the element is equal
 /// to or greater than the domain size. All operations that involve two bitsets
 /// will panic if the bitsets have differing domain sizes.
+///
+/// [`GrowableBitSet`]: struct.GrowableBitSet.html
 #[derive(Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
 pub struct BitSet<T: Idx> {
     domain_size: usize,
@@ -168,11 +171,7 @@ impl<T: Idx> BitSet<T> {
     /// Iterates over the indices of set bits in a sorted order.
     #[inline]
     pub fn iter(&self) -> BitIter<'_, T> {
-        BitIter {
-            cur: None,
-            iter: self.words.iter().enumerate(),
-            marker: PhantomData,
-        }
+        BitIter::new(&self.words)
     }
 
     /// Duplicates the set as a hybrid set.
@@ -291,26 +290,55 @@ impl<T: Idx> ToString for BitSet<T> {
 }
 
 pub struct BitIter<'a, T: Idx> {
-    cur: Option<(Word, usize)>,
-    iter: iter::Enumerate<slice::Iter<'a, Word>>,
+    /// A copy of the current word, but with any already-visited bits cleared.
+    /// (This lets us use `trailing_zeros()` to find the next set bit.) When it
+    /// is reduced to 0, we move onto the next word.
+    word: Word,
+
+    /// The offset (measured in bits) of the current word.
+    offset: usize,
+
+    /// Underlying iterator over the words.
+    iter: slice::Iter<'a, Word>,
+
     marker: PhantomData<T>
 }
 
+impl<'a, T: Idx> BitIter<'a, T> {
+    #[inline]
+    fn new(words: &'a [Word]) -> BitIter<'a, T> {
+        // We initialize `word` and `offset` to degenerate values. On the first
+        // call to `next()` we will fall through to getting the first word from
+        // `iter`, which sets `word` to the first word (if there is one) and
+        // `offset` to 0. Doing it this way saves us from having to maintain
+        // additional state about whether we have started.
+        BitIter {
+            word: 0,
+            offset: std::usize::MAX - (WORD_BITS - 1),
+            iter: words.iter(),
+            marker: PhantomData,
+        }
+    }
+}
+
 impl<'a, T: Idx> Iterator for BitIter<'a, T> {
     type Item = T;
     fn next(&mut self) -> Option<T> {
         loop {
-            if let Some((ref mut word, offset)) = self.cur {
-                let bit_pos = word.trailing_zeros() as usize;
-                if bit_pos != WORD_BITS {
-                    let bit = 1 << bit_pos;
-                    *word ^= bit;
-                    return Some(T::new(bit_pos + offset))
-                }
+            if self.word != 0 {
+                // Get the position of the next set bit in the current word,
+                // then clear the bit.
+                let bit_pos = self.word.trailing_zeros() as usize;
+                let bit = 1 << bit_pos;
+                self.word ^= bit;
+                return Some(T::new(bit_pos + self.offset))
             }
 
-            let (i, word) = self.iter.next()?;
-            self.cur = Some((*word, WORD_BITS * i));
+            // Move onto the next word. `wrapping_add()` is needed to handle
+            // the degenerate initial value given to `offset` in `new()`.
+            let word = self.iter.next()?;
+            self.word = *word;
+            self.offset = self.offset.wrapping_add(WORD_BITS);
         }
     }
 }
@@ -851,11 +879,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
     pub fn iter(&self, row: R) -> BitIter<'_, C> {
         assert!(row.index() < self.num_rows);
         let (start, end) = self.range(row);
-        BitIter {
-            cur: None,
-            iter: self.words[start..end].iter().enumerate(),
-            marker: PhantomData,
-        }
+        BitIter::new(&self.words[start..end])
     }
 
     /// Returns the number of elements in `row`.
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index bed5febb72e..0d8d765a572 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -15,6 +15,7 @@ rayon = { version = "0.3.0", package = "rustc-rayon" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 rustc = { path = "../librustc" }
@@ -26,6 +27,7 @@ rustc_codegen_utils = { path = "../librustc_codegen_utils" }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_passes = { path = "../librustc_passes" }
+rustc_target = { path = "../librustc_target" }
 rustc_typeck = { path = "../librustc_typeck" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_errors = { path = "../librustc_errors" }
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index b26bd75c974..5e1ad3e61dd 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -3,7 +3,8 @@ use crate::util;
 pub use crate::passes::BoxedResolver;
 
 use rustc::lint;
-use rustc::session::config::{self, Input};
+use rustc::session::early_error;
+use rustc::session::config::{self, Input, ErrorOutputType};
 use rustc::session::{DiagnosticOutput, Session};
 use rustc::util::common::ErrorReported;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
@@ -14,9 +15,13 @@ use rustc_metadata::cstore::CStore;
 use std::path::PathBuf;
 use std::result;
 use std::sync::{Arc, Mutex};
-use syntax;
-use syntax::source_map::{FileLoader, SourceMap};
+use syntax::{self, parse};
+use syntax::ast::{self, MetaItemKind};
+use syntax::parse::token;
+use syntax::source_map::{FileName, FilePathMapping, FileLoader, SourceMap};
+use syntax::sess::ParseSess;
 use syntax_pos::edition;
+use rustc_errors::{Diagnostic, emitter::Emitter, Handler, SourceMapperDyn};
 
 pub type Result<T> = result::Result<T, ErrorReported>;
 
@@ -60,6 +65,58 @@ impl Compiler {
     }
 }
 
+/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
+pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
+    struct NullEmitter;
+    impl Emitter for NullEmitter {
+        fn emit_diagnostic(&mut self, _: &Diagnostic) {}
+        fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> { None }
+    }
+
+    syntax::with_default_globals(move || {
+        let cfg = cfgspecs.into_iter().map(|s| {
+
+            let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+            let handler = Handler::with_emitter(false, None, Box::new(NullEmitter));
+            let sess = ParseSess::with_span_handler(handler, cm);
+            let filename = FileName::cfg_spec_source_code(&s);
+            let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string());
+
+            macro_rules! error {($reason: expr) => {
+                early_error(ErrorOutputType::default(),
+                            &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
+            }}
+
+            match &mut parser.parse_meta_item() {
+                Ok(meta_item) if parser.token == token::Eof => {
+                    if meta_item.path.segments.len() != 1 {
+                        error!("argument key must be an identifier");
+                    }
+                    match &meta_item.kind {
+                        MetaItemKind::List(..) => {
+                            error!(r#"expected `key` or `key="value"`"#);
+                        }
+                        MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
+                            error!("argument value must be a string");
+                        }
+                        MetaItemKind::NameValue(..) | MetaItemKind::Word => {
+                            let ident = meta_item.ident().expect("multi-segment cfg key");
+                            return (ident.name, meta_item.value_str());
+                        }
+                    }
+                }
+                Ok(..) => {}
+                Err(err) => err.cancel(),
+            }
+
+            error!(r#"expected `key` or `key="value"`"#);
+        }).collect::<ast::CrateConfig>();
+        cfg.into_iter().map(|(a, b)| {
+            (a.to_string(), b.map(|b| b.to_string()))
+        }).collect()
+    })
+}
+
 /// The compiler configuration
 pub struct Config {
     /// Command line options
diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index 6be36e9b900..53baf6556fb 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -18,3 +18,6 @@ pub mod util;
 mod proc_macro_decls;
 
 pub use interface::{run_compiler, Config};
+
+#[cfg(test)]
+mod tests;
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index a1dc5b01aba..89de5714695 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -35,7 +35,7 @@ use rustc_traits;
 use rustc_typeck as typeck;
 use syntax::{self, ast, visit};
 use syntax::early_buffered_lints::BufferedEarlyLint;
-use syntax::ext::base::{NamedSyntaxExtension, ExtCtxt};
+use syntax_expand::base::{NamedSyntaxExtension, ExtCtxt};
 use syntax::mut_visit::MutVisitor;
 use syntax::parse::{self, PResult};
 use syntax::util::node_count::NodeCounter;
@@ -130,7 +130,7 @@ pub fn configure_and_expand(
     let crate_name = crate_name.to_string();
     let (result, resolver) = BoxedResolver::new(static move || {
         let sess = &*sess;
-        let mut crate_loader = CrateLoader::new(sess, &*cstore, &crate_name);
+        let crate_loader = CrateLoader::new(sess, &*cstore, &crate_name);
         let resolver_arenas = Resolver::arenas();
         let res = configure_and_expand_inner(
             sess,
@@ -138,7 +138,7 @@ pub fn configure_and_expand(
             krate,
             &crate_name,
             &resolver_arenas,
-            &mut crate_loader,
+            &crate_loader,
             plugin_info,
         );
         let mut resolver = match res {
@@ -169,6 +169,7 @@ impl ExpansionResult {
         ExpansionResult {
             defs: Steal::new(resolver.definitions),
             resolutions: Steal::new(Resolutions {
+                extern_crate_map: resolver.extern_crate_map,
                 export_map: resolver.export_map,
                 trait_map: resolver.trait_map,
                 glob_map: resolver.glob_map,
@@ -187,6 +188,7 @@ impl ExpansionResult {
         ExpansionResult {
             defs: Steal::new(resolver.definitions.clone()),
             resolutions: Steal::new(Resolutions {
+                extern_crate_map: resolver.extern_crate_map.clone(),
                 export_map: resolver.export_map.clone(),
                 trait_map: resolver.trait_map.clone(),
                 glob_map: resolver.glob_map.clone(),
@@ -319,7 +321,7 @@ fn configure_and_expand_inner<'a>(
     mut krate: ast::Crate,
     crate_name: &str,
     resolver_arenas: &'a ResolverArenas<'a>,
-    crate_loader: &'a mut CrateLoader<'a>,
+    crate_loader: &'a CrateLoader<'a>,
     plugin_info: PluginInfo,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
     time(sess, "pre-AST-expansion lint checks", || {
@@ -395,12 +397,12 @@ fn configure_and_expand_inner<'a>(
 
         // Create the config for macro expansion
         let features = sess.features_untracked();
-        let cfg = syntax::ext::expand::ExpansionConfig {
+        let cfg = syntax_expand::expand::ExpansionConfig {
             features: Some(&features),
             recursion_limit: *sess.recursion_limit.get(),
             trace_mac: sess.opts.debugging_opts.trace_macros,
             should_test: sess.opts.test,
-            ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
+            ..syntax_expand::expand::ExpansionConfig::default(crate_name.to_string())
         };
 
         let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
@@ -541,7 +543,8 @@ pub fn lower_to_hir(
 ) -> Result<hir::map::Forest> {
     // Lower AST to HIR.
     let hir_forest = time(sess, "lowering AST -> HIR", || {
-        let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver);
+        let nt_to_tokenstream = syntax::parse::nt_to_tokenstream;
+        let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, resolver, nt_to_tokenstream);
 
         if sess.opts.debugging_opts.hir_stats {
             hir_stats::print_hir_stats(&hir_crate);
@@ -556,7 +559,7 @@ pub fn lower_to_hir(
 
     // Discard hygiene data, which isn't required after lowering to HIR.
     if !sess.opts.debugging_opts.keep_hygiene_data {
-        syntax::ext::hygiene::clear_syntax_context_map();
+        syntax_expand::hygiene::clear_syntax_context_map();
     }
 
     Ok(hir_forest)
@@ -662,16 +665,15 @@ fn write_out_deps(compiler: &Compiler, outputs: &OutputFilenames, out_filenames:
 
         if sess.binary_dep_depinfo() {
             for cnum in compiler.cstore.crates_untracked() {
-                let metadata = compiler.cstore.crate_data_as_rc_any(cnum);
-                let metadata = metadata.downcast_ref::<cstore::CrateMetadata>().unwrap();
-                if let Some((path, _)) = &metadata.source.dylib {
-                    files.push(escape_dep_filename(&FileName::Real(path.clone())));
+                let source = compiler.cstore.crate_source_untracked(cnum);
+                if let Some((path, _)) = source.dylib {
+                    files.push(escape_dep_filename(&FileName::Real(path)));
                 }
-                if let Some((path, _)) = &metadata.source.rlib {
-                    files.push(escape_dep_filename(&FileName::Real(path.clone())));
+                if let Some((path, _)) = source.rlib {
+                    files.push(escape_dep_filename(&FileName::Real(path)));
                 }
-                if let Some((path, _)) = &metadata.source.rmeta {
-                    files.push(escape_dep_filename(&FileName::Real(path.clone())));
+                if let Some((path, _)) = source.rmeta {
+                    files.push(escape_dep_filename(&FileName::Real(path)));
                 }
             }
         }
@@ -789,10 +791,13 @@ pub fn default_provide(providers: &mut ty::query::Providers<'_>) {
     cstore::provide(providers);
     lint::provide(providers);
     rustc_lint::provide(providers);
+    rustc_codegen_utils::provide(providers);
+    rustc_codegen_ssa::provide(providers);
 }
 
 pub fn default_provide_extern(providers: &mut ty::query::Providers<'_>) {
     cstore::provide_extern(providers);
+    rustc_codegen_ssa::provide_extern(providers);
 }
 
 declare_box_region_type!(
diff --git a/src/librustc/session/config/tests.rs b/src/librustc_interface/tests.rs
index c117418f636..7a57605da58 100644
--- a/src/librustc/session/config/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -1,40 +1,51 @@
-use getopts;
-use crate::lint;
-use crate::middle::cstore;
-use crate::session::config::{
-    build_configuration,
-    build_session_options_and_crate_config,
-    to_crate_config
-};
-use crate::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
-use crate::session::build_session;
-use crate::session::search_paths::SearchPath;
+extern crate getopts;
+
+use crate::interface::parse_cfgspecs;
+
+use rustc::lint;
+use rustc::middle::cstore;
+use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
+use rustc::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry};
+use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
+use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes};
+use rustc::session::build_session;
+use rustc::session::search_paths::SearchPath;
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
 use std::path::PathBuf;
-use super::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
 use syntax::symbol::sym;
 use syntax::edition::{Edition, DEFAULT_EDITION};
 use syntax;
-use super::Options;
-
-impl ExternEntry {
-    fn new_public<S: Into<String>,
-                  I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry {
-        let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
-            .collect();
-
-        ExternEntry {
-            locations,
-            is_private_dep: false
-        }
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{ColorConfig, emitter::HumanReadableErrorType, registry};
+
+pub fn build_session_options_and_crate_config(
+    matches: &getopts::Matches,
+) -> (Options, FxHashSet<(String, Option<String>)>) {
+    (
+        build_session_options(matches),
+        parse_cfgspecs(matches.opt_strs("cfg")),
+    )
+}
+
+fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
+where
+    S: Into<String>,
+    I: IntoIterator<Item = Option<S>>,
+{
+    let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
+        .collect();
+
+    ExternEntry {
+        locations,
+        is_private_dep: false
     }
 }
 
 fn optgroups() -> getopts::Options {
     let mut opts = getopts::Options::new();
-    for group in super::rustc_optgroups() {
+    for group in rustc_optgroups() {
         (group.apply)(&mut opts);
     }
     return opts;
@@ -52,7 +63,7 @@ fn test_switch_implies_cfg_test() {
             Ok(m) => m,
             Err(f) => panic!("test_switch_implies_cfg_test: {}", f),
         };
-        let registry = errors::registry::Registry::new(&[]);
+        let registry = registry::Registry::new(&[]);
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
         let sess = build_session(sessopts, None, registry);
         let cfg = build_configuration(&sess, to_crate_config(cfg));
@@ -70,7 +81,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
             Ok(m) => m,
             Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f),
         };
-        let registry = errors::registry::Registry::new(&[]);
+        let registry = registry::Registry::new(&[]);
         let (sessopts, cfg) = build_session_options_and_crate_config(matches);
         let sess = build_session(sessopts, None, registry);
         let cfg = build_configuration(&sess, to_crate_config(cfg));
@@ -84,7 +95,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
 fn test_can_print_warnings() {
     syntax::with_default_globals(|| {
         let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
-        let registry = errors::registry::Registry::new(&[]);
+        let registry = registry::Registry::new(&[]);
         let (sessopts, _) = build_session_options_and_crate_config(&matches);
         let sess = build_session(sessopts, None, registry);
         assert!(!sess.diagnostic().can_emit_warnings());
@@ -94,7 +105,7 @@ fn test_can_print_warnings() {
         let matches = optgroups()
             .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()])
             .unwrap();
-        let registry = errors::registry::Registry::new(&[]);
+        let registry = registry::Registry::new(&[]);
         let (sessopts, _) = build_session_options_and_crate_config(&matches);
         let sess = build_session(sessopts, None, registry);
         assert!(sess.diagnostic().can_emit_warnings());
@@ -102,7 +113,7 @@ fn test_can_print_warnings() {
 
     syntax::with_default_globals(|| {
         let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
-        let registry = errors::registry::Registry::new(&[]);
+        let registry = registry::Registry::new(&[]);
         let (sessopts, _) = build_session_options_and_crate_config(&matches);
         let sess = build_session(sessopts, None, registry);
         assert!(sess.diagnostic().can_emit_warnings());
@@ -161,33 +172,33 @@ fn test_externs_tracking_hash_different_construction_order() {
     v1.externs = Externs::new(mk_map(vec![
         (
             String::from("a"),
-            ExternEntry::new_public(vec![Some("b"), Some("c")])
+            new_public_extern_entry(vec![Some("b"), Some("c")])
         ),
         (
             String::from("d"),
-            ExternEntry::new_public(vec![Some("e"), Some("f")])
+            new_public_extern_entry(vec![Some("e"), Some("f")])
         ),
     ]));
 
     v2.externs = Externs::new(mk_map(vec![
         (
             String::from("d"),
-            ExternEntry::new_public(vec![Some("e"), Some("f")])
+            new_public_extern_entry(vec![Some("e"), Some("f")])
         ),
         (
             String::from("a"),
-            ExternEntry::new_public(vec![Some("b"), Some("c")])
+            new_public_extern_entry(vec![Some("b"), Some("c")])
         ),
     ]));
 
     v3.externs = Externs::new(mk_map(vec![
         (
             String::from("a"),
-            ExternEntry::new_public(vec![Some("b"), Some("c")])
+            new_public_extern_entry(vec![Some("b"), Some("c")])
         ),
         (
             String::from("d"),
-            ExternEntry::new_public(vec![Some("f"), Some("e")])
+            new_public_extern_entry(vec![Some("f"), Some("e")])
         ),
     ]));
 
@@ -271,9 +282,9 @@ fn test_search_paths_tracking_hash_different_order() {
     let mut v3 = Options::default();
     let mut v4 = Options::default();
 
-    const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
+    const JSON: ErrorOutputType = ErrorOutputType::Json {
         pretty: false,
-        json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
+        json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
     };
 
     // Reference
@@ -444,7 +455,7 @@ fn test_codegen_options_tracking_hash() {
     opts.cg.codegen_units = Some(42);
     assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
 
-    opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
+    opts.cg.remark = Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
     assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
 
     opts.cg.save_temps = true;
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index d0a7eab071c..5d9a97cc21e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -45,7 +45,7 @@ use syntax::feature_gate::{Stability, deprecated_attributes};
 use syntax_pos::{BytePos, Span};
 use syntax::symbol::{Symbol, kw, sym};
 use syntax::errors::{Applicability, DiagnosticBuilder};
-use syntax::print::pprust::expr_to_string;
+use syntax::print::pprust::{self, expr_to_string};
 use syntax::visit::FnKind;
 
 use rustc::hir::{self, GenericParamKind, PatKind};
@@ -701,7 +701,8 @@ impl EarlyLintPass for DeprecatedAttr {
             }
         }
         if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
-            let msg = format!("use of deprecated attribute `{}`: no longer used.", attr.path);
+            let path_str = pprust::path_to_string(&attr.path);
+            let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
             lint_deprecated_attr(cx, attr, &msg, None);
         }
     }
@@ -980,35 +981,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
 }
 
 declare_lint! {
-    UNIONS_WITH_DROP_FIELDS,
-    Warn,
-    "use of unions that contain fields with possibly non-trivial drop code"
-}
-
-declare_lint_pass!(
-    /// Lint for unions that contain fields with possibly non-trivial destructors.
-    UnionsWithDropFields => [UNIONS_WITH_DROP_FIELDS]
-);
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields {
-    fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) {
-        if let hir::ItemKind::Union(ref vdata, _) = item.kind {
-            for field in vdata.fields() {
-                let field_ty = ctx.tcx.type_of(
-                    ctx.tcx.hir().local_def_id(field.hir_id));
-                if field_ty.needs_drop(ctx.tcx, ctx.param_env) {
-                    ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
-                                  field.span,
-                                  "union contains a field with possibly non-trivial drop code, \
-                                   drop code of union fields is ignored when dropping the union");
-                    return;
-                }
-            }
-        }
-    }
-}
-
-declare_lint! {
     pub UNREACHABLE_PUB,
     Allow,
     "`pub` items not reachable from crate root"
@@ -1240,7 +1212,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
         if cx.tcx.features().trivial_bounds {
             let def_id = cx.tcx.hir().local_def_id(item.hir_id);
             let predicates = cx.tcx.predicates_of(def_id);
-            for &(predicate, span) in &predicates.predicates {
+            for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate {
                     Trait(..) => "Trait",
                     TypeOutlives(..) |
@@ -1287,7 +1259,6 @@ declare_lint_pass!(
         NO_MANGLE_GENERIC_ITEMS,
         MUTABLE_TRANSMUTES,
         UNSTABLE_FEATURES,
-        UNIONS_WITH_DROP_FIELDS,
         UNREACHABLE_PUB,
         TYPE_ALIAS_BOUNDS,
         TRIVIAL_BOUNDS
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 0e054013cd7..f83755181f8 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -164,9 +164,6 @@ macro_rules! late_lint_mod_passes {
             // Depends on referenced function signatures in expressions
             MutableTransmutes: MutableTransmutes,
 
-            // Depends on types of fields, checks if they implement Drop
-            UnionsWithDropFields: UnionsWithDropFields,
-
             TypeAliasBounds: TypeAliasBounds,
 
             TrivialConstraints: TrivialConstraints,
@@ -255,6 +252,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                     UNUSED_MUT,
                     UNREACHABLE_CODE,
                     UNREACHABLE_PATTERNS,
+                    OVERLAPPING_PATTERNS,
                     UNUSED_MUST_USE,
                     UNUSED_UNSAFE,
                     PATH_STATEMENTS,
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 3b3995832cb..a93946df68f 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -156,7 +156,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
                 }
                 ty::Opaque(def, _) => {
                     let mut has_emitted = false;
-                    for (predicate, _) in &cx.tcx.predicates_of(def).predicates {
+                    for (predicate, _) in cx.tcx.predicates_of(def).predicates {
                         if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
                             let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
                             let def_id = trait_ref.def_id;
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index 032470e1400..18192e35f8a 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -22,4 +22,5 @@ rustc_index = { path = "../librustc_index" }
 rustc_serialize = { path = "../libserialize", package = "serialize" }
 stable_deref_trait = "1.0.0"
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 50a2187c937..7412e8a2cb9 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -1,6 +1,6 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::cstore::{self, CStore, CrateSource, MetadataBlob};
+use crate::cstore::{self, CStore, MetadataBlob};
 use crate::locator::{self, CratePaths};
 use crate::schema::{CrateRoot, CrateDep};
 use rustc_data_structures::sync::{Lrc, RwLock, Lock, AtomicCell};
@@ -14,7 +14,7 @@ use rustc::session::{Session, CrateDisambiguator};
 use rustc::session::config::{Sanitizer, self};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 use rustc::session::search_paths::PathKind;
-use rustc::middle::cstore::{ExternCrate, ExternCrateSource};
+use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource};
 use rustc::util::common::record_time;
 use rustc::util::nodemap::FxHashSet;
 use rustc::hir::map::Definitions;
@@ -26,22 +26,20 @@ use std::{cmp, fs};
 
 use syntax::ast;
 use syntax::attr;
-use syntax::ext::allocator::{global_allocator_spans, AllocatorKind};
+use syntax_expand::allocator::{global_allocator_spans, AllocatorKind};
 use syntax::symbol::{Symbol, sym};
 use syntax::{span_err, span_fatal};
 use syntax_pos::{Span, DUMMY_SP};
 use log::{debug, info, log_enabled};
 use proc_macro::bridge::client::ProcMacro;
 
-pub struct Library {
-    pub dylib: Option<(PathBuf, PathKind)>,
-    pub rlib: Option<(PathBuf, PathKind)>,
-    pub rmeta: Option<(PathBuf, PathKind)>,
+crate struct Library {
+    pub source: CrateSource,
     pub metadata: MetadataBlob,
 }
 
 pub struct CrateLoader<'a> {
-    pub sess: &'a Session,
+    sess: &'a Session,
     cstore: &'a CStore,
     local_crate_name: Symbol,
 }
@@ -189,7 +187,7 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn register_crate(
-        &mut self,
+        &self,
         host_lib: Option<Library>,
         root: Option<&CratePaths>,
         span: Span,
@@ -197,10 +195,10 @@ impl<'a> CrateLoader<'a> {
         dep_kind: DepKind,
         name: Symbol
     ) -> (CrateNum, Lrc<cstore::CrateMetadata>) {
-        let _prof_timer =
-            self.sess.prof.generic_activity("metadata_register_crate");
+        let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
 
-        let crate_root = lib.metadata.get_root();
+        let Library { source, metadata } = lib;
+        let crate_root = metadata.get_root();
         self.verify_no_symbol_conflicts(span, &crate_root);
 
         let private_dep = self.sess.opts.externs.get(&name.as_str())
@@ -218,28 +216,22 @@ impl<'a> CrateLoader<'a> {
         let root = if let Some(root) = root {
             root
         } else {
-            crate_paths = CratePaths {
-                ident: crate_root.name.to_string(),
-                dylib: lib.dylib.clone().map(|p| p.0),
-                rlib:  lib.rlib.clone().map(|p| p.0),
-                rmeta: lib.rmeta.clone().map(|p| p.0),
-            };
+            crate_paths = CratePaths { name: crate_root.name, source: source.clone() };
             &crate_paths
         };
 
-        let Library { dylib, rlib, rmeta, metadata } = lib;
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
         let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
 
         let raw_proc_macros =  crate_root.proc_macro_data.map(|_| {
             let temp_root;
-            let (dlsym_dylib, dlsym_root) = match &host_lib {
+            let (dlsym_source, dlsym_root) = match &host_lib {
                 Some(host_lib) =>
-                    (&host_lib.dylib, { temp_root = host_lib.metadata.get_root(); &temp_root }),
-                None => (&dylib, &crate_root),
+                    (&host_lib.source, { temp_root = host_lib.metadata.get_root(); &temp_root }),
+                None => (&source, &crate_root),
             };
-            let dlsym_dylib = dlsym_dylib.as_ref().expect("no dylib for a proc-macro crate");
+            let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
             self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator, span)
         });
 
@@ -268,13 +260,8 @@ impl<'a> CrateLoader<'a> {
             source_map_import_info: RwLock::new(vec![]),
             alloc_decoding_state: AllocDecodingState::new(interpret_alloc_index),
             dep_kind: Lock::new(dep_kind),
-            source: cstore::CrateSource {
-                dylib,
-                rlib,
-                rmeta,
-            },
+            source,
             private_dep,
-            span,
             raw_proc_macros,
             dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
         };
@@ -285,7 +272,7 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn load_proc_macro<'b>(
-        &mut self,
+        &self,
         locate_ctxt: &mut locator::Context<'b>,
         path_kind: PathKind,
     ) -> Option<(LoadResult, Option<Library>)>
@@ -340,7 +327,7 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn resolve_crate<'b>(
-        &'b mut self,
+        &'b self,
         name: Symbol,
         span: Span,
         dep_kind: DepKind,
@@ -350,7 +337,7 @@ impl<'a> CrateLoader<'a> {
     }
 
     fn maybe_resolve_crate<'b>(
-        &'b mut self,
+        &'b self,
         name: Symbol,
         span: Span,
         mut dep_kind: DepKind,
@@ -410,7 +397,7 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn load(&mut self, locate_ctxt: &mut locator::Context<'_>) -> Option<LoadResult> {
+    fn load(&self, locate_ctxt: &mut locator::Context<'_>) -> Option<LoadResult> {
         let library = locate_ctxt.maybe_load_library_crate()?;
 
         // In the case that we're loading a crate, but not matching
@@ -437,7 +424,7 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn update_extern_crate(&mut self,
+    fn update_extern_crate(&self,
                            cnum: CrateNum,
                            mut extern_crate: ExternCrate,
                            visited: &mut FxHashSet<(CrateNum, bool)>)
@@ -479,7 +466,7 @@ impl<'a> CrateLoader<'a> {
     }
 
     // Go through the crate metadata and load any crates that it references
-    fn resolve_crate_deps(&mut self,
+    fn resolve_crate_deps(&self,
                           root: &CratePaths,
                           crate_root: &CrateRoot<'_>,
                           metadata: &MetadataBlob,
@@ -509,7 +496,7 @@ impl<'a> CrateLoader<'a> {
         })).collect()
     }
 
-    fn read_extension_crate(&mut self, name: Symbol, span: Span) -> ExtensionCrate {
+    fn read_extension_crate(&self, name: Symbol, span: Span) -> ExtensionCrate {
         info!("read extension crate `{}`", name);
         let target_triple = self.sess.opts.target_triple.clone();
         let host_triple = TargetTriple::from_triple(config::host_triple());
@@ -559,7 +546,7 @@ impl<'a> CrateLoader<'a> {
                 (data.source.dylib.clone(), PMDSource::Registered(data))
             }
             LoadResult::Loaded(library) => {
-                let dylib = library.dylib.clone();
+                let dylib = library.source.dylib.clone();
                 let metadata = PMDSource::Owned(library);
                 (dylib, metadata)
             }
@@ -605,7 +592,7 @@ impl<'a> CrateLoader<'a> {
 
     /// Look for a plugin registrar. Returns library path, crate
     /// SVH and DefIndex of the registrar function.
-    pub fn find_plugin_registrar(&mut self,
+    pub fn find_plugin_registrar(&self,
                                  span: Span,
                                  name: Symbol)
                                  -> Option<(PathBuf, CrateDisambiguator)> {
@@ -638,7 +625,7 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
+    fn inject_panic_runtime(&self, krate: &ast::Crate) {
         // If we're only compiling an rlib, then there's no need to select a
         // panic runtime, so we just skip this section entirely.
         let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
@@ -719,7 +706,7 @@ impl<'a> CrateLoader<'a> {
                                   &|data| data.root.needs_panic_runtime);
     }
 
-    fn inject_sanitizer_runtime(&mut self) {
+    fn inject_sanitizer_runtime(&self) {
         if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer {
             // Sanitizers can only be used on some tested platforms with
             // executables linked to `std`
@@ -751,10 +738,10 @@ impl<'a> CrateLoader<'a> {
                 if !self.sess.crate_types.borrow().iter().all(|ct| {
                     match *ct {
                         // Link the runtime
-                        config::CrateType::Staticlib |
                         config::CrateType::Executable => true,
                         // This crate will be compiled with the required
                         // instrumentation pass
+                        config::CrateType::Staticlib |
                         config::CrateType::Rlib |
                         config::CrateType::Dylib |
                         config::CrateType::Cdylib =>
@@ -817,7 +804,7 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn inject_profiler_runtime(&mut self) {
+    fn inject_profiler_runtime(&self) {
         if self.sess.opts.debugging_opts.profile ||
            self.sess.opts.cg.profile_generate.enabled()
         {
@@ -834,7 +821,7 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
+    fn inject_allocator_crate(&self, krate: &ast::Crate) {
         let has_global_allocator = match &*global_allocator_spans(krate) {
             [span1, span2, ..] => {
                 self.sess.struct_span_err(*span2, "cannot define multiple global allocators")
@@ -973,7 +960,7 @@ impl<'a> CrateLoader<'a> {
 }
 
 impl<'a> CrateLoader<'a> {
-    pub fn postprocess(&mut self, krate: &ast::Crate) {
+    pub fn postprocess(&self, krate: &ast::Crate) {
         self.inject_sanitizer_runtime();
         self.inject_profiler_runtime();
         self.inject_allocator_crate(krate);
@@ -984,9 +971,7 @@ impl<'a> CrateLoader<'a> {
         }
     }
 
-    pub fn process_extern_crate(
-        &mut self, item: &ast::Item, definitions: &Definitions,
-    ) -> CrateNum {
+    pub fn process_extern_crate(&self, item: &ast::Item, definitions: &Definitions) -> CrateNum {
         match item.kind {
             ast::ItemKind::ExternCrate(orig_name) => {
                 debug!("resolving extern crate stmt. ident: {} orig_name: {:?}",
@@ -1019,18 +1004,13 @@ impl<'a> CrateLoader<'a> {
                     },
                     &mut FxHashSet::default(),
                 );
-                self.cstore.add_extern_mod_stmt_cnum(item.id, cnum);
                 cnum
             }
             _ => bug!(),
         }
     }
 
-    pub fn process_path_extern(
-        &mut self,
-        name: Symbol,
-        span: Span,
-    ) -> CrateNum {
+    pub fn process_path_extern(&self, name: Symbol, span: Span) -> CrateNum {
         let cnum = self.resolve_crate(name, span, DepKind::Explicit, None).0;
 
         self.update_extern_crate(
@@ -1048,11 +1028,7 @@ impl<'a> CrateLoader<'a> {
         cnum
     }
 
-    pub fn maybe_process_path_extern(
-        &mut self,
-        name: Symbol,
-        span: Span,
-    ) -> Option<CrateNum> {
+    pub fn maybe_process_path_extern(&self, name: Symbol, span: Span) -> Option<CrateNum> {
         let cnum = self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()?.0;
 
         self.update_extern_crate(
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 98a08e501f1..9a0b98ffb73 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -5,19 +5,15 @@ use crate::schema;
 use rustc::dep_graph::DepNodeIndex;
 use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::map::definitions::DefPathTable;
-use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader};
+use rustc::middle::cstore::{CrateSource, DepKind, ExternCrate, MetadataLoader};
 use rustc::mir::interpret::AllocDecodingState;
 use rustc_index::vec::IndexVec;
-use rustc::util::nodemap::{FxHashMap, NodeMap};
-
-use rustc_data_structures::sync::{Lrc, RwLock, Lock, AtomicCell};
+use rustc::util::nodemap::FxHashMap;
+use rustc_data_structures::sync::{Lrc, RwLock, Lock, MetadataRef, AtomicCell};
 use syntax::ast;
-use syntax::ext::base::SyntaxExtension;
+use syntax_expand::base::SyntaxExtension;
 use syntax_pos;
-
-pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePreference};
-pub use rustc::middle::cstore::NativeLibraryKind::*;
-pub use rustc::middle::cstore::{CrateSource, LibSource, ForeignModule};
+use proc_macro::bridge::client::ProcMacro;
 
 pub use crate::cstore_impl::{provide, provide_extern};
 
@@ -25,17 +21,13 @@ pub use crate::cstore_impl::{provide, provide_extern};
 // local crate numbers (as generated during this session). Each external
 // crate may refer to types in other external crates, and each has their
 // own crate numbers.
-pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
+crate type CrateNumMap = IndexVec<CrateNum, CrateNum>;
 
-pub use rustc_data_structures::sync::MetadataRef;
-use syntax_pos::Span;
-use proc_macro::bridge::client::ProcMacro;
-
-pub struct MetadataBlob(pub MetadataRef);
+crate struct MetadataBlob(pub MetadataRef);
 
 /// Holds information about a syntax_pos::SourceFile imported from another crate.
 /// See `imported_source_files()` for more information.
-pub struct ImportedSourceFile {
+crate struct ImportedSourceFile {
     /// This SourceFile's byte-offset within the source_map of its original crate
     pub original_start_pos: syntax_pos::BytePos,
     /// The end of this SourceFile within the source_map of its original crate
@@ -45,59 +37,66 @@ pub struct ImportedSourceFile {
 }
 
 pub struct CrateMetadata {
-    /// Information about the extern crate that caused this crate to
-    /// be loaded. If this is `None`, then the crate was injected
-    /// (e.g., by the allocator)
-    pub extern_crate: Lock<Option<ExternCrate>>,
-
-    pub blob: MetadataBlob,
-    pub cnum_map: CrateNumMap,
-    pub cnum: CrateNum,
-    pub dependencies: Lock<Vec<CrateNum>>,
-    pub source_map_import_info: RwLock<Vec<ImportedSourceFile>>,
+    /// The primary crate data - binary metadata blob.
+    crate blob: MetadataBlob,
 
-    /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
-    pub alloc_decoding_state: AllocDecodingState,
-
-    // NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
-    // lifetime is only used behind `Lazy`, and therefore acts like an
-    // universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
-    // is being used to decode those values.
-    pub root: schema::CrateRoot<'static>,
+    // --- Some data pre-decoded from the metadata blob, usually for performance ---
 
+    /// Properties of the whole crate.
+    /// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
+    /// lifetime is only used behind `Lazy`, and therefore acts like an
+    /// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
+    /// is being used to decode those values.
+    crate root: schema::CrateRoot<'static>,
     /// For each definition in this crate, we encode a key. When the
     /// crate is loaded, we read all the keys and put them in this
     /// hashmap, which gives the reverse mapping. This allows us to
     /// quickly retrace a `DefPath`, which is needed for incremental
     /// compilation support.
-    pub def_path_table: Lrc<DefPathTable>,
-
-    pub trait_impls: FxHashMap<(u32, DefIndex), schema::Lazy<[DefIndex]>>,
-
-    pub dep_kind: Lock<DepKind>,
-    pub source: CrateSource,
-
+    crate def_path_table: Lrc<DefPathTable>,
+    /// Trait impl data.
+    /// FIXME: Used only from queries and can use query cache,
+    /// so pre-decoding can probably be avoided.
+    crate trait_impls: FxHashMap<(u32, DefIndex), schema::Lazy<[DefIndex]>>,
+    /// Proc macro descriptions for this crate, if it's a proc macro crate.
+    crate raw_proc_macros: Option<&'static [ProcMacro]>,
+    /// Source maps for code from the crate.
+    crate source_map_import_info: RwLock<Vec<ImportedSourceFile>>,
+    /// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
+    crate alloc_decoding_state: AllocDecodingState,
+    /// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
+    /// It is initialized on the first access in `get_crate_dep_node_index()`.
+    /// Do not access the value directly, as it might not have been initialized yet.
+    /// The field must always be initialized to `DepNodeIndex::INVALID`.
+    crate dep_node_index: AtomicCell<DepNodeIndex>,
+
+    // --- Other significant crate properties ---
+
+    /// ID of this crate, from the current compilation session's point of view.
+    crate cnum: CrateNum,
+    /// Maps crate IDs as they are were seen from this crate's compilation sessions into
+    /// IDs as they are seen from the current compilation session.
+    crate cnum_map: CrateNumMap,
+    /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
+    crate dependencies: Lock<Vec<CrateNum>>,
+    /// How to link (or not link) this crate to the currently compiled crate.
+    crate dep_kind: Lock<DepKind>,
+    /// Filesystem location of this crate.
+    crate source: CrateSource,
     /// Whether or not this crate should be consider a private dependency
     /// for purposes of the 'exported_private_dependencies' lint
-    pub private_dep: bool,
+    crate private_dep: bool,
 
-    pub span: Span,
+    // --- Data used only for improving diagnostics ---
 
-    pub raw_proc_macros: Option<&'static [ProcMacro]>,
-
-    /// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
-    /// It is initialized on the first access in `get_crate_dep_node_index()`.
-    /// Do not access the value directly, as it might not have been initialized
-    /// yet.
-    /// The field must always be initialized to `DepNodeIndex::INVALID`.
-    pub(super) dep_node_index: AtomicCell<DepNodeIndex>,
+    /// Information about the `extern crate` item or path that caused this crate to be loaded.
+    /// If this is `None`, then the crate was injected (e.g., by the allocator).
+    crate extern_crate: Lock<Option<ExternCrate>>,
 }
 
 pub struct CStore {
     metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
-    /// Map from NodeId's of local extern crate statements to crate numbers
-    extern_mod_crate_map: Lock<NodeMap<CrateNum>>,
-    pub metadata_loader: Box<dyn MetadataLoader + Sync>,
+    crate metadata_loader: Box<dyn MetadataLoader + Sync>,
 }
 
 pub enum LoadedMacro {
@@ -113,30 +112,29 @@ impl CStore {
             // corresponding `CrateNum`. This first entry will always remain
             // `None`.
             metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
-            extern_mod_crate_map: Default::default(),
             metadata_loader,
         }
     }
 
-    pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
+    crate fn alloc_new_crate_num(&self) -> CrateNum {
         let mut metas = self.metas.borrow_mut();
         let cnum = CrateNum::new(metas.len());
         metas.push(None);
         cnum
     }
 
-    pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
+    crate fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
         self.metas.borrow()[cnum].clone()
             .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum))
     }
 
-    pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
+    crate fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
         let mut metas = self.metas.borrow_mut();
         assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
         metas[cnum] = Some(data);
     }
 
-    pub(super) fn iter_crate_data<I>(&self, mut i: I)
+    crate fn iter_crate_data<I>(&self, mut i: I)
         where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
     {
         for (k, v) in self.metas.borrow().iter_enumerated() {
@@ -146,16 +144,14 @@ impl CStore {
         }
     }
 
-    pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
+    crate fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
         let mut ordering = Vec::new();
         self.push_dependencies_in_postorder(&mut ordering, krate);
         ordering.reverse();
         ordering
     }
 
-    pub(super) fn push_dependencies_in_postorder(&self,
-                                                 ordering: &mut Vec<CrateNum>,
-                                                 krate: CrateNum) {
+    crate fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate: CrateNum) {
         if ordering.contains(&krate) {
             return;
         }
@@ -170,7 +166,7 @@ impl CStore {
         ordering.push(krate);
     }
 
-    pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
+    crate fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
         let mut ordering = Vec::new();
         for (num, v) in self.metas.borrow().iter_enumerated() {
             if let &Some(_) = v {
@@ -179,12 +175,4 @@ impl CStore {
         }
         return ordering
     }
-
-    pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
-        self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
-    }
-
-    pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
-        self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
-    }
 }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 642a7632b3d..4cd1ff7b4a4 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -6,8 +6,7 @@ use crate::foreign_modules;
 use crate::schema;
 
 use rustc::ty::query::QueryConfig;
-use rustc::middle::cstore::{CrateStore, DepKind,
-                            EncodedMetadata, NativeLibraryKind};
+use rustc::middle::cstore::{CrateSource, CrateStore, DepKind, EncodedMetadata, NativeLibraryKind};
 use rustc::middle::exported_symbols::ExportedSymbol;
 use rustc::middle::stability::DeprecationEntry;
 use rustc::middle::dependency_format::Linkage;
@@ -98,11 +97,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     generics_of => {
         tcx.arena.alloc(cdata.get_generics(def_id.index, tcx.sess))
     }
-    predicates_of => { tcx.arena.alloc(cdata.get_predicates(def_id.index, tcx)) }
-    predicates_defined_on => {
-        tcx.arena.alloc(cdata.get_predicates_defined_on(def_id.index, tcx))
-    }
-    super_predicates_of => { tcx.arena.alloc(cdata.get_super_predicates(def_id.index, tcx)) }
+    predicates_of => { cdata.get_predicates(def_id.index, tcx) }
+    predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) }
+    super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
     trait_def => {
         tcx.arena.alloc(cdata.get_trait_def(def_id.index, tcx.sess))
     }
@@ -414,12 +411,6 @@ impl cstore::CStore {
         }
     }
 
-    pub fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind {
-        let data = self.get_crate_data(cnum);
-        let r = *data.dep_kind.lock();
-        r
-    }
-
     pub fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition {
         self.get_crate_data(cnum).root.edition
     }
@@ -428,14 +419,6 @@ impl cstore::CStore {
         self.get_crate_data(def.krate).get_struct_field_names(def.index, sess)
     }
 
-    pub fn ctor_kind_untracked(&self, def: DefId) -> def::CtorKind {
-        self.get_crate_data(def.krate).get_ctor_kind(def.index)
-    }
-
-    pub fn item_attrs_untracked(&self, def: DefId, sess: &Session) -> Lrc<[ast::Attribute]> {
-        self.get_crate_data(def.krate).get_item_attrs(def.index, sess)
-    }
-
     pub fn item_children_untracked(
         &self,
         def_id: DefId,
@@ -493,6 +476,10 @@ impl cstore::CStore {
     pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssocItem {
         self.get_crate_data(def.krate).get_associated_item(def.index)
     }
+
+    pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
+        self.get_crate_data(cnum).source.clone()
+    }
 }
 
 impl CrateStore for cstore::CStore {
@@ -549,11 +536,6 @@ impl CrateStore for cstore::CStore {
         result
     }
 
-    fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>
-    {
-        self.do_extern_mod_stmt_cnum(emod_id)
-    }
-
     fn postorder_cnums_untracked(&self) -> Vec<CrateNum> {
         self.do_postorder_cnums_untracked()
     }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 132ef7d4241..b8b00302440 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -1,13 +1,14 @@
 // Decoding metadata from a single crate's metadata
 
-use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
+use crate::cstore::{self, CrateMetadata, MetadataBlob};
 use crate::schema::*;
+use crate::table::{FixedSizeEncoding, PerDefTable};
 
 use rustc_index::vec::IndexVec;
 use rustc_data_structures::sync::{Lrc, ReadGuard};
 use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
-use rustc::middle::cstore::LinkagePreference;
+use rustc::middle::cstore::{LinkagePreference, NativeLibrary, ForeignModule};
 use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -25,20 +26,21 @@ use rustc::util::captures::Captures;
 
 use std::io;
 use std::mem;
+use std::num::NonZeroUsize;
 use std::u32;
 
-use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
+use rustc_serialize::{Decodable, Decoder, Encodable, SpecializedDecoder, opaque};
 use syntax::attr;
 use syntax::ast::{self, Ident};
 use syntax::source_map::{self, respan, Spanned};
 use syntax::symbol::{Symbol, sym};
-use syntax::ext::base::{MacroKind, SyntaxExtensionKind, SyntaxExtension};
+use syntax_expand::base::{MacroKind, SyntaxExtensionKind, SyntaxExtension};
 use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, symbol::{InternedString}};
 use log::debug;
 use proc_macro::bridge::client::ProcMacro;
-use syntax::ext::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro};
+use syntax_expand::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro};
 
-pub struct DecodeContext<'a, 'tcx> {
+crate struct DecodeContext<'a, 'tcx> {
     opaque: opaque::Decoder<'a>,
     cdata: Option<&'a CrateMetadata>,
     sess: Option<&'tcx Session>,
@@ -54,7 +56,7 @@ pub struct DecodeContext<'a, 'tcx> {
 }
 
 /// Abstract over the various ways one can create metadata decoders.
-pub trait Metadata<'a, 'tcx>: Copy {
+crate trait Metadata<'a, 'tcx>: Copy {
     fn raw_bytes(self) -> &'a [u8];
     fn cdata(self) -> Option<&'a CrateMetadata> { None }
     fn sess(self) -> Option<&'tcx Session> { None }
@@ -129,31 +131,31 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'tcx>) {
     }
 }
 
-impl<'a, 'tcx, T: Decodable> Lazy<T> {
-    pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
-        let mut dcx = meta.decoder(self.position);
+impl<'a, 'tcx, T: Encodable + Decodable> Lazy<T> {
+    crate fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
+        let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
         T::decode(&mut dcx).unwrap()
     }
 }
 
-impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> Lazy<[T]> {
-    pub fn decode<M: Metadata<'a, 'tcx>>(
+impl<'a: 'x, 'tcx: 'x, 'x, T: Encodable + Decodable> Lazy<[T]> {
+    crate fn decode<M: Metadata<'a, 'tcx>>(
         self,
-        meta: M,
+        metadata: M,
     ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
-        let mut dcx = meta.decoder(self.position);
+        let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
         (0..self.meta).map(move |_| T::decode(&mut dcx).unwrap())
     }
 }
 
 impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
-    pub fn tcx(&self) -> TyCtxt<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx.expect("missing TyCtxt in DecodeContext")
     }
 
-    pub fn cdata(&self) -> &'a CrateMetadata {
+    fn cdata(&self) -> &'a CrateMetadata {
         self.cdata.expect("missing CrateMetadata in DecodeContext")
     }
 
@@ -166,13 +168,14 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
         let position = match self.lazy_state {
             LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
             LazyState::NodeStart(start) => {
+                let start = start.get();
                 assert!(distance + min_size <= start);
                 start - distance - min_size
             }
-            LazyState::Previous(last_min_end) => last_min_end + distance,
+            LazyState::Previous(last_min_end) => last_min_end.get() + distance,
         };
-        self.lazy_state = LazyState::Previous(position + min_size);
-        Ok(Lazy::from_position_and_meta(position, meta))
+        self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
+        Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
     }
 }
 
@@ -235,13 +238,13 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> {
+impl<'a, 'tcx, T: Encodable> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> {
         self.read_lazy_with_meta(())
     }
 }
 
-impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> {
+impl<'a, 'tcx, T: Encodable> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<Lazy<[T]>, Self::Error> {
         let len = self.read_usize()?;
         if len == 0 {
@@ -252,6 +255,14 @@ impl<'a, 'tcx, T> SpecializedDecoder<Lazy<[T]>> for DecodeContext<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx, T> SpecializedDecoder<Lazy<PerDefTable<T>>> for DecodeContext<'a, 'tcx>
+    where Option<T>: FixedSizeEncoding,
+{
+    fn specialized_decode(&mut self) -> Result<Lazy<PerDefTable<T>>, Self::Error> {
+        let len = self.read_usize()?;
+        self.read_lazy_with_meta(len)
+    }
+}
 
 impl<'a, 'tcx> SpecializedDecoder<DefId> for DecodeContext<'a, 'tcx> {
     #[inline]
@@ -379,24 +390,28 @@ for DecodeContext<'a, 'tcx> {
 implement_ty_decoder!( DecodeContext<'a, 'tcx> );
 
 impl<'tcx> MetadataBlob {
-    pub fn is_compatible(&self) -> bool {
+    crate fn is_compatible(&self) -> bool {
         self.raw_bytes().starts_with(METADATA_HEADER)
     }
 
-    pub fn get_rustc_version(&self) -> String {
-        Lazy::<String>::from_position(METADATA_HEADER.len() + 4).decode(self)
+    crate fn get_rustc_version(&self) -> String {
+        Lazy::<String>::from_position(
+            NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap(),
+        ).decode(self)
     }
 
-    pub fn get_root(&self) -> CrateRoot<'tcx> {
+    crate fn get_root(&self) -> CrateRoot<'tcx> {
         let slice = self.raw_bytes();
         let offset = METADATA_HEADER.len();
         let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) |
                    ((slice[offset + 2] as u32) << 8) |
                    ((slice[offset + 3] as u32) << 0)) as usize;
-        Lazy::<CrateRoot<'tcx>>::from_position(pos).decode(self)
+        Lazy::<CrateRoot<'tcx>>::from_position(
+            NonZeroUsize::new(pos).unwrap(),
+        ).decode(self)
     }
 
-    pub fn list_crate_metadata(&self,
+    crate fn list_crate_metadata(&self,
                                out: &mut dyn io::Write) -> io::Result<()> {
         write!(out, "=External Dependencies=\n")?;
         let root = self.get_root();
@@ -449,7 +464,7 @@ impl<'tcx> EntryKind<'tcx> {
 }
 
 impl<'a, 'tcx> CrateMetadata {
-    pub fn is_proc_macro_crate(&self) -> bool {
+    crate fn is_proc_macro_crate(&self) -> bool {
         self.root.proc_macro_decls_static.is_some()
     }
 
@@ -458,27 +473,20 @@ impl<'a, 'tcx> CrateMetadata {
             self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
     }
 
-    fn entry_unless_proc_macro(&self, id: DefIndex) -> Option<Entry<'tcx>> {
-        match self.is_proc_macro(id) {
-            true => None,
-            false => Some(self.entry(id)),
-        }
+    fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind<'tcx>> {
+        self.root.per_def.kind.get(self, item_id).map(|k| k.decode(self))
     }
 
-    fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
-        self.root.entries_index.lookup(self.blob.raw_bytes(), item_id)
-    }
-
-    fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
-        match self.maybe_entry(item_id) {
-            None => {
-                bug!("entry: id not found: {:?} in crate {:?} with number {}",
-                     item_id,
-                     self.root.name,
-                     self.cnum)
-            }
-            Some(d) => d.decode(self),
-        }
+    fn kind(&self, item_id: DefIndex) -> EntryKind<'tcx> {
+        assert!(!self.is_proc_macro(item_id));
+        self.maybe_kind(item_id).unwrap_or_else(|| {
+            bug!(
+                "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
+                item_id,
+                self.root.name,
+                self.cnum,
+            )
+        })
     }
 
     fn local_def_id(&self, index: DefIndex) -> DefId {
@@ -499,7 +507,7 @@ impl<'a, 'tcx> CrateMetadata {
         &self.raw_proc_macros.unwrap()[pos]
     }
 
-    pub fn item_name(&self, item_index: DefIndex) -> Symbol {
+    crate fn item_name(&self, item_index: DefIndex) -> Symbol {
         if !self.is_proc_macro(item_index) {
             self.def_key(item_index)
                 .disambiguated_data
@@ -512,9 +520,9 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
+    crate fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
         if !self.is_proc_macro(index) {
-            self.entry(index).kind.def_kind()
+            self.kind(index).def_kind()
         } else {
             Some(DefKind::Macro(
                 macro_kind(self.raw_proc_macro(index))
@@ -522,8 +530,8 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
-        self.entry(index).span.decode((self, sess))
+    crate fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
+        self.root.per_def.span.get(self, index).unwrap().decode((self, sess))
     }
 
     crate fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
@@ -552,12 +560,12 @@ impl<'a, 'tcx> CrateMetadata {
             helper_attrs,
             self.root.edition,
             Symbol::intern(name),
-            &self.get_attributes(&self.entry(id), sess),
+            &self.get_item_attrs(id, sess),
         )
     }
 
-    pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
-        match self.entry(item_id).kind {
+    crate fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
+        match self.kind(item_id) {
             EntryKind::Trait(data) => {
                 let data = data.decode((self, sess));
                 ty::TraitDef::new(self.local_def_id(item_id),
@@ -582,18 +590,24 @@ impl<'a, 'tcx> CrateMetadata {
     fn get_variant(
         &self,
         tcx: TyCtxt<'tcx>,
-        item: &Entry<'_>,
+        kind: &EntryKind<'_>,
         index: DefIndex,
         parent_did: DefId,
-        adt_kind: ty::AdtKind,
     ) -> ty::VariantDef {
-        let data = match item.kind {
+        let data = match kind {
             EntryKind::Variant(data) |
             EntryKind::Struct(data, _) |
             EntryKind::Union(data, _) => data.decode(self),
             _ => bug!(),
         };
 
+        let adt_kind = match kind {
+            EntryKind::Variant(_) => ty::AdtKind::Enum,
+            EntryKind::Struct(..) => ty::AdtKind::Struct,
+            EntryKind::Union(..) => ty::AdtKind::Union,
+            _ => bug!(),
+        };
+
         let variant_did = if adt_kind == ty::AdtKind::Enum {
             Some(self.local_def_id(index))
         } else {
@@ -607,14 +621,12 @@ impl<'a, 'tcx> CrateMetadata {
             variant_did,
             ctor_did,
             data.discr,
-            item.children.decode(self).map(|index| {
-                let f = self.entry(index);
-                ty::FieldDef {
+            self.root.per_def.children.get(self, index).unwrap_or(Lazy::empty())
+                .decode(self).map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
                     ident: Ident::with_dummy_span(self.item_name(index)),
-                    vis: f.visibility.decode(self)
-                }
-            }).collect(),
+                    vis: self.get_visibility(index),
+                }).collect(),
             data.ctor_kind,
             adt_kind,
             parent_did,
@@ -622,53 +634,53 @@ impl<'a, 'tcx> CrateMetadata {
         )
     }
 
-    pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
-        let item = self.entry(item_id);
+    crate fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
+        let kind = self.kind(item_id);
         let did = self.local_def_id(item_id);
 
-        let (kind, repr) = match item.kind {
+        let (adt_kind, repr) = match kind {
             EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
             EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
             EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
             _ => bug!("get_adt_def called on a non-ADT {:?}", did),
         };
 
-        let variants = if let ty::AdtKind::Enum = kind {
-            item.children
+        let variants = if let ty::AdtKind::Enum = adt_kind {
+            self.root.per_def.children.get(self, item_id).unwrap_or(Lazy::empty())
                 .decode(self)
                 .map(|index| {
-                    self.get_variant(tcx, &self.entry(index), index, did, kind)
+                    self.get_variant(tcx, &self.kind(index), index, did)
                 })
                 .collect()
         } else {
-            std::iter::once(self.get_variant(tcx, &item, item_id, did, kind)).collect()
+            std::iter::once(self.get_variant(tcx, &kind, item_id, did)).collect()
         };
 
-        tcx.alloc_adt_def(did, kind, variants, repr)
+        tcx.alloc_adt_def(did, adt_kind, variants, repr)
     }
 
-    pub fn get_predicates(
+    crate fn get_predicates(
         &self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
-        self.entry(item_id).predicates.unwrap().decode((self, tcx))
+        self.root.per_def.predicates.get(self, item_id).unwrap().decode((self, tcx))
 }
 
-    pub fn get_predicates_defined_on(
+    crate fn get_predicates_defined_on(
         &self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
-        self.entry(item_id).predicates_defined_on.unwrap().decode((self, tcx))
+        self.root.per_def.predicates_defined_on.get(self, item_id).unwrap().decode((self, tcx))
     }
 
-    pub fn get_super_predicates(
+    crate fn get_super_predicates(
         &self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
-        let super_predicates = match self.entry(item_id).kind {
+        let super_predicates = match self.kind(item_id) {
             EntryKind::Trait(data) => data.decode(self).super_predicates,
             EntryKind::TraitAlias(data) => data.decode(self).super_predicates,
             _ => bug!("def-index does not refer to trait or trait alias"),
@@ -677,67 +689,66 @@ impl<'a, 'tcx> CrateMetadata {
         super_predicates.decode((self, tcx))
     }
 
-    pub fn get_generics(&self,
-                        item_id: DefIndex,
-                        sess: &Session)
-                        -> ty::Generics {
-        self.entry(item_id).generics.unwrap().decode((self, sess))
+    crate fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
+        self.root.per_def.generics.get(self, item_id).unwrap().decode((self, sess))
     }
 
-    pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        self.entry(id).ty.unwrap().decode((self, tcx))
+    crate fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        self.root.per_def.ty.get(self, id).unwrap().decode((self, tcx))
     }
 
-    pub fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
+    crate fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
         match self.is_proc_macro(id) {
             true => self.root.proc_macro_stability.clone(),
-            false => self.entry(id).stability.map(|stab| stab.decode(self)),
+            false => self.root.per_def.stability.get(self, id).map(|stab| stab.decode(self)),
         }
     }
 
-    pub fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
-        self.entry_unless_proc_macro(id)
-            .and_then(|entry| entry.deprecation.map(|depr| depr.decode(self)))
+    crate fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
+        self.root.per_def.deprecation.get(self, id)
+            .filter(|_| !self.is_proc_macro(id))
+            .map(|depr| depr.decode(self))
     }
 
-    pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
+    crate fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
         match self.is_proc_macro(id) {
             true => ty::Visibility::Public,
-            false => self.entry(id).visibility.decode(self),
+            false => self.root.per_def.visibility.get(self, id).unwrap().decode(self),
         }
     }
 
     fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> {
-        match self.entry(id).kind {
+        match self.kind(id) {
             EntryKind::Impl(data) => data.decode(self),
             _ => bug!(),
         }
     }
 
-    pub fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
+    crate fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
         self.get_impl_data(id).parent_impl
     }
 
-    pub fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
+    crate fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
         self.get_impl_data(id).polarity
     }
 
-    pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
+    crate fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
         self.get_impl_data(id).defaultness
     }
 
-    pub fn get_coerce_unsized_info(&self,
-                                   id: DefIndex)
-                                   -> Option<ty::adjustment::CoerceUnsizedInfo> {
+    crate fn get_coerce_unsized_info(
+        &self,
+        id: DefIndex,
+    ) -> Option<ty::adjustment::CoerceUnsizedInfo> {
         self.get_impl_data(id).coerce_unsized_info
     }
 
-    pub fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
+    crate fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
         self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx)))
     }
 
     /// Iterates over all the stability attributes in the given crate.
-    pub fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(ast::Name, Option<ast::Name>)] {
+    crate fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(ast::Name, Option<ast::Name>)] {
         // FIXME: For a proc macro crate, not sure whether we should return the "host"
         // features or an empty Vec. Both don't cause ICEs.
         tcx.arena.alloc_from_iter(self.root
@@ -746,7 +757,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     /// Iterates over the language items in the given crate.
-    pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
+    crate fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
         if self.is_proc_macro_crate() {
             // Proc macro crates do not export any lang-items to the target.
             &[]
@@ -759,7 +770,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     /// Iterates over the diagnostic items in the given crate.
-    pub fn get_diagnostic_items(
+    crate fn get_diagnostic_items(
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx FxHashMap<Symbol, DefId> {
@@ -776,7 +787,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     /// Iterates over each child of the given item.
-    pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
+    crate fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
         where F: FnMut(def::Export<hir::HirId>)
     {
         if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) {
@@ -803,38 +814,42 @@ impl<'a, 'tcx> CrateMetadata {
         }
 
         // Find the item.
-        let item = match self.maybe_entry(id) {
+        let kind = match self.maybe_kind(id) {
             None => return,
-            Some(item) => item.decode((self, sess)),
+            Some(kind) => kind,
         };
 
         // Iterate over all children.
         let macros_only = self.dep_kind.lock().macros_only();
-        for child_index in item.children.decode((self, sess)) {
+        let children = self.root.per_def.children.get(self, id).unwrap_or(Lazy::empty());
+        for child_index in children.decode((self, sess)) {
             if macros_only {
                 continue
             }
 
             // Get the item.
-            if let Some(child) = self.maybe_entry(child_index) {
-                let child = child.decode((self, sess));
-                match child.kind {
+            if let Some(child_kind) = self.maybe_kind(child_index) {
+                match child_kind {
                     EntryKind::MacroDef(..) => {}
                     _ if macros_only => continue,
                     _ => {}
                 }
 
                 // Hand off the item to the callback.
-                match child.kind {
+                match child_kind {
                     // FIXME(eddyb) Don't encode these in children.
                     EntryKind::ForeignMod => {
-                        for child_index in child.children.decode((self, sess)) {
+                        let child_children =
+                            self.root.per_def.children.get(self, child_index)
+                                .unwrap_or(Lazy::empty());
+                        for child_index in child_children.decode((self, sess)) {
                             if let Some(kind) = self.def_kind(child_index) {
                                 callback(def::Export {
                                     res: Res::Def(kind, self.local_def_id(child_index)),
                                     ident: Ident::with_dummy_span(self.item_name(child_index)),
                                     vis: self.get_visibility(child_index),
-                                    span: self.entry(child_index).span.decode((self, sess)),
+                                    span: self.root.per_def.span.get(self, child_index).unwrap()
+                                        .decode((self, sess)),
                                 });
                             }
                         }
@@ -846,7 +861,7 @@ impl<'a, 'tcx> CrateMetadata {
                 }
 
                 let def_key = self.def_key(child_index);
-                let span = child.span.decode((self, sess));
+                let span = self.get_span(child_index, sess);
                 if let (Some(kind), Some(name)) =
                     (self.def_kind(child_index), def_key.disambiguated_data.data.get_opt_name()) {
                     let ident = Ident::from_interned_str(name);
@@ -899,7 +914,7 @@ impl<'a, 'tcx> CrateMetadata {
             }
         }
 
-        if let EntryKind::Mod(data) = item.kind {
+        if let EntryKind::Mod(data) = kind {
             for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
                 match exp.res {
                     Res::Def(DefKind::Macro(..), _) => {}
@@ -911,33 +926,35 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
+    crate fn is_item_mir_available(&self, id: DefIndex) -> bool {
         !self.is_proc_macro(id) &&
-        self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
+            self.root.per_def.mir.get(self, id).is_some()
     }
 
-    pub fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
-        self.entry_unless_proc_macro(id)
-            .and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx))))
+    crate fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+        self.root.per_def.mir.get(self, id)
+            .filter(|_| !self.is_proc_macro(id))
             .unwrap_or_else(|| {
                 bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id))
             })
+            .decode((self, tcx))
     }
 
-    pub fn get_promoted_mir(
+    crate fn get_promoted_mir(
         &self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
     ) -> IndexVec<Promoted, Body<'tcx>> {
-        self.entry_unless_proc_macro(id)
-            .and_then(|entry| entry.promoted_mir.map(|promoted| promoted.decode((self, tcx))))
+        self.root.per_def.promoted_mir.get(self, id)
+            .filter(|_| !self.is_proc_macro(id))
             .unwrap_or_else(|| {
                 bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id))
             })
+            .decode((self, tcx))
     }
 
-    pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
-        match self.entry(id).kind {
+    crate fn mir_const_qualif(&self, id: DefIndex) -> u8 {
+        match self.kind(id) {
             EntryKind::Const(qualif, _) |
             EntryKind::AssocConst(AssocContainer::ImplDefault, qualif, _) |
             EntryKind::AssocConst(AssocContainer::ImplFinal, qualif, _) => {
@@ -947,13 +964,12 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem {
-        let item = self.entry(id);
+    crate fn get_associated_item(&self, id: DefIndex) -> ty::AssocItem {
         let def_key = self.def_key(id);
         let parent = self.local_def_id(def_key.parent.unwrap());
         let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
 
-        let (kind, container, has_self) = match item.kind {
+        let (kind, container, has_self) = match self.kind(id) {
             EntryKind::AssocConst(container, _, _) => {
                 (ty::AssocKind::Const, container, false)
             }
@@ -973,7 +989,7 @@ impl<'a, 'tcx> CrateMetadata {
         ty::AssocItem {
             ident: Ident::from_interned_str(name),
             kind,
-            vis: item.visibility.decode(self),
+            vis: self.get_visibility(id),
             defaultness: container.defaultness(),
             def_id: self.local_def_id(id),
             container: container.with_def_id(parent),
@@ -981,12 +997,13 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
-        self.entry(id).variances.decode(self).collect()
+    crate fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
+        self.root.per_def.variances.get(self, id).unwrap_or(Lazy::empty())
+            .decode(self).collect()
     }
 
-    pub fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
-        match self.entry(node_id).kind {
+    crate fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
+        match self.kind(node_id) {
             EntryKind::Struct(data, _) |
             EntryKind::Union(data, _) |
             EntryKind::Variant(data) => data.decode(self).ctor_kind,
@@ -994,8 +1011,8 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
-        match self.entry(node_id).kind {
+    crate fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
+        match self.kind(node_id) {
             EntryKind::Struct(data, _) => {
                 data.decode(self).ctor.map(|index| self.local_def_id(index))
             }
@@ -1006,8 +1023,7 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-
-    pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
+    crate fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
         // The attributes for a tuple struct/variant are attached to the definition, not the ctor;
         // we assume that someone passing in a tuple struct ctor is actually wanting to
         // look at the definition
@@ -1018,22 +1034,22 @@ impl<'a, 'tcx> CrateMetadata {
             node_id
         };
 
-        let item = self.entry(item_id);
-        Lrc::from(self.get_attributes(&item, sess))
+        Lrc::from(self.root.per_def.attributes.get(self, item_id).unwrap_or(Lazy::empty())
+            .decode((self, sess))
+            .collect::<Vec<_>>())
     }
 
-    pub fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec<Spanned<ast::Name>> {
-        self.entry(id)
-            .children
+    crate fn get_struct_field_names(
+        &self,
+        id: DefIndex,
+        sess: &Session,
+    ) -> Vec<Spanned<ast::Name>> {
+        self.root.per_def.children.get(self, id).unwrap_or(Lazy::empty())
             .decode(self)
             .map(|index| respan(self.get_span(index, sess), self.item_name(index)))
             .collect()
     }
 
-    fn get_attributes(&self, item: &Entry<'tcx>, sess: &Session) -> Vec<ast::Attribute> {
-        item.attributes.decode((self, sess)).collect()
-    }
-
     // Translate a DefId from the current compilation environment to a DefId
     // for an external crate.
     fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
@@ -1049,18 +1065,19 @@ impl<'a, 'tcx> CrateMetadata {
         None
     }
 
-    pub fn get_inherent_implementations_for_type(
+    crate fn get_inherent_implementations_for_type(
         &self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
     ) -> &'tcx [DefId] {
-        tcx.arena.alloc_from_iter(self.entry(id)
-                                      .inherent_impls
-                                      .decode(self)
-                                      .map(|index| self.local_def_id(index)))
+        tcx.arena.alloc_from_iter(
+            self.root.per_def.inherent_impls.get(self, id).unwrap_or(Lazy::empty())
+                .decode(self)
+                .map(|index| self.local_def_id(index))
+        )
     }
 
-    pub fn get_implementations_for_trait(
+    crate fn get_implementations_for_trait(
         &self,
         tcx: TyCtxt<'tcx>,
         filter: Option<DefId>,
@@ -1091,7 +1108,7 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
+    crate fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
         let def_key = self.def_key(id);
         match def_key.disambiguated_data.data {
             DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
@@ -1099,7 +1116,7 @@ impl<'a, 'tcx> CrateMetadata {
             _ => return None,
         }
         def_key.parent.and_then(|parent_index| {
-            match self.entry(parent_index).kind {
+            match self.kind(parent_index) {
                 EntryKind::Trait(_) |
                 EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)),
                 _ => None,
@@ -1108,7 +1125,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
 
-    pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
+    crate fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
         if self.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* native libraries.
             vec![]
@@ -1117,7 +1134,7 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
+    crate fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
         if self.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* foreign modules.
             &[]
@@ -1126,7 +1143,7 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_dylib_dependency_formats(
+    crate fn get_dylib_dependency_formats(
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(CrateNum, LinkagePreference)] {
@@ -1140,7 +1157,7 @@ impl<'a, 'tcx> CrateMetadata {
             }))
     }
 
-    pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
+    crate fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
         if self.is_proc_macro_crate() {
             // Proc macro crates do not depend on any target weak lang-items.
             &[]
@@ -1151,8 +1168,8 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_fn_param_names(&self, id: DefIndex) -> Vec<ast::Name> {
-        let param_names = match self.entry(id).kind {
+    crate fn get_fn_param_names(&self, id: DefIndex) -> Vec<ast::Name> {
+        let param_names = match self.kind(id) {
             EntryKind::Fn(data) |
             EntryKind::ForeignFn(data) => data.decode(self).param_names,
             EntryKind::Method(data) => data.decode(self).fn_data.param_names,
@@ -1161,7 +1178,7 @@ impl<'a, 'tcx> CrateMetadata {
         param_names.decode(self).collect()
     }
 
-    pub fn exported_symbols(
+    crate fn exported_symbols(
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
@@ -1174,24 +1191,23 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_rendered_const(&self, id: DefIndex) -> String {
-        match self.entry(id).kind {
+    crate fn get_rendered_const(&self, id: DefIndex) -> String {
+        match self.kind(id) {
             EntryKind::Const(_, data) |
             EntryKind::AssocConst(_, _, data) => data.decode(self).0,
             _ => bug!(),
         }
     }
 
-    pub fn get_macro(&self, id: DefIndex) -> MacroDef {
-        let entry = self.entry(id);
-        match entry.kind {
+    crate fn get_macro(&self, id: DefIndex) -> MacroDef {
+        match self.kind(id) {
             EntryKind::MacroDef(macro_def) => macro_def.decode(self),
             _ => bug!(),
         }
     }
 
     crate fn is_const_fn_raw(&self, id: DefIndex) -> bool {
-        let constness = match self.entry(id).kind {
+        let constness = match self.kind(id) {
             EntryKind::Method(data) => data.decode(self).fn_data.constness,
             EntryKind::Fn(data) => data.decode(self).constness,
             EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
@@ -1200,17 +1216,17 @@ impl<'a, 'tcx> CrateMetadata {
         constness == hir::Constness::Const
     }
 
-    pub fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
-         match self.entry(id).kind {
+    crate fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
+         match self.kind(id) {
             EntryKind::Fn(data) => data.decode(self).asyncness,
             EntryKind::Method(data) => data.decode(self).fn_data.asyncness,
             EntryKind::ForeignFn(data) => data.decode(self).asyncness,
-            _ => bug!("asyncness: expect functions entry."),
+            _ => bug!("asyncness: expected function kind"),
         }
     }
 
-    pub fn is_foreign_item(&self, id: DefIndex) -> bool {
-        match self.entry(id).kind {
+    crate fn is_foreign_item(&self, id: DefIndex) -> bool {
+        match self.kind(id) {
             EntryKind::ForeignImmStatic |
             EntryKind::ForeignMutStatic |
             EntryKind::ForeignFn(_) => true,
@@ -1219,7 +1235,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     crate fn static_mutability(&self, id: DefIndex) -> Option<hir::Mutability> {
-        match self.entry(id).kind {
+        match self.kind(id) {
             EntryKind::ImmStatic |
             EntryKind::ForeignImmStatic => Some(hir::MutImmutable),
             EntryKind::MutStatic |
@@ -1228,8 +1244,8 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
-        let sig = match self.entry(id).kind {
+    crate fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
+        let sig = match self.kind(id) {
             EntryKind::Fn(data) |
             EntryKind::ForeignFn(data) => data.decode(self).sig,
             EntryKind::Method(data) => data.decode(self).fn_data.sig,
@@ -1242,7 +1258,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     #[inline]
-    pub fn def_key(&self, index: DefIndex) -> DefKey {
+    crate fn def_key(&self, index: DefIndex) -> DefKey {
         let mut key = self.def_path_table.def_key(index);
         if self.is_proc_macro(index) {
             let name = self.raw_proc_macro(index).name();
@@ -1252,13 +1268,13 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     // Returns the path leading to the thing with this `id`.
-    pub fn def_path(&self, id: DefIndex) -> DefPath {
+    crate fn def_path(&self, id: DefIndex) -> DefPath {
         debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
         DefPath::make(self.cnum, id, |parent| self.def_key(parent))
     }
 
     #[inline]
-    pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
+    crate fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
         self.def_path_table.def_path_hash(index)
     }
 
@@ -1287,9 +1303,10 @@ impl<'a, 'tcx> CrateMetadata {
     ///
     /// Proc macro crates don't currently export spans, so this function does not have
     /// to work for them.
-    pub fn imported_source_files(&'a self,
-                                 local_source_map: &source_map::SourceMap)
-                                 -> ReadGuard<'a, Vec<cstore::ImportedSourceFile>> {
+    fn imported_source_files(
+        &'a self,
+        local_source_map: &source_map::SourceMap,
+    ) -> ReadGuard<'a, Vec<cstore::ImportedSourceFile>> {
         {
             let source_files = self.source_map_import_info.borrow();
             if !source_files.is_empty() {
diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs
index 9a30623b33d..7f76a9730e1 100644
--- a/src/librustc_metadata/dependency_format.rs
+++ b/src/librustc_metadata/dependency_format.rs
@@ -60,7 +60,7 @@ use rustc::ty::TyCtxt;
 use rustc::util::nodemap::FxHashMap;
 use rustc_target::spec::PanicStrategy;
 
-pub fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
+crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
     tcx.sess.crate_types.borrow().iter().map(|&ty| {
         let linkage = calculate_type(tcx, ty);
         verify_ok(tcx, &linkage);
diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs
index 4c279361ff5..3871eb89f7b 100644
--- a/src/librustc_metadata/dynamic_lib.rs
+++ b/src/librustc_metadata/dynamic_lib.rs
@@ -32,30 +32,6 @@ impl DynamicLibrary {
         }
     }
 
-    /// Loads a dynamic library into the global namespace (RTLD_GLOBAL on Unix)
-    /// and do it now (don't use RTLD_LAZY on Unix).
-    pub fn open_global_now(filename: &Path) -> Result<DynamicLibrary, String> {
-        let maybe_library = dl::open_global_now(filename.as_os_str());
-        match maybe_library {
-            Err(err) => Err(err),
-            Ok(handle) => Ok(DynamicLibrary { handle })
-        }
-    }
-
-    /// Returns the environment variable for this process's dynamic library
-    /// search path
-    pub fn envvar() -> &'static str {
-        if cfg!(windows) {
-            "PATH"
-        } else if cfg!(target_os = "macos") {
-            "DYLD_LIBRARY_PATH"
-        } else if cfg!(target_os = "haiku") {
-            "LIBRARY_PATH"
-        } else {
-            "LD_LIBRARY_PATH"
-        }
-    }
-
     /// Accesses the value at the symbol of the dynamic library.
     pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
         // This function should have a lifetime constraint of 'a on
@@ -83,7 +59,7 @@ mod dl {
     use std::ptr;
     use std::str;
 
-    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
+    pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
         check_for_errors_in(|| {
             unsafe {
                 match filename {
@@ -94,13 +70,6 @@ mod dl {
         })
     }
 
-    pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> {
-        check_for_errors_in(|| unsafe {
-            let s = CString::new(filename.as_bytes()).unwrap();
-            libc::dlopen(s.as_ptr(), libc::RTLD_GLOBAL | libc::RTLD_NOW) as *mut u8
-        })
-    }
-
     unsafe fn open_external(filename: &OsStr) -> *mut u8 {
         let s = CString::new(filename.as_bytes()).unwrap();
         libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8
@@ -110,8 +79,8 @@ mod dl {
         libc::dlopen(ptr::null(), libc::RTLD_LAZY) as *mut u8
     }
 
-    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
-        F: FnOnce() -> T,
+    fn check_for_errors_in<T, F>(f: F) -> Result<T, String>
+        where F: FnOnce() -> T,
     {
         use std::sync::{Mutex, Once};
         static INIT: Once = Once::new();
@@ -139,14 +108,15 @@ mod dl {
         }
     }
 
-    pub unsafe fn symbol(handle: *mut u8,
-                         symbol: *const libc::c_char)
-                         -> Result<*mut u8, String> {
+    pub(super) unsafe fn symbol(
+        handle: *mut u8,
+        symbol: *const libc::c_char,
+    ) -> Result<*mut u8, String> {
         check_for_errors_in(|| {
             libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8
         })
     }
-    pub unsafe fn close(handle: *mut u8) {
+    pub(super) unsafe fn close(handle: *mut u8) {
         libc::dlclose(handle as *mut libc::c_void); ()
     }
 }
@@ -178,11 +148,7 @@ mod dl {
         fn FreeLibrary(handle: HMODULE) -> BOOL;
     }
 
-    pub fn open_global_now(filename: &OsStr) -> Result<*mut u8, String> {
-        open(Some(filename))
-    }
-
-    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
+    pub(super) fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
         // disable "dll load failed" error dialog.
         let prev_error_mode = unsafe {
             // SEM_FAILCRITICALERRORS 0x01
@@ -225,14 +191,15 @@ mod dl {
         result
     }
 
-    pub unsafe fn symbol(handle: *mut u8,
-                         symbol: *const c_char)
-                         -> Result<*mut u8, String> {
+    pub(super) unsafe fn symbol(
+        handle: *mut u8,
+        symbol: *const c_char,
+    ) -> Result<*mut u8, String> {
         let ptr = GetProcAddress(handle as HMODULE, symbol) as *mut u8;
         ptr_result(ptr)
     }
 
-    pub unsafe fn close(handle: *mut u8) {
+    pub(super) unsafe fn close(handle: *mut u8) {
         FreeLibrary(handle as HMODULE);
     }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index bbfbba2e0d8..6ae8c2fc6c6 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1,11 +1,11 @@
-use crate::index::Index;
 use crate::schema::*;
+use crate::table::{FixedSizeEncoding, PerDefTable};
 
 use rustc::middle::cstore::{LinkagePreference, NativeLibrary,
                             EncodedMetadata, ForeignModule};
 use rustc::hir::def::CtorKind;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, LOCAL_CRATE};
-use rustc::hir::GenericParamKind;
+use rustc::hir::{GenericParamKind, AnonConst};
 use rustc::hir::map::definitions::DefPathTable;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_index::vec::IndexVec;
@@ -15,7 +15,7 @@ use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel,
 use rustc::middle::lang_items;
 use rustc::mir::{self, interpret};
 use rustc::traits::specialization_graph;
-use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName};
+use rustc::ty::{self, Ty, TyCtxt, SymbolName};
 use rustc::ty::codec::{self as ty_codec, TyEncoder};
 use rustc::ty::layout::VariantIdx;
 
@@ -23,15 +23,16 @@ use rustc::session::config::{self, CrateType};
 use rustc::util::nodemap::FxHashMap;
 
 use rustc_data_structures::stable_hasher::StableHasher;
+use rustc_data_structures::sync::Lrc;
 use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
 
 use std::hash::Hash;
+use std::num::NonZeroUsize;
 use std::path::Path;
-use rustc_data_structures::sync::Lrc;
 use std::u32;
 use syntax::ast;
 use syntax::attr;
-use syntax::ext::proc_macro::is_proc_macro_attr;
+use syntax_expand::proc_macro::is_proc_macro_attr;
 use syntax::source_map::Spanned;
 use syntax::symbol::{kw, sym, Ident, Symbol};
 use syntax_pos::{self, FileName, SourceFile, Span};
@@ -42,11 +43,11 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc::hir::intravisit;
 
-pub struct EncodeContext<'tcx> {
+struct EncodeContext<'tcx> {
     opaque: opaque::Encoder,
-    pub tcx: TyCtxt<'tcx>,
+    tcx: TyCtxt<'tcx>,
 
-    entries_index: Index<'tcx>,
+    per_def: PerDefTables<'tcx>,
 
     lazy_state: LazyState,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
@@ -59,6 +60,27 @@ pub struct EncodeContext<'tcx> {
     source_file_cache: Lrc<SourceFile>,
 }
 
+#[derive(Default)]
+struct PerDefTables<'tcx> {
+    kind: PerDefTable<Lazy<EntryKind<'tcx>>>,
+    visibility: PerDefTable<Lazy<ty::Visibility>>,
+    span: PerDefTable<Lazy<Span>>,
+    attributes: PerDefTable<Lazy<[ast::Attribute]>>,
+    children: PerDefTable<Lazy<[DefIndex]>>,
+    stability: PerDefTable<Lazy<attr::Stability>>,
+    deprecation: PerDefTable<Lazy<attr::Deprecation>>,
+
+    ty: PerDefTable<Lazy<Ty<'tcx>>>,
+    inherent_impls: PerDefTable<Lazy<[DefIndex]>>,
+    variances: PerDefTable<Lazy<[ty::Variance]>>,
+    generics: PerDefTable<Lazy<ty::Generics>>,
+    predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
+    predicates_defined_on: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
+
+    mir: PerDefTable<Lazy<mir::Body<'tcx>>>,
+    promoted_mir: PerDefTable<Lazy<IndexVec<mir::Promoted, mir::Body<'tcx>>>>,
+}
+
 macro_rules! encoder_methods {
     ($($name:ident($ty:ty);)*) => {
         $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
@@ -97,13 +119,13 @@ impl<'tcx> Encoder for EncodeContext<'tcx> {
     }
 }
 
-impl<'tcx, T> SpecializedEncoder<Lazy<T>> for EncodeContext<'tcx> {
+impl<'tcx, T: Encodable> SpecializedEncoder<Lazy<T>> for EncodeContext<'tcx> {
     fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
         self.emit_lazy_distance(*lazy)
     }
 }
 
-impl<'tcx, T> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> {
+impl<'tcx, T: Encodable> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> {
     fn specialized_encode(&mut self, lazy: &Lazy<[T]>) -> Result<(), Self::Error> {
         self.emit_usize(lazy.meta)?;
         if lazy.meta == 0 {
@@ -113,6 +135,15 @@ impl<'tcx, T> SpecializedEncoder<Lazy<[T]>> for EncodeContext<'tcx> {
     }
 }
 
+impl<'tcx, T> SpecializedEncoder<Lazy<PerDefTable<T>>> for EncodeContext<'tcx>
+    where Option<T>: FixedSizeEncoding,
+{
+    fn specialized_encode(&mut self, lazy: &Lazy<PerDefTable<T>>) -> Result<(), Self::Error> {
+        self.emit_usize(lazy.meta)?;
+        self.emit_lazy_distance(*lazy)
+    }
+}
+
 impl<'tcx> SpecializedEncoder<CrateNum> for EncodeContext<'tcx> {
     #[inline]
     fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
@@ -212,11 +243,11 @@ impl<'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'tcx> {
     }
 }
 
-impl<'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'tcx> {
+impl<'tcx> SpecializedEncoder<&'tcx [(ty::Predicate<'tcx>, Span)]> for EncodeContext<'tcx> {
     fn specialized_encode(&mut self,
-                          predicates: &ty::GenericPredicates<'tcx>)
+                          predicates: &&'tcx [(ty::Predicate<'tcx>, Span)])
                           -> Result<(), Self::Error> {
-        ty_codec::encode_predicates(self, predicates, |ecx| &mut ecx.predicate_shorthands)
+        ty_codec::encode_spanned_predicates(self, predicates, |ecx| &mut ecx.predicate_shorthands)
     }
 }
 
@@ -257,7 +288,7 @@ impl<T: Encodable> EncodeContentsForLazy<T> for T {
     }
 }
 
-impl<I, T> EncodeContentsForLazy<[T]> for I
+impl<I, T: Encodable> EncodeContentsForLazy<[T]> for I
     where I: IntoIterator,
           I::Item: EncodeContentsForLazy<T>,
 {
@@ -266,15 +297,28 @@ impl<I, T> EncodeContentsForLazy<[T]> for I
     }
 }
 
+// Shorthand for `$self.$tables.$table.set($key, $self.lazy($value))`, which would
+// normally need extra variables to avoid errors about multiple mutable borrows.
+macro_rules! record {
+    ($self:ident.$tables:ident.$table:ident[$key:expr] <- $value:expr) => {{
+        {
+            let value = $value;
+            let lazy = $self.lazy(value);
+            $self.$tables.$table.set($key, lazy);
+        }
+    }}
+}
+
 impl<'tcx> EncodeContext<'tcx> {
     fn emit_lazy_distance<T: ?Sized + LazyMeta>(
         &mut self,
         lazy: Lazy<T>,
     ) -> Result<(), <Self as Encoder>::Error> {
-        let min_end = lazy.position + T::min_size(lazy.meta);
+        let min_end = lazy.position.get() + T::min_size(lazy.meta);
         let distance = match self.lazy_state {
             LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
             LazyState::NodeStart(start) => {
+                let start = start.get();
                 assert!(min_end <= start);
                 start - min_end
             }
@@ -284,10 +328,10 @@ impl<'tcx> EncodeContext<'tcx> {
                     "make sure that the calls to `lazy*` \
                     are in the same order as the metadata fields",
                 );
-                lazy.position - last_min_end
+                lazy.position.get() - last_min_end.get()
             }
         };
-        self.lazy_state = LazyState::Previous(min_end);
+        self.lazy_state = LazyState::Previous(NonZeroUsize::new(min_end).unwrap());
         self.emit_usize(distance)
     }
 
@@ -295,42 +339,22 @@ impl<'tcx> EncodeContext<'tcx> {
         &mut self,
         value: impl EncodeContentsForLazy<T>,
     ) -> Lazy<T> {
-        let pos = self.position();
+        let pos = NonZeroUsize::new(self.position()).unwrap();
 
         assert_eq!(self.lazy_state, LazyState::NoNode);
         self.lazy_state = LazyState::NodeStart(pos);
         let meta = value.encode_contents_for_lazy(self);
         self.lazy_state = LazyState::NoNode;
 
-        assert!(pos + <T>::min_size(meta) <= self.position());
+        assert!(pos.get() + <T>::min_size(meta) <= self.position());
 
         Lazy::from_position_and_meta(pos, meta)
     }
 
-    /// Emit the data for a `DefId` to the metadata. The function to
-    /// emit the data is `op`, and it will be given `data` as
-    /// arguments. This `record` function will call `op` to generate
-    /// the `Entry` (which may point to other encoded information)
-    /// and will then record the `Lazy<Entry>` for use in the index.
-    // FIXME(eddyb) remove this.
-    pub fn record<DATA>(&mut self,
-                        id: DefId,
-                        op: impl FnOnce(&mut Self, DATA) -> Entry<'tcx>,
-                        data: DATA)
-    {
-        assert!(id.is_local());
-
-        let entry = op(self, data);
-        let entry = self.lazy(entry);
-        self.entries_index.record(id, entry);
-    }
-
     fn encode_info_for_items(&mut self) {
         let krate = self.tcx.hir().krate();
         let vis = Spanned { span: syntax_pos::DUMMY_SP, node: hir::VisibilityKind::Public };
-        self.record(DefId::local(CRATE_DEF_INDEX),
-                     EncodeContext::encode_info_for_mod,
-                     (hir::CRATE_HIR_ID, &krate.module, &krate.attrs, &vis));
+        self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.module, &krate.attrs, &vis);
         krate.visit_all_item_likes(&mut self.as_deep_visitor());
         for macro_def in &krate.exported_macros {
             self.visit_macro_def(macro_def);
@@ -474,8 +498,26 @@ impl<'tcx> EncodeContext<'tcx> {
 
 
         i = self.position();
-        let entries_index = self.entries_index.write_index(&mut self.opaque);
-        let entries_index_bytes = self.position() - i;
+        let per_def = LazyPerDefTables {
+            kind: self.per_def.kind.encode(&mut self.opaque),
+            visibility: self.per_def.visibility.encode(&mut self.opaque),
+            span: self.per_def.span.encode(&mut self.opaque),
+            attributes: self.per_def.attributes.encode(&mut self.opaque),
+            children: self.per_def.children.encode(&mut self.opaque),
+            stability: self.per_def.stability.encode(&mut self.opaque),
+            deprecation: self.per_def.deprecation.encode(&mut self.opaque),
+
+            ty: self.per_def.ty.encode(&mut self.opaque),
+            inherent_impls: self.per_def.inherent_impls.encode(&mut self.opaque),
+            variances: self.per_def.variances.encode(&mut self.opaque),
+            generics: self.per_def.generics.encode(&mut self.opaque),
+            predicates: self.per_def.predicates.encode(&mut self.opaque),
+            predicates_defined_on: self.per_def.predicates_defined_on.encode(&mut self.opaque),
+
+            mir: self.per_def.mir.encode(&mut self.opaque),
+            promoted_mir: self.per_def.promoted_mir.encode(&mut self.opaque),
+        };
+        let per_def_bytes = self.position() - i;
 
         // Encode the proc macro data
         i = self.position();
@@ -534,7 +576,7 @@ impl<'tcx> EncodeContext<'tcx> {
             impls,
             exported_symbols,
             interpret_alloc_index,
-            entries_index,
+            per_def,
         });
 
         let total_bytes = self.position();
@@ -559,7 +601,7 @@ impl<'tcx> EncodeContext<'tcx> {
             println!("  def-path table bytes: {}", def_path_table_bytes);
             println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
             println!("            item bytes: {}", item_bytes);
-            println!("   entries index bytes: {}", entries_index_bytes);
+            println!("   per-def table bytes: {}", per_def_bytes);
             println!("            zero bytes: {}", zero_bytes);
             println!("           total bytes: {}", total_bytes);
         }
@@ -569,23 +611,21 @@ impl<'tcx> EncodeContext<'tcx> {
 }
 
 impl EncodeContext<'tcx> {
-    fn encode_variances_of(&mut self, def_id: DefId) -> Lazy<[ty::Variance]> {
+    fn encode_variances_of(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_variances_of({:?})", def_id);
-        let tcx = self.tcx;
-        self.lazy(&tcx.variances_of(def_id)[..])
+        record!(self.per_def.variances[def_id] <- &self.tcx.variances_of(def_id)[..]);
     }
 
-    fn encode_item_type(&mut self, def_id: DefId) -> Lazy<Ty<'tcx>> {
-        let tcx = self.tcx;
-        let ty = tcx.type_of(def_id);
-        debug!("EncodeContext::encode_item_type({:?}) => {:?}", def_id, ty);
-        self.lazy(ty)
+    fn encode_item_type(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_item_type({:?})", def_id);
+        record!(self.per_def.ty[def_id] <- self.tcx.type_of(def_id));
     }
 
     fn encode_enum_variant_info(
         &mut self,
-        (enum_did, index): (DefId, VariantIdx),
-    ) -> Entry<'tcx> {
+        enum_did: DefId,
+        index: VariantIdx,
+    ) {
         let tcx = self.tcx;
         let def = tcx.adt_def(enum_did);
         let variant = &def.variants[index];
@@ -607,38 +647,32 @@ impl EncodeContext<'tcx> {
         let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
         let enum_vis = &tcx.hir().expect_item(enum_id).vis;
 
-        Entry {
-            kind: EntryKind::Variant(self.lazy(data)),
-            visibility: self.lazy(ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
-            children: self.lazy(variant.fields.iter().map(|f| {
-                assert!(f.did.is_local());
-                f.did.index
-            })),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: if variant.ctor_kind == CtorKind::Fn {
-                self.encode_variances_of(def_id)
-            } else {
-                Lazy::empty()
-            },
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: self.encode_optimized_mir(def_id),
-            promoted_mir: self.encode_promoted_mir(def_id),
+        record!(self.per_def.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+        record!(self.per_def.visibility[def_id] <-
+            ty::Visibility::from_hir(enum_vis, enum_id, self.tcx));
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
+        record!(self.per_def.children[def_id] <- variant.fields.iter().map(|f| {
+            assert!(f.did.is_local());
+            f.did.index
+        }));
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        self.encode_item_type(def_id);
+        if variant.ctor_kind == CtorKind::Fn {
+            self.encode_variances_of(def_id);
         }
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
+        self.encode_optimized_mir(def_id);
+        self.encode_promoted_mir(def_id);
     }
 
     fn encode_enum_variant_ctor(
         &mut self,
-        (enum_did, index): (DefId, VariantIdx),
-    ) -> Entry<'tcx> {
+        enum_did: DefId,
+        index: VariantIdx,
+    ) {
         let tcx = self.tcx;
         let def = tcx.adt_def(enum_did);
         let variant = &def.variants[index];
@@ -665,35 +699,28 @@ impl EncodeContext<'tcx> {
             ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
         }
 
-        Entry {
-            kind: EntryKind::Variant(self.lazy(data)),
-            visibility: self.lazy(ctor_vis),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: Lazy::empty(),
-            children: Lazy::empty(),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: if variant.ctor_kind == CtorKind::Fn {
-                self.encode_variances_of(def_id)
-            } else {
-                Lazy::empty()
-            },
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: self.encode_optimized_mir(def_id),
-            promoted_mir: self.encode_promoted_mir(def_id),
+        record!(self.per_def.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+        record!(self.per_def.visibility[def_id] <- ctor_vis);
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        self.encode_item_type(def_id);
+        if variant.ctor_kind == CtorKind::Fn {
+            self.encode_variances_of(def_id);
         }
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
+        self.encode_optimized_mir(def_id);
+        self.encode_promoted_mir(def_id);
     }
 
     fn encode_info_for_mod(
         &mut self,
-        (id, md, attrs, vis): (hir::HirId, &hir::Mod, &[ast::Attribute], &hir::Visibility),
-    ) -> Entry<'tcx> {
+        id: hir::HirId,
+        md: &hir::Mod,
+        attrs: &[ast::Attribute],
+        vis: &hir::Visibility,
+    ) {
         let tcx = self.tcx;
         let def_id = tcx.hir().local_def_id(id);
         debug!("EncodeContext::encode_info_for_mod({:?})", def_id);
@@ -705,33 +732,23 @@ impl EncodeContext<'tcx> {
             },
         };
 
-        Entry {
-            kind: EntryKind::Mod(self.lazy(data)),
-            visibility: self.lazy(ty::Visibility::from_hir(vis, id, tcx)),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: self.encode_attributes(attrs),
-            children: self.lazy(md.item_ids.iter().map(|item_id| {
-                tcx.hir().local_def_id(item_id.id).index
-            })),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: None,
-            inherent_impls: Lazy::empty(),
-            variances: Lazy::empty(),
-            generics: None,
-            predicates: None,
-            predicates_defined_on: None,
-
-            mir: None,
-            promoted_mir: None,
-        }
+        record!(self.per_def.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+        record!(self.per_def.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx));
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.per_def.attributes[def_id] <- attrs);
+        record!(self.per_def.children[def_id] <- md.item_ids.iter().map(|item_id| {
+            tcx.hir().local_def_id(item_id.id).index
+        }));
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
     }
 
     fn encode_field(
         &mut self,
-        (adt_def_id, variant_index, field_index): (DefId, VariantIdx, usize),
-    ) -> Entry<'tcx> {
+        adt_def_id: DefId,
+        variant_index: VariantIdx,
+        field_index: usize,
+    ) {
         let tcx = self.tcx;
         let variant = &tcx.adt_def(adt_def_id).variants[variant_index];
         let field = &variant.fields[field_index];
@@ -742,28 +759,18 @@ impl EncodeContext<'tcx> {
         let variant_id = tcx.hir().as_local_hir_id(variant.def_id).unwrap();
         let variant_data = tcx.hir().expect_variant_data(variant_id);
 
-        Entry {
-            kind: EntryKind::Field,
-            visibility: self.lazy(field.vis),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
-            children: Lazy::empty(),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: Lazy::empty(),
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: None,
-            promoted_mir: None,
-        }
+        record!(self.per_def.kind[def_id] <- EntryKind::Field);
+        record!(self.per_def.visibility[def_id] <- field.vis);
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.per_def.attributes[def_id] <- &variant_data.fields()[field_index].attrs);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        self.encode_item_type(def_id);
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
     }
 
-    fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> {
+    fn encode_struct_ctor(&mut self, adt_def_id: DefId, def_id: DefId) {
         debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
         let tcx = self.tcx;
         let adt_def = tcx.adt_def(adt_def_id);
@@ -797,52 +804,38 @@ impl EncodeContext<'tcx> {
             ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
         }
 
-        let repr_options = get_repr_options(tcx, adt_def_id);
-
-        Entry {
-            kind: EntryKind::Struct(self.lazy(data), repr_options),
-            visibility: self.lazy(ctor_vis),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: Lazy::empty(),
-            children: Lazy::empty(),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: if variant.ctor_kind == CtorKind::Fn {
-                self.encode_variances_of(def_id)
-            } else {
-                Lazy::empty()
-            },
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: self.encode_optimized_mir(def_id),
-            promoted_mir: self.encode_promoted_mir(def_id),
+        record!(self.per_def.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
+        record!(self.per_def.visibility[def_id] <- ctor_vis);
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        self.encode_item_type(def_id);
+        if variant.ctor_kind == CtorKind::Fn {
+            self.encode_variances_of(def_id);
         }
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
+        self.encode_optimized_mir(def_id);
+        self.encode_promoted_mir(def_id);
     }
 
-    fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics> {
+    fn encode_generics(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_generics({:?})", def_id);
-        let tcx = self.tcx;
-        self.lazy(tcx.generics_of(def_id))
+        record!(self.per_def.generics[def_id] <- self.tcx.generics_of(def_id));
     }
 
-    fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+    fn encode_predicates(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_predicates({:?})", def_id);
-        let tcx = self.tcx;
-        self.lazy(&*tcx.predicates_of(def_id))
+        record!(self.per_def.predicates[def_id] <- self.tcx.predicates_of(def_id));
     }
 
-    fn encode_predicates_defined_on(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+    fn encode_predicates_defined_on(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_predicates_defined_on({:?})", def_id);
-        let tcx = self.tcx;
-        self.lazy(&*tcx.predicates_defined_on(def_id))
+        record!(self.per_def.predicates_defined_on[def_id] <-
+            self.tcx.predicates_defined_on(def_id))
     }
 
-    fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+    fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
         let tcx = self.tcx;
 
@@ -859,7 +852,7 @@ impl EncodeContext<'tcx> {
                 span_bug!(ast_item.span, "traits cannot have final items"),
         };
 
-        let kind = match trait_item.kind {
+        record!(self.per_def.kind[def_id] <- match trait_item.kind {
             ty::AssocKind::Const => {
                 let rendered =
                     hir::print::to_string(self.tcx.hir(), |s| s.print_trait_item(ast_item));
@@ -868,7 +861,7 @@ impl EncodeContext<'tcx> {
                 EntryKind::AssocConst(container, ConstQualif { mir: 0 }, rendered_const)
             }
             ty::AssocKind::Method => {
-                let fn_data = if let hir::TraitItemKind::Method(method_sig, m) = &ast_item.kind {
+                let fn_data = if let hir::TraitItemKind::Method(m_sig, m) = &ast_item.kind {
                     let param_names = match *m {
                         hir::TraitMethod::Required(ref names) => {
                             self.encode_fn_param_names(names)
@@ -878,10 +871,10 @@ impl EncodeContext<'tcx> {
                         }
                     };
                     FnData {
-                        asyncness: method_sig.header.asyncness,
+                        asyncness: m_sig.header.asyncness,
                         constness: hir::Constness::NotConst,
                         param_names,
-                        sig: self.lazy(&tcx.fn_sig(def_id)),
+                        sig: self.lazy(tcx.fn_sig(def_id)),
                     }
                 } else {
                     bug!()
@@ -894,44 +887,31 @@ impl EncodeContext<'tcx> {
             }
             ty::AssocKind::Type => EntryKind::AssocType(container),
             ty::AssocKind::OpaqueTy => span_bug!(ast_item.span, "opaque type in trait"),
-        };
-
-        Entry {
-            kind,
-            visibility: self.lazy(trait_item.vis),
-            span: self.lazy(ast_item.span),
-            attributes: self.encode_attributes(&ast_item.attrs),
-            children: Lazy::empty(),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: match trait_item.kind {
-                ty::AssocKind::Const |
-                ty::AssocKind::Method => {
-                    Some(self.encode_item_type(def_id))
-                }
-                ty::AssocKind::Type => {
-                    if trait_item.defaultness.has_value() {
-                        Some(self.encode_item_type(def_id))
-                    } else {
-                        None
-                    }
+        });
+        record!(self.per_def.visibility[def_id] <- trait_item.vis);
+        record!(self.per_def.span[def_id] <- ast_item.span);
+        record!(self.per_def.attributes[def_id] <- &ast_item.attrs);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        match trait_item.kind {
+            ty::AssocKind::Const |
+            ty::AssocKind::Method => {
+                self.encode_item_type(def_id);
+            }
+            ty::AssocKind::Type => {
+                if trait_item.defaultness.has_value() {
+                    self.encode_item_type(def_id);
                 }
-                ty::AssocKind::OpaqueTy => unreachable!(),
-            },
-            inherent_impls: Lazy::empty(),
-            variances: if trait_item.kind == ty::AssocKind::Method {
-                self.encode_variances_of(def_id)
-            } else {
-                Lazy::empty()
-            },
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: self.encode_optimized_mir(def_id),
-            promoted_mir: self.encode_promoted_mir(def_id),
+            }
+            ty::AssocKind::OpaqueTy => unreachable!(),
+        }
+        if trait_item.kind == ty::AssocKind::Method {
+            self.encode_variances_of(def_id);
         }
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
+        self.encode_optimized_mir(def_id);
+        self.encode_promoted_mir(def_id);
     }
 
     fn metadata_output_only(&self) -> bool {
@@ -939,7 +919,7 @@ impl EncodeContext<'tcx> {
         !self.tcx.sess.opts.output_types.should_codegen()
     }
 
-    fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+    fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
         let tcx = self.tcx;
 
@@ -954,7 +934,7 @@ impl EncodeContext<'tcx> {
                 span_bug!(ast_item.span, "impl items always have values (currently)"),
         };
 
-        let kind = match impl_item.kind {
+        record!(self.per_def.kind[def_id] <- match impl_item.kind {
             ty::AssocKind::Const => {
                 if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
                     let mir = self.tcx.at(ast_item.span).mir_const_qualif(def_id).0;
@@ -972,7 +952,7 @@ impl EncodeContext<'tcx> {
                         asyncness: sig.header.asyncness,
                         constness: sig.header.constness,
                         param_names: self.encode_fn_param_names_for_body(body),
-                        sig: self.lazy(&tcx.fn_sig(def_id)),
+                        sig: self.lazy(tcx.fn_sig(def_id)),
                     }
                 } else {
                     bug!()
@@ -985,8 +965,18 @@ impl EncodeContext<'tcx> {
             }
             ty::AssocKind::OpaqueTy => EntryKind::AssocOpaqueTy(container),
             ty::AssocKind::Type => EntryKind::AssocType(container)
-        };
-
+        });
+        record!(self.per_def.visibility[def_id] <- impl_item.vis);
+        record!(self.per_def.span[def_id] <- ast_item.span);
+        record!(self.per_def.attributes[def_id] <- &ast_item.attrs);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        self.encode_item_type(def_id);
+        if impl_item.kind == ty::AssocKind::Method {
+            self.encode_variances_of(def_id);
+        }
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
         let mir = match ast_item.kind {
             hir::ImplItemKind::Const(..) => true,
             hir::ImplItemKind::Method(ref sig, _) => {
@@ -1001,29 +991,9 @@ impl EncodeContext<'tcx> {
             hir::ImplItemKind::OpaqueTy(..) |
             hir::ImplItemKind::TyAlias(..) => false,
         };
-
-        Entry {
-            kind,
-            visibility: self.lazy(impl_item.vis),
-            span: self.lazy(ast_item.span),
-            attributes: self.encode_attributes(&ast_item.attrs),
-            children: Lazy::empty(),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: if impl_item.kind == ty::AssocKind::Method {
-                self.encode_variances_of(def_id)
-            } else {
-                Lazy::empty()
-            },
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: if mir { self.encode_optimized_mir(def_id) } else { None },
-            promoted_mir: if mir { self.encode_promoted_mir(def_id) } else { None },
+        if mir {
+            self.encode_optimized_mir(def_id);
+            self.encode_promoted_mir(def_id);
         }
     }
 
@@ -1044,51 +1014,44 @@ impl EncodeContext<'tcx> {
         self.lazy(param_names.iter().map(|ident| ident.name))
     }
 
-    fn encode_optimized_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Body<'tcx>>> {
+    fn encode_optimized_mir(&mut self, def_id: DefId) {
         debug!("EntryBuilder::encode_mir({:?})", def_id);
         if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
-            let mir = self.tcx.optimized_mir(def_id);
-            Some(self.lazy(mir))
-        } else {
-            None
+            record!(self.per_def.mir[def_id] <- self.tcx.optimized_mir(def_id));
         }
     }
 
-    fn encode_promoted_mir(
-        &mut self,
-        def_id: DefId,
-    ) -> Option<Lazy<IndexVec<mir::Promoted, mir::Body<'tcx>>>> {
+    fn encode_promoted_mir(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
         if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
-            let promoted = self.tcx.promoted_mir(def_id);
-            Some(self.lazy(promoted))
-        } else {
-            None
+            record!(self.per_def.promoted_mir[def_id] <- self.tcx.promoted_mir(def_id));
         }
     }
 
     // Encodes the inherent implementations of a structure, enumeration, or trait.
-    fn encode_inherent_implementations(&mut self, def_id: DefId) -> Lazy<[DefIndex]> {
+    fn encode_inherent_implementations(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_inherent_implementations({:?})", def_id);
         let implementations = self.tcx.inherent_impls(def_id);
-        if implementations.is_empty() {
-            Lazy::empty()
-        } else {
-            self.lazy(implementations.iter().map(|&def_id| {
+        if !implementations.is_empty() {
+            record!(self.per_def.inherent_impls[def_id] <- implementations.iter().map(|&def_id| {
                 assert!(def_id.is_local());
                 def_id.index
-            }))
+            }));
         }
     }
 
-    fn encode_stability(&mut self, def_id: DefId) -> Option<Lazy<attr::Stability>> {
+    fn encode_stability(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_stability({:?})", def_id);
-        self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab))
+        if let Some(stab) = self.tcx.lookup_stability(def_id) {
+            record!(self.per_def.stability[def_id] <- stab)
+        }
     }
 
-    fn encode_deprecation(&mut self, def_id: DefId) -> Option<Lazy<attr::Deprecation>> {
+    fn encode_deprecation(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_deprecation({:?})", def_id);
-        self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(depr))
+        if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
+            record!(self.per_def.deprecation[def_id] <- depr);
+        }
     }
 
     fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy<RenderedConst> {
@@ -1098,16 +1061,16 @@ impl EncodeContext<'tcx> {
         self.lazy(rendered_const)
     }
 
-    fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> {
+    fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item) {
         let tcx = self.tcx;
 
         debug!("EncodeContext::encode_info_for_item({:?})", def_id);
 
-        let kind = match item.kind {
+        record!(self.per_def.kind[def_id] <- match item.kind {
             hir::ItemKind::Static(_, hir::MutMutable, _) => EntryKind::MutStatic,
             hir::ItemKind::Static(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
             hir::ItemKind::Const(_, body_id) => {
-                let mir = tcx.at(item.span).mir_const_qualif(def_id).0;
+                let mir = self.tcx.at(item.span).mir_const_qualif(def_id).0;
                 EntryKind::Const(
                     ConstQualif { mir },
                     self.encode_rendered_const_for_body(body_id)
@@ -1124,48 +1087,48 @@ impl EncodeContext<'tcx> {
                 EntryKind::Fn(self.lazy(data))
             }
             hir::ItemKind::Mod(ref m) => {
-                return self.encode_info_for_mod((item.hir_id, m, &item.attrs, &item.vis));
+                return self.encode_info_for_mod(item.hir_id, m, &item.attrs, &item.vis);
             }
             hir::ItemKind::ForeignMod(_) => EntryKind::ForeignMod,
             hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
             hir::ItemKind::TyAlias(..) => EntryKind::Type,
             hir::ItemKind::OpaqueTy(..) => EntryKind::OpaqueTy,
-            hir::ItemKind::Enum(..) => EntryKind::Enum(get_repr_options(tcx, def_id)),
+            hir::ItemKind::Enum(..) => EntryKind::Enum(self.tcx.adt_def(def_id).repr),
             hir::ItemKind::Struct(ref struct_def, _) => {
-                let variant = tcx.adt_def(def_id).non_enum_variant();
+                let adt_def = self.tcx.adt_def(def_id);
+                let variant = adt_def.non_enum_variant();
 
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
                 // needs to know
-                let ctor = struct_def.ctor_hir_id()
-                    .map(|ctor_hir_id| tcx.hir().local_def_id(ctor_hir_id).index);
-
-                let repr_options = get_repr_options(tcx, def_id);
+                let ctor = struct_def.ctor_hir_id().map(|ctor_hir_id| {
+                    self.tcx.hir().local_def_id(ctor_hir_id).index
+                });
 
                 EntryKind::Struct(self.lazy(VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
                     ctor,
                     ctor_sig: None,
-                }), repr_options)
+                }), adt_def.repr)
             }
             hir::ItemKind::Union(..) => {
-                let variant = tcx.adt_def(def_id).non_enum_variant();
-                let repr_options = get_repr_options(tcx, def_id);
+                let adt_def = self.tcx.adt_def(def_id);
+                let variant = adt_def.non_enum_variant();
 
                 EntryKind::Union(self.lazy(VariantData {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
                     ctor: None,
                     ctor_sig: None,
-                }), repr_options)
+                }), adt_def.repr)
             }
             hir::ItemKind::Impl(_, _, defaultness, ..) => {
-                let trait_ref = tcx.impl_trait_ref(def_id);
-                let polarity = tcx.impl_polarity(def_id);
+                let trait_ref = self.tcx.impl_trait_ref(def_id);
+                let polarity = self.tcx.impl_polarity(def_id);
                 let parent = if let Some(trait_ref) = trait_ref {
-                    let trait_def = tcx.trait_def(trait_ref.def_id);
-                    trait_def.ancestors(tcx, def_id).nth(1).and_then(|node| {
+                    let trait_def = self.tcx.trait_def(trait_ref.def_id);
+                    trait_def.ancestors(self.tcx, def_id).nth(1).and_then(|node| {
                         match node {
                             specialization_graph::Node::Impl(parent) => Some(parent),
                             _ => None,
@@ -1179,8 +1142,8 @@ impl EncodeContext<'tcx> {
                 // "unsized info", else just store None
                 let coerce_unsized_info =
                     trait_ref.and_then(|t| {
-                        if Some(t.def_id) == tcx.lang_items().coerce_unsized_trait() {
-                            Some(tcx.at(item.span).coerce_unsized_info(def_id))
+                        if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
+                            Some(self.tcx.at(item.span).coerce_unsized_info(def_id))
                         } else {
                             None
                         }
@@ -1197,27 +1160,115 @@ impl EncodeContext<'tcx> {
                 EntryKind::Impl(self.lazy(data))
             }
             hir::ItemKind::Trait(..) => {
-                let trait_def = tcx.trait_def(def_id);
+                let trait_def = self.tcx.trait_def(def_id);
                 let data = TraitData {
                     unsafety: trait_def.unsafety,
                     paren_sugar: trait_def.paren_sugar,
-                    has_auto_impl: tcx.trait_is_auto(def_id),
+                    has_auto_impl: self.tcx.trait_is_auto(def_id),
                     is_marker: trait_def.is_marker,
-                    super_predicates: self.lazy(&*tcx.super_predicates_of(def_id)),
+                    super_predicates: self.lazy(tcx.super_predicates_of(def_id)),
                 };
 
                 EntryKind::Trait(self.lazy(data))
             }
             hir::ItemKind::TraitAlias(..) => {
                 let data = TraitAliasData {
-                    super_predicates: self.lazy(&*tcx.super_predicates_of(def_id)),
+                    super_predicates: self.lazy(tcx.super_predicates_of(def_id)),
                 };
 
                 EntryKind::TraitAlias(self.lazy(data))
             }
             hir::ItemKind::ExternCrate(_) |
             hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
-        };
+        });
+        record!(self.per_def.visibility[def_id] <-
+            ty::Visibility::from_hir(&item.vis, item.hir_id, tcx));
+        record!(self.per_def.span[def_id] <- item.span);
+        record!(self.per_def.attributes[def_id] <- &item.attrs);
+        // FIXME(eddyb) there should be a nicer way to do this.
+        match item.kind {
+            hir::ItemKind::ForeignMod(ref fm) => record!(self.per_def.children[def_id] <-
+                fm.items
+                    .iter()
+                    .map(|foreign_item| tcx.hir().local_def_id(
+                        foreign_item.hir_id).index)
+            ),
+            hir::ItemKind::Enum(..) => record!(self.per_def.children[def_id] <-
+                self.tcx.adt_def(def_id).variants.iter().map(|v| {
+                    assert!(v.def_id.is_local());
+                    v.def_id.index
+                })
+            ),
+            hir::ItemKind::Struct(..) |
+            hir::ItemKind::Union(..) => record!(self.per_def.children[def_id] <-
+                self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
+                    assert!(f.did.is_local());
+                    f.did.index
+                })
+            ),
+            hir::ItemKind::Impl(..) |
+            hir::ItemKind::Trait(..) => {
+                let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
+                record!(self.per_def.children[def_id] <-
+                    associated_item_def_ids.iter().map(|&def_id| {
+                        assert!(def_id.is_local());
+                        def_id.index
+                    })
+                );
+            }
+            _ => {}
+        }
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        match item.kind {
+            hir::ItemKind::Static(..) |
+            hir::ItemKind::Const(..) |
+            hir::ItemKind::Fn(..) |
+            hir::ItemKind::TyAlias(..) |
+            hir::ItemKind::OpaqueTy(..) |
+            hir::ItemKind::Enum(..) |
+            hir::ItemKind::Struct(..) |
+            hir::ItemKind::Union(..) |
+            hir::ItemKind::Impl(..) => self.encode_item_type(def_id),
+            _ => {}
+        }
+        self.encode_inherent_implementations(def_id);
+        match item.kind {
+            hir::ItemKind::Enum(..) |
+            hir::ItemKind::Struct(..) |
+            hir::ItemKind::Union(..) |
+            hir::ItemKind::Fn(..) => self.encode_variances_of(def_id),
+            _ => {}
+        }
+        match item.kind {
+            hir::ItemKind::Static(..) |
+            hir::ItemKind::Const(..) |
+            hir::ItemKind::Fn(..) |
+            hir::ItemKind::TyAlias(..) |
+            hir::ItemKind::Enum(..) |
+            hir::ItemKind::Struct(..) |
+            hir::ItemKind::Union(..) |
+            hir::ItemKind::Impl(..) |
+            hir::ItemKind::OpaqueTy(..) |
+            hir::ItemKind::Trait(..) |
+            hir::ItemKind::TraitAlias(..) => {
+                self.encode_generics(def_id);
+                self.encode_predicates(def_id);
+            }
+            _ => {}
+        }
+        // The only time that `predicates_defined_on` is used (on
+        // an external item) is for traits, during chalk lowering,
+        // so only encode it in that case as an efficiency
+        // hack. (No reason not to expand it in the future if
+        // necessary.)
+        match item.kind {
+            hir::ItemKind::Trait(..) |
+            hir::ItemKind::TraitAlias(..) => {
+                self.encode_predicates_defined_on(def_id);
+            }
+            _ => {} // not *wrong* for other kinds of items, but not needed
+        }
 
         let mir = match item.kind {
             hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
@@ -1232,188 +1283,48 @@ impl EncodeContext<'tcx> {
             }
             _ => false,
         };
-
-        Entry {
-            kind,
-            visibility: self.lazy(ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)),
-            span: self.lazy(item.span),
-            attributes: self.encode_attributes(&item.attrs),
-            children: match item.kind {
-                hir::ItemKind::ForeignMod(ref fm) => {
-                    self.lazy(fm.items
-                        .iter()
-                        .map(|foreign_item| tcx.hir().local_def_id(
-                            foreign_item.hir_id).index))
-                }
-                hir::ItemKind::Enum(..) => {
-                    let def = self.tcx.adt_def(def_id);
-                    self.lazy(def.variants.iter().map(|v| {
-                        assert!(v.def_id.is_local());
-                        v.def_id.index
-                    }))
-                }
-                hir::ItemKind::Struct(..) |
-                hir::ItemKind::Union(..) => {
-                    let def = self.tcx.adt_def(def_id);
-                    self.lazy(def.non_enum_variant().fields.iter().map(|f| {
-                        assert!(f.did.is_local());
-                        f.did.index
-                    }))
-                }
-                hir::ItemKind::Impl(..) |
-                hir::ItemKind::Trait(..) => {
-                    self.lazy(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| {
-                        assert!(def_id.is_local());
-                        def_id.index
-                    }))
-                }
-                _ => Lazy::empty(),
-            },
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: match item.kind {
-                hir::ItemKind::Static(..) |
-                hir::ItemKind::Const(..) |
-                hir::ItemKind::Fn(..) |
-                hir::ItemKind::TyAlias(..) |
-                hir::ItemKind::OpaqueTy(..) |
-                hir::ItemKind::Enum(..) |
-                hir::ItemKind::Struct(..) |
-                hir::ItemKind::Union(..) |
-                hir::ItemKind::Impl(..) => Some(self.encode_item_type(def_id)),
-                _ => None,
-            },
-            inherent_impls: self.encode_inherent_implementations(def_id),
-            variances: match item.kind {
-                hir::ItemKind::Enum(..) |
-                hir::ItemKind::Struct(..) |
-                hir::ItemKind::Union(..) |
-                hir::ItemKind::Fn(..) => self.encode_variances_of(def_id),
-                _ => Lazy::empty(),
-            },
-            generics: match item.kind {
-                hir::ItemKind::Static(..) |
-                hir::ItemKind::Const(..) |
-                hir::ItemKind::Fn(..) |
-                hir::ItemKind::TyAlias(..) |
-                hir::ItemKind::Enum(..) |
-                hir::ItemKind::Struct(..) |
-                hir::ItemKind::Union(..) |
-                hir::ItemKind::Impl(..) |
-                hir::ItemKind::OpaqueTy(..) |
-                hir::ItemKind::Trait(..) => Some(self.encode_generics(def_id)),
-                hir::ItemKind::TraitAlias(..) => Some(self.encode_generics(def_id)),
-                _ => None,
-            },
-            predicates: match item.kind {
-                hir::ItemKind::Static(..) |
-                hir::ItemKind::Const(..) |
-                hir::ItemKind::Fn(..) |
-                hir::ItemKind::TyAlias(..) |
-                hir::ItemKind::Enum(..) |
-                hir::ItemKind::Struct(..) |
-                hir::ItemKind::Union(..) |
-                hir::ItemKind::Impl(..) |
-                hir::ItemKind::OpaqueTy(..) |
-                hir::ItemKind::Trait(..) |
-                hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates(def_id)),
-                _ => None,
-            },
-
-            // The only time that `predicates_defined_on` is used (on
-            // an external item) is for traits, during chalk lowering,
-            // so only encode it in that case as an efficiency
-            // hack. (No reason not to expand it in the future if
-            // necessary.)
-            predicates_defined_on: match item.kind {
-                hir::ItemKind::Trait(..) |
-                hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates_defined_on(def_id)),
-                _ => None, // not *wrong* for other kinds of items, but not needed
-            },
-
-            mir: if mir { self.encode_optimized_mir(def_id) } else { None },
-            promoted_mir: if mir { self.encode_promoted_mir(def_id) } else { None },
+        if mir {
+            self.encode_optimized_mir(def_id);
+            self.encode_promoted_mir(def_id);
         }
     }
 
     /// Serialize the text of exported macros
-    fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> {
+    fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) {
         use syntax::print::pprust;
         let def_id = self.tcx.hir().local_def_id(macro_def.hir_id);
-        Entry {
-            kind: EntryKind::MacroDef(self.lazy(MacroDef {
-                body: pprust::tts_to_string(macro_def.body.clone()),
-                legacy: macro_def.legacy,
-            })),
-            visibility: self.lazy(ty::Visibility::Public),
-            span: self.lazy(macro_def.span),
-            attributes: self.encode_attributes(&macro_def.attrs),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            children: Lazy::empty(),
-            ty: None,
-            inherent_impls: Lazy::empty(),
-            variances: Lazy::empty(),
-            generics: None,
-            predicates: None,
-            predicates_defined_on: None,
-            mir: None,
-            promoted_mir: None,
-        }
+        record!(self.per_def.kind[def_id] <- EntryKind::MacroDef(self.lazy(MacroDef {
+            body: pprust::tts_to_string(macro_def.body.clone()),
+            legacy: macro_def.legacy,
+        })));
+        record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
+        record!(self.per_def.span[def_id] <- macro_def.span);
+        record!(self.per_def.attributes[def_id] <- &macro_def.attrs);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
     }
 
     fn encode_info_for_generic_param(
         &mut self,
         def_id: DefId,
-        entry_kind: EntryKind<'tcx>,
+        kind: EntryKind<'tcx>,
         encode_type: bool,
-    ) -> Entry<'tcx> {
-        let tcx = self.tcx;
-        Entry {
-            kind: entry_kind,
-            visibility: self.lazy(ty::Visibility::Public),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: Lazy::empty(),
-            children: Lazy::empty(),
-            stability: None,
-            deprecation: None,
-            ty: if encode_type { Some(self.encode_item_type(def_id)) } else { None },
-            inherent_impls: Lazy::empty(),
-            variances: Lazy::empty(),
-            generics: None,
-            predicates: None,
-            predicates_defined_on: None,
-
-            mir: None,
-            promoted_mir: None,
+    ) {
+        record!(self.per_def.kind[def_id] <- kind);
+        record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        if encode_type {
+            self.encode_item_type(def_id);
         }
     }
 
-    fn encode_info_for_ty_param(
-        &mut self,
-        (def_id, encode_type): (DefId, bool),
-    ) -> Entry<'tcx> {
-        debug!("EncodeContext::encode_info_for_ty_param({:?})", def_id);
-        self.encode_info_for_generic_param(def_id, EntryKind::TypeParam, encode_type)
-    }
-
-    fn encode_info_for_const_param(
-        &mut self,
-        def_id: DefId,
-    ) -> Entry<'tcx> {
-        debug!("EncodeContext::encode_info_for_const_param({:?})", def_id);
-        self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true)
-    }
-
-    fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
+    fn encode_info_for_closure(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
-        let tcx = self.tcx;
 
         let tables = self.tcx.typeck_tables_of(def_id);
         let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap();
-        let kind = match tables.node_type(hir_id).kind {
+
+        record!(self.per_def.kind[def_id] <- match tables.node_type(hir_id).kind {
             ty::Generator(def_id, ..) => {
                 let layout = self.tcx.generator_layout(def_id);
                 let data = GeneratorData {
@@ -1428,61 +1339,32 @@ impl EncodeContext<'tcx> {
                 EntryKind::Closure(self.lazy(data))
             }
 
-            _ => bug!("closure that is neither generator nor closure")
-        };
-
-        Entry {
-            kind,
-            visibility: self.lazy(ty::Visibility::Public),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
-            children: Lazy::empty(),
-            stability: None,
-            deprecation: None,
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: Lazy::empty(),
-            generics: Some(self.encode_generics(def_id)),
-            predicates: None,
-            predicates_defined_on: None,
-
-            mir: self.encode_optimized_mir(def_id),
-            promoted_mir: self.encode_promoted_mir(def_id),
-        }
+            _ => bug!("closure that is neither generator nor closure"),
+        });
+        record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.per_def.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
+        self.encode_item_type(def_id);
+        self.encode_generics(def_id);
+        self.encode_optimized_mir(def_id);
+        self.encode_promoted_mir(def_id);
     }
 
-    fn encode_info_for_anon_const(&mut self, def_id: DefId) -> Entry<'tcx> {
+    fn encode_info_for_anon_const(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id);
-        let tcx = self.tcx;
-        let id = tcx.hir().as_local_hir_id(def_id).unwrap();
-        let body_id = tcx.hir().body_owned_by(id);
+        let id = self.tcx.hir().as_local_hir_id(def_id).unwrap();
+        let body_id = self.tcx.hir().body_owned_by(id);
         let const_data = self.encode_rendered_const_for_body(body_id);
-        let mir = tcx.mir_const_qualif(def_id).0;
-
-        Entry {
-            kind: EntryKind::Const(ConstQualif { mir }, const_data),
-            visibility: self.lazy(ty::Visibility::Public),
-            span: self.lazy(tcx.def_span(def_id)),
-            attributes: Lazy::empty(),
-            children: Lazy::empty(),
-            stability: None,
-            deprecation: None,
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: Lazy::empty(),
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: self.encode_optimized_mir(def_id),
-            promoted_mir: self.encode_promoted_mir(def_id),
-        }
-    }
+        let mir = self.tcx.mir_const_qualif(def_id).0;
 
-    fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> Lazy<[ast::Attribute]> {
-        self.lazy(attrs)
+        record!(self.per_def.kind[def_id] <- EntryKind::Const(ConstQualif { mir }, const_data));
+        record!(self.per_def.visibility[def_id] <- ty::Visibility::Public);
+        record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id));
+        self.encode_item_type(def_id);
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
+        self.encode_optimized_mir(def_id);
+        self.encode_promoted_mir(def_id);
     }
 
     fn encode_native_libraries(&mut self) -> Lazy<[NativeLibrary]> {
@@ -1656,14 +1538,16 @@ impl EncodeContext<'tcx> {
         Lazy::empty()
     }
 
-    fn encode_info_for_foreign_item(&mut self,
-                                    (def_id, nitem): (DefId, &hir::ForeignItem))
-                                    -> Entry<'tcx> {
+    fn encode_info_for_foreign_item(
+        &mut self,
+        def_id: DefId,
+        nitem: &hir::ForeignItem,
+    )  {
         let tcx = self.tcx;
 
         debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id);
 
-        let kind = match nitem.kind {
+        record!(self.per_def.kind[def_id] <- match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
                 let data = FnData {
                     asyncness: hir::IsAsync::NotAsync,
@@ -1676,33 +1560,23 @@ impl EncodeContext<'tcx> {
             hir::ForeignItemKind::Static(_, hir::MutMutable) => EntryKind::ForeignMutStatic,
             hir::ForeignItemKind::Static(_, hir::MutImmutable) => EntryKind::ForeignImmStatic,
             hir::ForeignItemKind::Type => EntryKind::ForeignType,
-        };
-
-        Entry {
-            kind,
-            visibility: self.lazy(ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, tcx)),
-            span: self.lazy(nitem.span),
-            attributes: self.encode_attributes(&nitem.attrs),
-            children: Lazy::empty(),
-            stability: self.encode_stability(def_id),
-            deprecation: self.encode_deprecation(def_id),
-
-            ty: Some(self.encode_item_type(def_id)),
-            inherent_impls: Lazy::empty(),
-            variances: match nitem.kind {
-                hir::ForeignItemKind::Fn(..) => self.encode_variances_of(def_id),
-                _ => Lazy::empty(),
-            },
-            generics: Some(self.encode_generics(def_id)),
-            predicates: Some(self.encode_predicates(def_id)),
-            predicates_defined_on: None,
-
-            mir: None,
-            promoted_mir: None,
+        });
+        record!(self.per_def.visibility[def_id] <-
+            ty::Visibility::from_hir(&nitem.vis, nitem.hir_id, self.tcx));
+        record!(self.per_def.span[def_id] <- nitem.span);
+        record!(self.per_def.attributes[def_id] <- &nitem.attrs);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
+        self.encode_item_type(def_id);
+        if let hir::ForeignItemKind::Fn(..) = nitem.kind {
+            self.encode_variances_of(def_id);
         }
+        self.encode_generics(def_id);
+        self.encode_predicates(def_id);
     }
 }
 
+// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
 impl Visitor<'tcx> for EncodeContext<'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir())
@@ -1711,45 +1585,32 @@ impl Visitor<'tcx> for EncodeContext<'tcx> {
         intravisit::walk_expr(self, ex);
         self.encode_info_for_expr(ex);
     }
+    fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
+        intravisit::walk_anon_const(self, c);
+        let def_id = self.tcx.hir().local_def_id(c.hir_id);
+        self.encode_info_for_anon_const(def_id);
+    }
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         intravisit::walk_item(self, item);
         let def_id = self.tcx.hir().local_def_id(item.hir_id);
         match item.kind {
             hir::ItemKind::ExternCrate(_) |
             hir::ItemKind::Use(..) => {} // ignore these
-            _ => self.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)),
+            _ => self.encode_info_for_item(def_id, item),
         }
         self.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
         intravisit::walk_foreign_item(self, ni);
         let def_id = self.tcx.hir().local_def_id(ni.hir_id);
-        self.record(def_id,
-                          EncodeContext::encode_info_for_foreign_item,
-                          (def_id, ni));
-    }
-    fn visit_variant(&mut self,
-                     v: &'tcx hir::Variant,
-                     g: &'tcx hir::Generics,
-                     id: hir::HirId) {
-        intravisit::walk_variant(self, v, g, id);
-
-        if let Some(ref discr) = v.disr_expr {
-            let def_id = self.tcx.hir().local_def_id(discr.hir_id);
-            self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id);
-        }
+        self.encode_info_for_foreign_item(def_id, ni);
     }
     fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
         intravisit::walk_generics(self, generics);
         self.encode_info_for_generics(generics);
     }
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        intravisit::walk_ty(self, ty);
-        self.encode_info_for_ty(ty);
-    }
     fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) {
-        let def_id = self.tcx.hir().local_def_id(macro_def.hir_id);
-        self.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def);
+        self.encode_info_for_macro_def(macro_def);
     }
 }
 
@@ -1757,10 +1618,10 @@ impl EncodeContext<'tcx> {
     fn encode_fields(&mut self, adt_def_id: DefId) {
         let def = self.tcx.adt_def(adt_def_id);
         for (variant_index, variant) in def.variants.iter_enumerated() {
-            for (field_index, field) in variant.fields.iter().enumerate() {
-                self.record(field.did,
-                            EncodeContext::encode_field,
-                            (adt_def_id, variant_index, field_index));
+            for (field_index, _field) in variant.fields.iter().enumerate() {
+                // FIXME(eddyb) `adt_def_id` is leftover from incremental isolation,
+                // pass `def`, `variant` or `field` instead.
+                self.encode_field(adt_def_id, variant_index, field_index);
             }
         }
     }
@@ -1771,34 +1632,24 @@ impl EncodeContext<'tcx> {
             match param.kind {
                 GenericParamKind::Lifetime { .. } => continue,
                 GenericParamKind::Type { ref default, .. } => {
-                    self.record(
+                    self.encode_info_for_generic_param(
                         def_id,
-                        EncodeContext::encode_info_for_ty_param,
-                        (def_id, default.is_some()),
+                        EntryKind::TypeParam,
+                        default.is_some(),
                     );
                 }
                 GenericParamKind::Const { .. } => {
-                    self.record(def_id, EncodeContext::encode_info_for_const_param, def_id);
+                    self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true);
                 }
             }
         }
     }
 
-    fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
-        match ty.kind {
-            hir::TyKind::Array(_, ref length) => {
-                let def_id = self.tcx.hir().local_def_id(length.hir_id);
-                self.record(def_id, EncodeContext::encode_info_for_anon_const, def_id);
-            }
-            _ => {}
-        }
-    }
-
     fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
         match expr.kind {
             hir::ExprKind::Closure(..) => {
                 let def_id = self.tcx.hir().local_def_id(expr.hir_id);
-                self.record(def_id, EncodeContext::encode_info_for_closure, def_id);
+                self.encode_info_for_closure(def_id);
             }
             _ => {}
         }
@@ -1829,14 +1680,14 @@ impl EncodeContext<'tcx> {
 
                 let def = self.tcx.adt_def(def_id);
                 for (i, variant) in def.variants.iter_enumerated() {
-                    self.record(variant.def_id,
-                                EncodeContext::encode_enum_variant_info,
-                                (def_id, i));
-
-                    if let Some(ctor_def_id) = variant.ctor_def_id {
-                        self.record(ctor_def_id,
-                                    EncodeContext::encode_enum_variant_ctor,
-                                    (def_id, i));
+                    // FIXME(eddyb) `def_id` is leftover from incremental isolation,
+                    // pass `def` or `variant` instead.
+                    self.encode_enum_variant_info(def_id, i);
+
+                    // FIXME(eddyb) `def_id` is leftover from incremental isolation,
+                    // pass `def`, `variant` or `ctor_def_id` instead.
+                    if let Some(_ctor_def_id) = variant.ctor_def_id {
+                        self.encode_enum_variant_ctor(def_id, i);
                     }
                 }
             }
@@ -1846,9 +1697,7 @@ impl EncodeContext<'tcx> {
                 // If the struct has a constructor, encode it.
                 if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
                     let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
-                    self.record(ctor_def_id,
-                                EncodeContext::encode_struct_ctor,
-                                (def_id, ctor_def_id));
+                    self.encode_struct_ctor(def_id, ctor_def_id);
                 }
             }
             hir::ItemKind::Union(..) => {
@@ -1856,16 +1705,12 @@ impl EncodeContext<'tcx> {
             }
             hir::ItemKind::Impl(..) => {
                 for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() {
-                    self.record(trait_item_def_id,
-                                EncodeContext::encode_info_for_impl_item,
-                                trait_item_def_id);
+                    self.encode_info_for_impl_item(trait_item_def_id);
                 }
             }
             hir::ItemKind::Trait(..) => {
                 for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() {
-                    self.record(item_def_id,
-                                EncodeContext::encode_info_for_trait_item,
-                                item_def_id);
+                    self.encode_info_for_trait_item(item_def_id);
                 }
             }
         }
@@ -1920,7 +1765,7 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
 // will allow us to slice the metadata to the precise length that we just
 // generated regardless of trailing bytes that end up in it.
 
-pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
+crate fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
     let mut encoder = opaque::Encoder::new(vec![]);
     encoder.emit_raw_bytes(METADATA_HEADER);
 
@@ -1933,7 +1778,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
         let mut ecx = EncodeContext {
             opaque: encoder,
             tcx,
-            entries_index: Index::new(tcx.hir().definitions().def_index_count()),
+            per_def: Default::default(),
             lazy_state: LazyState::NoNode,
             type_shorthands: Default::default(),
             predicate_shorthands: Default::default(),
@@ -1953,7 +1798,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
 
     // Encode the root position.
     let header = METADATA_HEADER.len();
-    let pos = root.position;
+    let pos = root.position.get();
     result[header + 0] = (pos >> 24) as u8;
     result[header + 1] = (pos >> 16) as u8;
     result[header + 2] = (pos >> 8) as u8;
@@ -1961,11 +1806,3 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
 
     EncodedMetadata { raw_data: result }
 }
-
-pub fn get_repr_options(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions {
-    let ty = tcx.type_of(did);
-    match ty.kind {
-        ty::Adt(ref def, _) => return def.repr,
-        _ => bug!("{} is not an ADT", ty),
-    }
-}
diff --git a/src/librustc_metadata/foreign_modules.rs b/src/librustc_metadata/foreign_modules.rs
index 8a4f6e6f17a..fa1402584ed 100644
--- a/src/librustc_metadata/foreign_modules.rs
+++ b/src/librustc_metadata/foreign_modules.rs
@@ -3,7 +3,7 @@ use rustc::hir;
 use rustc::middle::cstore::ForeignModule;
 use rustc::ty::TyCtxt;
 
-pub fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
+crate fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
     let mut collector = Collector {
         tcx,
         modules: Vec::new(),
diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs
deleted file mode 100644
index 6f248f22cf2..00000000000
--- a/src/librustc_metadata/index.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use crate::schema::*;
-
-use rustc::hir::def_id::{DefId, DefIndex};
-use rustc_serialize::opaque::Encoder;
-use std::marker::PhantomData;
-use std::u32;
-use log::debug;
-
-/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
-pub trait FixedSizeEncoding {
-    const BYTE_LEN: usize;
-
-    // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
-    // once that starts being allowed by the compiler (i.e. lazy normalization).
-    fn from_bytes(b: &[u8]) -> Self;
-    fn write_to_bytes(self, b: &mut [u8]);
-
-    // FIXME(eddyb) make these generic functions, or at least defaults here.
-    // (same problem as above, needs `[u8; Self::BYTE_LEN]`)
-    // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
-    fn read_from_bytes_at(b: &[u8], i: usize) -> Self;
-    fn write_to_bytes_at(self, b: &mut [u8], i: usize);
-}
-
-// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
-macro_rules! fixed_size_encoding_byte_len_and_defaults {
-    ($byte_len:expr) => {
-        const BYTE_LEN: usize = $byte_len;
-        fn read_from_bytes_at(b: &[u8], i: usize) -> Self {
-            const BYTE_LEN: usize = $byte_len;
-            // HACK(eddyb) ideally this would be done with fully safe code,
-            // but slicing `[u8]` with `i * N..` is optimized worse, due to the
-            // possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
-            let b = unsafe {
-                std::slice::from_raw_parts(
-                    b.as_ptr() as *const [u8; BYTE_LEN],
-                    b.len() / BYTE_LEN,
-                )
-            };
-            Self::from_bytes(&b[i])
-        }
-        fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
-            const BYTE_LEN: usize = $byte_len;
-            // HACK(eddyb) ideally this would be done with fully safe code,
-            // see similar comment in `read_from_bytes_at` for why it can't yet.
-            let b = unsafe {
-                std::slice::from_raw_parts_mut(
-                    b.as_mut_ptr() as *mut [u8; BYTE_LEN],
-                    b.len() / BYTE_LEN,
-                )
-            };
-            self.write_to_bytes(&mut b[i]);
-        }
-    }
-}
-
-impl FixedSizeEncoding for u32 {
-    fixed_size_encoding_byte_len_and_defaults!(4);
-
-    fn from_bytes(b: &[u8]) -> Self {
-        let mut bytes = [0; Self::BYTE_LEN];
-        bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
-        Self::from_le_bytes(bytes)
-    }
-
-    fn write_to_bytes(self, b: &mut [u8]) {
-        b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
-    }
-}
-
-/// While we are generating the metadata, we also track the position
-/// of each DefIndex. It is not required that all definitions appear
-/// in the metadata, nor that they are serialized in order, and
-/// therefore we first allocate the vector here and fill it with
-/// `u32::MAX`. Whenever an index is visited, we fill in the
-/// appropriate spot by calling `record_position`. We should never
-/// visit the same index twice.
-pub struct Index<'tcx> {
-    positions: Vec<u8>,
-    _marker: PhantomData<&'tcx ()>,
-}
-
-impl Index<'tcx> {
-    pub fn new(max_index: usize) -> Self {
-        Index {
-            positions: vec![0xff; max_index * 4],
-            _marker: PhantomData,
-        }
-    }
-
-    pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'tcx>>) {
-        assert!(def_id.is_local());
-        self.record_index(def_id.index, entry);
-    }
-
-    pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'tcx>>) {
-        assert!(entry.position < (u32::MAX as usize));
-        let position = entry.position as u32;
-        let array_index = item.index();
-
-        let positions = &mut self.positions;
-        assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX,
-                "recorded position for item {:?} twice, first at {:?} and now at {:?}",
-                item,
-                u32::read_from_bytes_at(positions, array_index),
-                position);
-
-        position.write_to_bytes_at(positions, array_index)
-    }
-
-    pub fn write_index(&self, buf: &mut Encoder) -> Lazy<[Self]> {
-        let pos = buf.position();
-
-        // First we write the length of the lower range ...
-        buf.emit_raw_bytes(&(self.positions.len() as u32 / 4).to_le_bytes());
-        // ... then the values.
-        buf.emit_raw_bytes(&self.positions);
-        Lazy::from_position_and_meta(pos as usize, self.positions.len() / 4 + 1)
-    }
-}
-
-impl Lazy<[Index<'tcx>]> {
-    /// Given the metadata, extract out the offset of a particular
-    /// DefIndex (if any).
-    #[inline(never)]
-    pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
-        let bytes = &bytes[self.position..];
-        debug!("Index::lookup: index={:?} len={:?}",
-               def_index,
-               self.meta);
-
-        let position = u32::read_from_bytes_at(bytes, 1 + def_index.index());
-        if position == u32::MAX {
-            debug!("Index::lookup: position=u32::MAX");
-            None
-        } else {
-            debug!("Index::lookup: position={:?}", position);
-            Some(Lazy::from_position(position as usize))
-        }
-    }
-}
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 6aa684b1c3d..291ee23ff72 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -26,15 +26,15 @@ extern crate rustc_data_structures;
 
 pub mod error_codes;
 
-mod index;
 mod encoder;
 mod decoder;
+mod dependency_format;
 mod cstore_impl;
-mod schema;
-mod native_libs;
-mod link_args;
 mod foreign_modules;
-mod dependency_format;
+mod link_args;
+mod native_libs;
+mod schema;
+mod table;
 
 pub mod creader;
 pub mod cstore;
diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs
index 527d4421fca..4291f3a4ae3 100644
--- a/src/librustc_metadata/link_args.rs
+++ b/src/librustc_metadata/link_args.rs
@@ -4,7 +4,7 @@ use rustc::ty::TyCtxt;
 use rustc_target::spec::abi::Abi;
 use syntax::symbol::sym;
 
-pub fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
+crate fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
     let mut collector = Collector {
         args: Vec::new(),
     };
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index 8df236c41cf..05676dad334 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -212,13 +212,14 @@
 //! no means all of the necessary details. Take a look at the rest of
 //! metadata::locator or metadata::creader for all the juicy details!
 
-use crate::cstore::{MetadataRef, MetadataBlob};
+use crate::cstore::{MetadataBlob, CStore};
 use crate::creader::Library;
 use crate::schema::{METADATA_HEADER, rustc_version};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::svh::Svh;
-use rustc::middle::cstore::MetadataLoader;
+use rustc_data_structures::sync::MetadataRef;
+use rustc::middle::cstore::{CrateSource, MetadataLoader};
 use rustc::session::{config, Session};
 use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch};
 use rustc::session::search_paths::PathKind;
@@ -245,13 +246,13 @@ use rustc_data_structures::owning_ref::OwningRef;
 use log::{debug, info, warn};
 
 #[derive(Clone)]
-pub struct CrateMismatch {
+crate struct CrateMismatch {
     path: PathBuf,
     got: String,
 }
 
 #[derive(Clone)]
-pub struct Context<'a> {
+crate struct Context<'a> {
     pub sess: &'a Session,
     pub span: Span,
     pub crate_name: Symbol,
@@ -272,11 +273,9 @@ pub struct Context<'a> {
     pub metadata_loader: &'a dyn MetadataLoader,
 }
 
-pub struct CratePaths {
-    pub ident: String,
-    pub dylib: Option<PathBuf>,
-    pub rlib: Option<PathBuf>,
-    pub rmeta: Option<PathBuf>,
+crate struct CratePaths {
+    pub name: Symbol,
+    pub source: CrateSource,
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -296,14 +295,8 @@ impl fmt::Display for CrateFlavor {
     }
 }
 
-impl CratePaths {
-    fn paths(&self) -> Vec<PathBuf> {
-        self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).cloned().collect()
-    }
-}
-
 impl<'a> Context<'a> {
-    pub fn reset(&mut self) {
+    crate fn reset(&mut self) {
         self.rejected_via_hash.clear();
         self.rejected_via_triple.clear();
         self.rejected_via_kind.clear();
@@ -311,7 +304,7 @@ impl<'a> Context<'a> {
         self.rejected_via_filename.clear();
     }
 
-    pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
+    crate fn maybe_load_library_crate(&mut self) -> Option<Library> {
         let mut seen_paths = FxHashSet::default();
         match self.extra_filename {
             Some(s) => self.find_library_crate(s, &mut seen_paths)
@@ -320,10 +313,10 @@ impl<'a> Context<'a> {
         }
     }
 
-    pub fn report_errs(self) -> ! {
+    crate fn report_errs(self) -> ! {
         let add = match self.root {
             None => String::new(),
-            Some(r) => format!(" which `{}` depends on", r.ident),
+            Some(r) => format!(" which `{}` depends on", r.name),
         };
         let mut msg = "the following crate versions were found:".to_string();
         let mut err = if !self.rejected_via_hash.is_empty() {
@@ -341,8 +334,8 @@ impl<'a> Context<'a> {
             match self.root {
                 None => {}
                 Some(r) => {
-                    for path in r.paths().iter() {
-                        msg.push_str(&format!("\ncrate `{}`: {}", r.ident, path.display()));
+                    for path in r.source.paths() {
+                        msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display()));
                     }
                 }
             }
@@ -534,18 +527,8 @@ impl<'a> Context<'a> {
         // search is being performed for.
         let mut libraries = FxHashMap::default();
         for (_hash, (rlibs, rmetas, dylibs)) in candidates {
-            let mut slot = None;
-            let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
-            let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
-            let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
-            if let Some((h, m)) = slot {
-                libraries.insert(h,
-                                 Library {
-                                     dylib,
-                                     rlib,
-                                     rmeta,
-                                     metadata: m,
-                                 });
+            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs) {
+                libraries.insert(svh, lib);
             }
         }
 
@@ -563,7 +546,7 @@ impl<'a> Context<'a> {
                                                self.crate_name);
                 let candidates = libraries.iter().filter_map(|(_, lib)| {
                     let crate_name = &lib.metadata.get_root().name.as_str();
-                    match &(&lib.dylib, &lib.rlib) {
+                    match &(&lib.source.dylib, &lib.source.rlib) {
                         &(&Some((ref pd, _)), &Some((ref pr, _))) => {
                             Some(format!("\ncrate `{}`: {}\n{:>padding$}",
                                          crate_name,
@@ -584,6 +567,21 @@ impl<'a> Context<'a> {
         }
     }
 
+    fn extract_lib(
+        &mut self,
+        rlibs: FxHashMap<PathBuf, PathKind>,
+        rmetas: FxHashMap<PathBuf, PathKind>,
+        dylibs: FxHashMap<PathBuf, PathKind>,
+    ) -> Option<(Svh, Library)> {
+        let mut slot = None;
+        let source = CrateSource {
+            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
+            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
+            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
+        };
+        slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
+    }
+
     // Attempts to extract *one* library from the set `m`. If the set has no
     // elements, `None` is returned. If the set has more than one element, then
     // the errors and notes are emitted about the set of libraries.
@@ -828,23 +826,8 @@ impl<'a> Context<'a> {
             }
         };
 
-        // Extract the rlib/dylib pair.
-        let mut slot = None;
-        let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
-        let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
-        let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
-
-        if rlib.is_none() && rmeta.is_none() && dylib.is_none() {
-            return None;
-        }
-        slot.map(|(_, metadata)|
-            Library {
-                dylib,
-                rlib,
-                rmeta,
-                metadata,
-            }
-        )
+        // Extract the dylib/rlib/rmeta triple.
+        self.extract_lib(rlibs, rmetas, dylibs).map(|(_, lib)| lib)
     }
 }
 
@@ -931,7 +914,7 @@ fn get_metadata_section_imp(target: &Target,
 /// A diagnostic function for dumping crate metadata to an output stream.
 pub fn list_file_metadata(target: &Target,
                           path: &Path,
-                          loader: &dyn MetadataLoader,
+                          cstore: &CStore,
                           out: &mut dyn io::Write)
                           -> io::Result<()> {
     let filename = path.file_name().unwrap().to_str().unwrap();
@@ -942,7 +925,7 @@ pub fn list_file_metadata(target: &Target,
     } else {
         CrateFlavor::Dylib
     };
-    match get_metadata_section(target, flavor, path, loader) {
+    match get_metadata_section(target, flavor, path, &*cstore.metadata_loader) {
         Ok(metadata) => metadata.list_crate_metadata(out),
         Err(msg) => write!(out, "{}\n", msg),
     }
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index 24ed8fcd8dd..a58db6a903b 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -11,7 +11,7 @@ use syntax::feature_gate::{self, GateIssue};
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::{span_err, struct_span_err};
 
-pub fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
+crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
     let mut collector = Collector {
         tcx,
         libs: Vec::new(),
@@ -21,7 +21,7 @@ pub fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLibrary> {
     return collector.libs;
 }
 
-pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
+crate fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
     match lib.cfg {
         Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
         None => true,
@@ -198,12 +198,10 @@ impl Collector<'tcx> {
                     self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
                                                 attributes referencing this library.", name));
-                } else if renames.contains(name) {
+                } else if !renames.insert(name) {
                     self.tcx.sess.err(&format!("multiple renamings were \
                                                 specified for library `{}` .",
                                                name));
-                } else {
-                    renames.insert(name);
                 }
             }
         }
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 4fe9c466cb6..96f35783278 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -1,4 +1,4 @@
-use crate::index;
+use crate::table::PerDefTable;
 
 use rustc::hir;
 use rustc::hir::def::{self, CtorKind};
@@ -14,14 +14,16 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
 use rustc_index::vec::IndexVec;
 use rustc_data_structures::svh::Svh;
 
+use rustc_serialize::Encodable;
 use syntax::{ast, attr};
 use syntax::edition::Edition;
 use syntax::symbol::Symbol;
 use syntax_pos::{self, Span};
 
 use std::marker::PhantomData;
+use std::num::NonZeroUsize;
 
-pub fn rustc_version() -> String {
+crate fn rustc_version() -> String {
     format!("rustc {}",
             option_env!("CFG_VERSION").unwrap_or("unknown version"))
 }
@@ -29,7 +31,7 @@ pub fn rustc_version() -> String {
 /// Metadata encoding version.
 /// N.B., increment this if you change the format of metadata such that
 /// the rustc version can't be found to compare with `rustc_version()`.
-pub const METADATA_VERSION: u8 = 4;
+const METADATA_VERSION: u8 = 4;
 
 /// Metadata header which includes `METADATA_VERSION`.
 /// To get older versions of rustc to ignore this metadata,
@@ -39,12 +41,12 @@ pub const METADATA_VERSION: u8 = 4;
 /// This header is followed by the position of the `CrateRoot`,
 /// which is encoded as a 32-bit big-endian unsigned integer,
 /// and further followed by the rustc version string.
-pub const METADATA_HEADER: &[u8; 12] =
+crate const METADATA_HEADER: &[u8; 12] =
     &[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
 /// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
 /// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
-pub trait LazyMeta {
+crate trait LazyMeta {
     type Meta: Copy + 'static;
 
     /// Returns the minimum encoded size.
@@ -52,7 +54,7 @@ pub trait LazyMeta {
     fn min_size(meta: Self::Meta) -> usize;
 }
 
-impl<T> LazyMeta for T {
+impl<T: Encodable> LazyMeta for T {
     type Meta = ();
 
     fn min_size(_: ()) -> usize {
@@ -61,7 +63,7 @@ impl<T> LazyMeta for T {
     }
 }
 
-impl<T> LazyMeta for [T] {
+impl<T: Encodable> LazyMeta for [T] {
     type Meta = usize;
 
     fn min_size(len: usize) -> usize {
@@ -98,17 +100,17 @@ impl<T> LazyMeta for [T] {
 #[must_use]
 // FIXME(#59875) the `Meta` parameter only exists to dodge
 // invariance wrt `T` (coming from the `meta: T::Meta` field).
-pub struct Lazy<T, Meta = <T as LazyMeta>::Meta>
+crate struct Lazy<T, Meta = <T as LazyMeta>::Meta>
     where T: ?Sized + LazyMeta<Meta = Meta>,
           Meta: 'static + Copy,
 {
-    pub position: usize,
+    pub position: NonZeroUsize,
     pub meta: Meta,
     _marker: PhantomData<T>,
 }
 
 impl<T: ?Sized + LazyMeta> Lazy<T> {
-    pub fn from_position_and_meta(position: usize, meta: T::Meta) -> Lazy<T> {
+     crate fn from_position_and_meta(position: NonZeroUsize, meta: T::Meta) -> Lazy<T> {
         Lazy {
             position,
             meta,
@@ -117,15 +119,15 @@ impl<T: ?Sized + LazyMeta> Lazy<T> {
     }
 }
 
-impl<T> Lazy<T> {
-    pub fn from_position(position: usize) -> Lazy<T> {
+impl<T: Encodable> Lazy<T> {
+    crate fn from_position(position: NonZeroUsize) -> Lazy<T> {
         Lazy::from_position_and_meta(position, ())
     }
 }
 
-impl<T> Lazy<[T]> {
-    pub fn empty() -> Lazy<[T]> {
-        Lazy::from_position_and_meta(0, 0)
+impl<T: Encodable> Lazy<[T]> {
+    crate fn empty() -> Lazy<[T]> {
+        Lazy::from_position_and_meta(NonZeroUsize::new(1).unwrap(), 0)
     }
 }
 
@@ -141,22 +143,32 @@ impl<T: ?Sized + LazyMeta> rustc_serialize::UseSpecializedDecodable for Lazy<T>
 
 /// Encoding / decoding state for `Lazy`.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum LazyState {
+crate enum LazyState {
     /// Outside of a metadata node.
     NoNode,
 
     /// Inside a metadata node, and before any `Lazy`.
     /// The position is that of the node itself.
-    NodeStart(usize),
+    NodeStart(NonZeroUsize),
 
     /// Inside a metadata node, with a previous `Lazy`.
     /// The position is a conservative estimate of where that
     /// previous `Lazy` would end (see their comments).
-    Previous(usize),
+    Previous(NonZeroUsize),
+}
+
+// FIXME(#59875) `Lazy!(T)` replaces `Lazy<T>`, passing the `Meta` parameter
+// manually, instead of relying on the default, to get the correct variance.
+// Only needed when `T` itself contains a parameter (e.g. `'tcx`).
+macro_rules! Lazy {
+    (Table<$T:ty>) => {Lazy<Table<$T>, usize>};
+    (PerDefTable<$T:ty>) => {Lazy<PerDefTable<$T>, usize>};
+    ([$T:ty]) => {Lazy<[$T], usize>};
+    ($T:ty) => {Lazy<$T, ()>};
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct CrateRoot<'tcx> {
+crate struct CrateRoot<'tcx> {
     pub name: Symbol,
     pub triple: TargetTriple,
     pub extra_filename: String,
@@ -182,10 +194,10 @@ pub struct CrateRoot<'tcx> {
     pub source_map: Lazy<[syntax_pos::SourceFile]>,
     pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
     pub impls: Lazy<[TraitImpls]>,
-    pub exported_symbols: Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]>,
+    pub exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]),
     pub interpret_alloc_index: Lazy<[u32]>,
 
-    pub entries_index: Lazy<[index::Index<'tcx>]>,
+    pub per_def: LazyPerDefTables<'tcx>,
 
     /// The DefIndex's of any proc macros delcared by
     /// this crate
@@ -202,7 +214,7 @@ pub struct CrateRoot<'tcx> {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct CrateDep {
+crate struct CrateDep {
     pub name: ast::Name,
     pub hash: Svh,
     pub kind: DepKind,
@@ -210,34 +222,34 @@ pub struct CrateDep {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct TraitImpls {
+crate struct TraitImpls {
     pub trait_id: (u32, DefIndex),
     pub impls: Lazy<[DefIndex]>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct Entry<'tcx> {
-    pub kind: EntryKind<'tcx>,
-    pub visibility: Lazy<ty::Visibility>,
-    pub span: Lazy<Span>,
-    pub attributes: Lazy<[ast::Attribute]>,
-    pub children: Lazy<[DefIndex]>,
-    pub stability: Option<Lazy<attr::Stability>>,
-    pub deprecation: Option<Lazy<attr::Deprecation>>,
-
-    pub ty: Option<Lazy<Ty<'tcx>>>,
-    pub inherent_impls: Lazy<[DefIndex]>,
-    pub variances: Lazy<[ty::Variance]>,
-    pub generics: Option<Lazy<ty::Generics>>,
-    pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
-    pub predicates_defined_on: Option<Lazy<ty::GenericPredicates<'tcx>>>,
-
-    pub mir: Option<Lazy<mir::Body<'tcx>>>,
-    pub promoted_mir: Option<Lazy<IndexVec<mir::Promoted, mir::Body<'tcx>>>>,
+crate struct LazyPerDefTables<'tcx> {
+    pub kind: Lazy!(PerDefTable<Lazy!(EntryKind<'tcx>)>),
+    pub visibility: Lazy!(PerDefTable<Lazy<ty::Visibility>>),
+    pub span: Lazy!(PerDefTable<Lazy<Span>>),
+    pub attributes: Lazy!(PerDefTable<Lazy<[ast::Attribute]>>),
+    pub children: Lazy!(PerDefTable<Lazy<[DefIndex]>>),
+    pub stability: Lazy!(PerDefTable<Lazy<attr::Stability>>),
+    pub deprecation: Lazy!(PerDefTable<Lazy<attr::Deprecation>>),
+
+    pub ty: Lazy!(PerDefTable<Lazy!(Ty<'tcx>)>),
+    pub inherent_impls: Lazy!(PerDefTable<Lazy<[DefIndex]>>),
+    pub variances: Lazy!(PerDefTable<Lazy<[ty::Variance]>>),
+    pub generics: Lazy!(PerDefTable<Lazy<ty::Generics>>),
+    pub predicates: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
+    pub predicates_defined_on: Lazy!(PerDefTable<Lazy!(ty::GenericPredicates<'tcx>)>),
+
+    pub mir: Lazy!(PerDefTable<Lazy!(mir::Body<'tcx>)>),
+    pub promoted_mir: Lazy!(PerDefTable<Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>),
 }
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub enum EntryKind<'tcx> {
+crate enum EntryKind<'tcx> {
     Const(ConstQualif, Lazy<RenderedConst>),
     ImmStatic,
     MutStatic,
@@ -252,88 +264,88 @@ pub enum EntryKind<'tcx> {
     OpaqueTy,
     Enum(ReprOptions),
     Field,
-    Variant(Lazy<VariantData<'tcx>>),
-    Struct(Lazy<VariantData<'tcx>>, ReprOptions),
-    Union(Lazy<VariantData<'tcx>>, ReprOptions),
-    Fn(Lazy<FnData<'tcx>>),
-    ForeignFn(Lazy<FnData<'tcx>>),
+    Variant(Lazy!(VariantData<'tcx>)),
+    Struct(Lazy!(VariantData<'tcx>), ReprOptions),
+    Union(Lazy!(VariantData<'tcx>), ReprOptions),
+    Fn(Lazy!(FnData<'tcx>)),
+    ForeignFn(Lazy!(FnData<'tcx>)),
     Mod(Lazy<ModData>),
     MacroDef(Lazy<MacroDef>),
-    Closure(Lazy<ClosureData<'tcx>>),
-    Generator(Lazy<GeneratorData<'tcx>>),
-    Trait(Lazy<TraitData<'tcx>>),
-    Impl(Lazy<ImplData<'tcx>>),
-    Method(Lazy<MethodData<'tcx>>),
+    Closure(Lazy!(ClosureData<'tcx>)),
+    Generator(Lazy!(GeneratorData<'tcx>)),
+    Trait(Lazy!(TraitData<'tcx>)),
+    Impl(Lazy!(ImplData<'tcx>)),
+    Method(Lazy!(MethodData<'tcx>)),
     AssocType(AssocContainer),
     AssocOpaqueTy(AssocContainer),
     AssocConst(AssocContainer, ConstQualif, Lazy<RenderedConst>),
-    TraitAlias(Lazy<TraitAliasData<'tcx>>),
+    TraitAlias(Lazy!(TraitAliasData<'tcx>)),
 }
 
 /// Additional data for EntryKind::Const and EntryKind::AssocConst
 #[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
-pub struct ConstQualif {
+crate struct ConstQualif {
     pub mir: u8,
 }
 
 /// Contains a constant which has been rendered to a String.
 /// Used by rustdoc.
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct RenderedConst(pub String);
+crate struct RenderedConst(pub String);
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct ModData {
+crate struct ModData {
     pub reexports: Lazy<[def::Export<hir::HirId>]>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct MacroDef {
+crate struct MacroDef {
     pub body: String,
     pub legacy: bool,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct FnData<'tcx> {
+crate struct FnData<'tcx> {
     pub asyncness: hir::IsAsync,
     pub constness: hir::Constness,
     pub param_names: Lazy<[ast::Name]>,
-    pub sig: Lazy<ty::PolyFnSig<'tcx>>,
+    pub sig: Lazy!(ty::PolyFnSig<'tcx>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData<'tcx> {
+crate struct VariantData<'tcx> {
     pub ctor_kind: CtorKind,
     pub discr: ty::VariantDiscr,
     /// If this is unit or tuple-variant/struct, then this is the index of the ctor id.
     pub ctor: Option<DefIndex>,
     /// If this is a tuple struct or variant
     /// ctor, this is its "function" signature.
-    pub ctor_sig: Option<Lazy<ty::PolyFnSig<'tcx>>>,
+    pub ctor_sig: Option<Lazy!(ty::PolyFnSig<'tcx>)>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct TraitData<'tcx> {
+crate struct TraitData<'tcx> {
     pub unsafety: hir::Unsafety,
     pub paren_sugar: bool,
     pub has_auto_impl: bool,
     pub is_marker: bool,
-    pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
+    pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct TraitAliasData<'tcx> {
-    pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
+crate struct TraitAliasData<'tcx> {
+    pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct ImplData<'tcx> {
+crate struct ImplData<'tcx> {
     pub polarity: ty::ImplPolarity,
     pub defaultness: hir::Defaultness,
     pub parent_impl: Option<DefId>,
 
     /// This is `Some` only for impls of `CoerceUnsized`.
     pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>,
-    pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>,
+    pub trait_ref: Option<Lazy!(ty::TraitRef<'tcx>)>,
 }
 
 
@@ -341,7 +353,7 @@ pub struct ImplData<'tcx> {
 /// is a trait or an impl and whether, in a trait, it has
 /// a default, or an in impl, whether it's marked "default".
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub enum AssocContainer {
+crate enum AssocContainer {
     TraitRequired,
     TraitWithDefault,
     ImplDefault,
@@ -349,7 +361,7 @@ pub enum AssocContainer {
 }
 
 impl AssocContainer {
-    pub fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
+    crate fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
         match *self {
             AssocContainer::TraitRequired |
             AssocContainer::TraitWithDefault => ty::TraitContainer(def_id),
@@ -359,7 +371,7 @@ impl AssocContainer {
         }
     }
 
-    pub fn defaultness(&self) -> hir::Defaultness {
+    crate fn defaultness(&self) -> hir::Defaultness {
         match *self {
             AssocContainer::TraitRequired => hir::Defaultness::Default {
                 has_value: false,
@@ -376,22 +388,22 @@ impl AssocContainer {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct MethodData<'tcx> {
+crate struct MethodData<'tcx> {
     pub fn_data: FnData<'tcx>,
     pub container: AssocContainer,
     pub has_self: bool,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct ClosureData<'tcx> {
-    pub sig: Lazy<ty::PolyFnSig<'tcx>>,
+crate struct ClosureData<'tcx> {
+    pub sig: Lazy!(ty::PolyFnSig<'tcx>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-pub struct GeneratorData<'tcx> {
+crate struct GeneratorData<'tcx> {
     pub layout: mir::GeneratorLayout<'tcx>,
 }
 
 // Tags used for encoding Spans:
-pub const TAG_VALID_SPAN: u8 = 0;
-pub const TAG_INVALID_SPAN: u8 = 1;
+crate const TAG_VALID_SPAN: u8 = 0;
+crate const TAG_INVALID_SPAN: u8 = 1;
diff --git a/src/librustc_metadata/table.rs b/src/librustc_metadata/table.rs
new file mode 100644
index 00000000000..e164c28c953
--- /dev/null
+++ b/src/librustc_metadata/table.rs
@@ -0,0 +1,239 @@
+use crate::decoder::Metadata;
+use crate::schema::*;
+
+use rustc::hir::def_id::{DefId, DefIndex};
+use rustc_serialize::{Encodable, opaque::Encoder};
+use std::convert::TryInto;
+use std::marker::PhantomData;
+use std::num::NonZeroUsize;
+use log::debug;
+
+/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
+/// Used mainly for Lazy positions and lengths.
+/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
+/// but this has no impact on safety.
+crate trait FixedSizeEncoding: Default {
+    const BYTE_LEN: usize;
+
+    // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
+    // once that starts being allowed by the compiler (i.e. lazy normalization).
+    fn from_bytes(b: &[u8]) -> Self;
+    fn write_to_bytes(self, b: &mut [u8]);
+
+    // FIXME(eddyb) make these generic functions, or at least defaults here.
+    // (same problem as above, needs `[u8; Self::BYTE_LEN]`)
+    // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
+
+    /// Read a `Self` value (encoded as `Self::BYTE_LEN` bytes),
+    /// from `&b[i * Self::BYTE_LEN..]`, returning `None` if `i`
+    /// is not in bounds, or `Some(Self::from_bytes(...))` otherwise.
+    fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self>;
+    /// Write a `Self` value (encoded as `Self::BYTE_LEN` bytes),
+    /// at `&mut b[i * Self::BYTE_LEN..]`, using `Self::write_to_bytes`.
+    fn write_to_bytes_at(self, b: &mut [u8], i: usize);
+}
+
+// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
+macro_rules! fixed_size_encoding_byte_len_and_defaults {
+    ($byte_len:expr) => {
+        const BYTE_LEN: usize = $byte_len;
+        fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self> {
+            const BYTE_LEN: usize = $byte_len;
+            // HACK(eddyb) ideally this would be done with fully safe code,
+            // but slicing `[u8]` with `i * N..` is optimized worse, due to the
+            // possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
+            let b = unsafe {
+                std::slice::from_raw_parts(
+                    b.as_ptr() as *const [u8; BYTE_LEN],
+                    b.len() / BYTE_LEN,
+                )
+            };
+            b.get(i).map(|b| FixedSizeEncoding::from_bytes(b))
+        }
+        fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
+            const BYTE_LEN: usize = $byte_len;
+            // HACK(eddyb) ideally this would be done with fully safe code,
+            // see similar comment in `read_from_bytes_at` for why it can't yet.
+            let b = unsafe {
+                std::slice::from_raw_parts_mut(
+                    b.as_mut_ptr() as *mut [u8; BYTE_LEN],
+                    b.len() / BYTE_LEN,
+                )
+            };
+            self.write_to_bytes(&mut b[i]);
+        }
+    }
+}
+
+impl FixedSizeEncoding for u32 {
+    fixed_size_encoding_byte_len_and_defaults!(4);
+
+    fn from_bytes(b: &[u8]) -> Self {
+        let mut bytes = [0; Self::BYTE_LEN];
+        bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
+        Self::from_le_bytes(bytes)
+    }
+
+    fn write_to_bytes(self, b: &mut [u8]) {
+        b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
+    }
+}
+
+// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
+// generic `Lazy<T>` impl, but in the general case we might not need / want to
+// fit every `usize` in `u32`.
+impl<T: Encodable> FixedSizeEncoding for Option<Lazy<T>> {
+    fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN);
+
+    fn from_bytes(b: &[u8]) -> Self {
+        Some(Lazy::from_position(NonZeroUsize::new(u32::from_bytes(b) as usize)?))
+    }
+
+    fn write_to_bytes(self, b: &mut [u8]) {
+        let position = self.map_or(0, |lazy| lazy.position.get());
+        let position: u32 = position.try_into().unwrap();
+
+        position.write_to_bytes(b)
+    }
+}
+
+impl<T: Encodable> FixedSizeEncoding for Option<Lazy<[T]>> {
+    fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN * 2);
+
+    fn from_bytes(b: &[u8]) -> Self {
+        Some(Lazy::from_position_and_meta(
+            <Option<Lazy<T>>>::from_bytes(b)?.position,
+            u32::from_bytes(&b[u32::BYTE_LEN..]) as usize,
+        ))
+    }
+
+    fn write_to_bytes(self, b: &mut [u8]) {
+        self.map(|lazy| Lazy::<T>::from_position(lazy.position))
+            .write_to_bytes(b);
+
+        let len = self.map_or(0, |lazy| lazy.meta);
+        let len: u32 = len.try_into().unwrap();
+
+        len.write_to_bytes(&mut b[u32::BYTE_LEN..]);
+    }
+}
+
+/// Random-access table (i.e. offeringconstant-time `get`/`set`), similar to
+/// `Vec<Option<T>>`, but without requiring encoding or decoding all the values
+/// eagerly and in-order.
+/// A total of `(max_idx + 1) * <Option<T> as FixedSizeEncoding>::BYTE_LEN` bytes
+/// are used for a table, where `max_idx` is the largest index passed to `set`.
+// FIXME(eddyb) replace `Vec` with `[_]` here, such that `Box<Table<T>>` would be used
+// when building it, and `Lazy<Table<T>>` or `&Table<T>` when reading it.
+// (not sure if that is possible given that the `Vec` is being resized now)
+crate struct Table<T> where Option<T>: FixedSizeEncoding {
+    // FIXME(eddyb) store `[u8; <Option<T>>::BYTE_LEN]` instead of `u8` in `Vec`,
+    // once that starts being allowed by the compiler (i.e. lazy normalization).
+    bytes: Vec<u8>,
+    _marker: PhantomData<T>,
+}
+
+impl<T> Default for Table<T> where Option<T>: FixedSizeEncoding {
+    fn default() -> Self {
+        Table {
+            bytes: vec![],
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl<T> Table<T> where Option<T>: FixedSizeEncoding {
+    crate fn set(&mut self, i: usize, value: T) {
+        // FIXME(eddyb) investigate more compact encodings for sparse tables.
+        // On the PR @michaelwoerister mentioned:
+        // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
+        // > trick (i.e. divide things into buckets of 32 or 64 items and then
+        // > store bit-masks of which item in each bucket is actually serialized).
+        let needed = (i + 1) * <Option<T>>::BYTE_LEN;
+        if self.bytes.len() < needed {
+            self.bytes.resize(needed, 0);
+        }
+
+        Some(value).write_to_bytes_at(&mut self.bytes, i);
+    }
+
+    crate fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
+        let pos = buf.position();
+        buf.emit_raw_bytes(&self.bytes);
+        Lazy::from_position_and_meta(
+            NonZeroUsize::new(pos as usize).unwrap(),
+            self.bytes.len(),
+        )
+    }
+}
+
+impl<T> LazyMeta for Table<T> where Option<T>: FixedSizeEncoding {
+    type Meta = usize;
+
+    fn min_size(len: usize) -> usize {
+        len
+    }
+}
+
+impl<T> Lazy<Table<T>> where Option<T>: FixedSizeEncoding {
+    /// Given the metadata, extract out the value at a particular index (if any).
+    #[inline(never)]
+    crate fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(
+        &self,
+        metadata: M,
+        i: usize,
+    ) -> Option<T> {
+        debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
+
+        let start = self.position.get();
+        let bytes = &metadata.raw_bytes()[start..start + self.meta];
+        <Option<T>>::maybe_read_from_bytes_at(bytes, i)?
+    }
+}
+
+/// Like a `Table` but using `DefIndex` instead of `usize` as keys.
+// FIXME(eddyb) replace by making `Table` behave like `IndexVec`,
+// and by using `newtype_index!` to define `DefIndex`.
+crate struct PerDefTable<T>(Table<T>) where Option<T>: FixedSizeEncoding;
+
+impl<T> Default for PerDefTable<T> where Option<T>: FixedSizeEncoding {
+    fn default() -> Self {
+        PerDefTable(Table::default())
+    }
+}
+
+impl<T> PerDefTable<T> where Option<T>: FixedSizeEncoding {
+    crate fn set(&mut self, def_id: DefId, value: T) {
+        assert!(def_id.is_local());
+        self.0.set(def_id.index.index(), value);
+    }
+
+    crate fn encode(&self, buf: &mut Encoder) -> Lazy<Self> {
+        let lazy = self.0.encode(buf);
+        Lazy::from_position_and_meta(lazy.position, lazy.meta)
+    }
+}
+
+impl<T> LazyMeta for PerDefTable<T> where Option<T>: FixedSizeEncoding {
+    type Meta = <Table<T> as LazyMeta>::Meta;
+
+    fn min_size(meta: Self::Meta) -> usize {
+        Table::<T>::min_size(meta)
+    }
+}
+
+impl<T> Lazy<PerDefTable<T>> where Option<T>: FixedSizeEncoding {
+    fn as_table(&self) -> Lazy<Table<T>> {
+        Lazy::from_position_and_meta(self.position, self.meta)
+    }
+
+    /// Given the metadata, extract out the value at a particular DefIndex (if any).
+    #[inline(never)]
+    crate fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(
+        &self,
+        metadata: M,
+        def_index: DefIndex,
+    ) -> Option<T> {
+        self.as_table().get(metadata, def_index.index())
+    }
+}
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index 098258994f4..4c469a82ac3 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -78,7 +78,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 .last()
                 .unwrap();
 
-            if self.uninitialized_error_reported.contains(&root_place) {
+            if !self.uninitialized_error_reported.insert(root_place) {
                 debug!(
                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
                     root_place
@@ -86,8 +86,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 return;
             }
 
-            self.uninitialized_error_reported.insert(root_place);
-
             let item_msg = match self.describe_place_with_options(used_place,
                                                                   IncludingDowncast(true)) {
                 Some(name) => format!("`{}`", name),
diff --git a/src/librustc_mir/borrow_check/nll/constraints/mod.rs b/src/librustc_mir/borrow_check/nll/constraints/mod.rs
index 93113753c63..8a242b7ee25 100644
--- a/src/librustc_mir/borrow_check/nll/constraints/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/constraints/mod.rs
@@ -71,7 +71,7 @@ impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
 pub struct OutlivesConstraint {
     // NB. The ordering here is not significant for correctness, but
     // it is for convenience. Before we dump the constraints in the
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index 5354b45f92d..59b2796db7a 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -458,7 +458,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// True if an edge `source -> target` is a backedge -- in other words, if the target
     /// dominates the source.
     fn is_back_edge(&self, source: Location, target: Location) -> bool {
-        target.dominates(source, &self.body.dominators())
+        target.dominates(source, &self.dominators)
     }
 
     /// Determine how the borrow was later used.
diff --git a/src/librustc_mir/borrow_check/nll/member_constraints.rs b/src/librustc_mir/borrow_check/nll/member_constraints.rs
index fd195873a55..75213d30982 100644
--- a/src/librustc_mir/borrow_check/nll/member_constraints.rs
+++ b/src/librustc_mir/borrow_check/nll/member_constraints.rs
@@ -11,7 +11,7 @@ use syntax_pos::Span;
 /// indexed by the region `R0`.
 crate struct MemberConstraintSet<'tcx, R>
 where
-    R: Copy + Hash + Eq,
+    R: Copy + Eq,
 {
     /// Stores the first "member" constraint for a given `R0`. This is an
     /// index into the `constraints` vector below.
@@ -191,7 +191,7 @@ where
 
 impl<'tcx, R> Index<NllMemberConstraintIndex> for MemberConstraintSet<'tcx, R>
 where
-    R: Copy + Hash + Eq,
+    R: Copy + Eq,
 {
     type Output = NllMemberConstraint<'tcx>;
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
index 6acbff76bdc..7a86536573d 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs
@@ -129,7 +129,7 @@ rustc_index::newtype_index! {
 
 /// An individual element in a region value -- the value of a
 /// particular region variable consists of a set of these elements.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Debug)]
 crate enum RegionElement {
     /// A point in the control-flow graph.
     Location(Location),
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 88ad1fb1295..9ecd6f83775 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,6 +1,6 @@
 use rustc::ty::subst::SubstsRef;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::mir::{Location, Body, Promoted};
+use rustc::mir::{Body, Location, PlaceElem, Promoted};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 use rustc_index::vec::IndexVec;
@@ -62,6 +62,21 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        if let PlaceElem::Field(field, ty) = elem {
+            let new_ty = self.renumber_regions(ty);
+
+            if new_ty != *ty {
+                return Some(PlaceElem::Field(*field, new_ty));
+            }
+        }
+
+        None
+    }
+
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
         debug!("visit_substs(substs={:?}, location={:?})", substs, location);
 
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index 5f695185643..fd1f333010a 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -146,7 +146,7 @@ struct UniversalRegionIndices<'tcx> {
     indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Debug, PartialEq)]
 pub enum RegionClassification {
     /// A **global** region is one that can be named from
     /// anywhere. There is only one, `'static`.
diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs
index 990425c3252..bc09e327179 100644
--- a/src/librustc_mir/dataflow/impls/indirect_mutation.rs
+++ b/src/librustc_mir/dataflow/impls/indirect_mutation.rs
@@ -104,25 +104,16 @@ impl<'tcx> TransferFunction<'_, '_, 'tcx> {
         kind: mir::BorrowKind,
         borrowed_place: &mir::Place<'tcx>,
     ) -> bool {
-        let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty;
-
-        // Zero-sized types cannot be mutated, since there is nothing inside to mutate.
-        //
-        // FIXME: For now, we only exempt arrays of length zero. We need to carefully
-        // consider the effects before extending this to all ZSTs.
-        if let ty::Array(_, len) = borrowed_ty.kind {
-            if len.try_eval_usize(self.tcx, self.param_env) == Some(0) {
-                return false;
-            }
-        }
-
         match kind {
             mir::BorrowKind::Mut { .. } => true,
 
             | mir::BorrowKind::Shared
             | mir::BorrowKind::Shallow
             | mir::BorrowKind::Unique
-            => !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP),
+            => !borrowed_place
+                .ty(self.body, self.tcx)
+                .ty
+                .is_freeze(self.tcx, self.param_env, DUMMY_SP),
         }
     }
 }
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index 06999abdc8b..ad0f75d7725 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -1,4 +1,5 @@
 use syntax::ast::{self, MetaItem};
+use syntax::print::pprust;
 use syntax::symbol::{Symbol, sym};
 
 use rustc_index::bit_set::{BitSet, HybridBitSet};
@@ -159,9 +160,8 @@ where
                 if let Some(s) = item.value_str() {
                     return Some(s.to_string())
                 } else {
-                    sess.span_err(
-                        item.span,
-                        &format!("{} attribute requires a path", item.path));
+                    let path = pprust::path_to_string(&item.path);
+                    sess.span_err(item.span, &format!("{} attribute requires a path", path));
                     return None;
                 }
             }
diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs
index 77853ff1fe8..419c905cb51 100644
--- a/src/librustc_mir/error_codes.rs
+++ b/src/librustc_mir/error_codes.rs
@@ -64,7 +64,9 @@ E0004: r##"
 This error indicates that the compiler cannot guarantee a matching pattern for
 one or more possible inputs to a match expression. Guaranteed matches are
 required in order to assign values to match expressions, or alternatively,
-determine the flow of execution. Erroneous code example:
+determine the flow of execution.
+
+Erroneous code example:
 
 ```compile_fail,E0004
 enum Terminator {
@@ -109,7 +111,9 @@ match x {
 
 E0005: r##"
 Patterns used to bind names must be irrefutable, that is, they must guarantee
-that a name will be extracted in all cases. Erroneous code example:
+that a name will be extracted in all cases.
+
+Erroneous code example:
 
 ```compile_fail,E0005
 let x = Some(1);
@@ -145,6 +149,8 @@ like the following is invalid as it requires the entire `Option<String>` to be
 moved into a variable called `op_string` while simultaneously requiring the
 inner `String` to be moved into a variable called `s`.
 
+Erroneous code example:
+
 ```compile_fail,E0007
 let x = Some("s".to_string());
 
@@ -208,15 +214,130 @@ match x {
 ```
 "##,
 
+E0010: r##"
+The value of statics and constants must be known at compile time, and they live
+for the entire lifetime of a program. Creating a boxed value allocates memory on
+the heap at runtime, and therefore cannot be done at compile time.
+
+Erroneous code example:
+
+```compile_fail,E0010
+#![feature(box_syntax)]
+
+const CON : Box<i32> = box 0;
+```
+"##,
+
+E0013: r##"
+Static and const variables can refer to other const variables. But a const
+variable cannot refer to a static variable.
+
+Erroneous code example:
+
+```compile_fail,E0013
+static X: i32 = 42;
+const Y: i32 = X;
+```
+
+In this example, `Y` cannot refer to `X` here. To fix this, the value can be
+extracted as a const and then used:
+
+```
+const A: i32 = 42;
+static X: i32 = A;
+const Y: i32 = A;
+```
+"##,
+
+// FIXME(#57563) Change the language here when const fn stabilizes
+E0015: r##"
+The only functions that can be called in static or constant expressions are
+`const` functions, and struct/enum constructors. `const` functions are only
+available on a nightly compiler. Rust currently does not support more general
+compile-time function execution.
+
+```
+const FOO: Option<u8> = Some(1); // enum constructor
+struct Bar {x: u8}
+const BAR: Bar = Bar {x: 1}; // struct constructor
+```
+
+See [RFC 911] for more details on the design of `const fn`s.
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
+E0017: r##"
+References in statics and constants may only refer to immutable values.
+
+Erroneous code example:
+
+```compile_fail,E0017
+static X: i32 = 1;
+const C: i32 = 2;
+
+// these three are not allowed:
+const CR: &mut i32 = &mut C;
+static STATIC_REF: &'static mut i32 = &mut X;
+static CONST_REF: &'static mut i32 = &mut C;
+```
+
+Statics are shared everywhere, and if they refer to mutable data one might
+violate memory safety since holding multiple mutable references to shared data
+is not allowed.
+
+If you really want global mutable state, try using `static mut` or a global
+`UnsafeCell`.
+"##,
+
+E0019: r##"
+A function call isn't allowed in the const's initialization expression
+because the expression's value must be known at compile-time.
+
+Erroneous code example:
+
+```compile_fail,E0019
+#![feature(box_syntax)]
+
+fn main() {
+    struct MyOwned;
+
+    static STATIC11: Box<MyOwned> = box MyOwned; // error!
+}
+```
+
+Remember: you can't use a function call inside a const's initialization
+expression! However, you can totally use it anywhere else:
+
+```
+enum Test {
+    V1
+}
+
+impl Test {
+    fn func(&self) -> i32 {
+        12
+    }
+}
+
+fn main() {
+    const FOO: Test = Test::V1;
+
+    FOO.func(); // here is good
+    let x = FOO.func(); // or even here!
+}
+```
+"##,
+
 E0030: r##"
 When matching against a range, the compiler verifies that the range is
-non-empty.  Range patterns include both end-points, so this is equivalent to
+non-empty. Range patterns include both end-points, so this is equivalent to
 requiring the start of the range to be less than or equal to the end of the
 range.
 
-For example:
+Erroneous code example:
 
-```compile_fail
+```compile_fail,E0030
 match 5u32 {
     // This range is ok, albeit pointless.
     1 ..= 1 => {}
@@ -226,7 +347,61 @@ match 5u32 {
 ```
 "##,
 
+E0133: r##"
+Unsafe code was used outside of an unsafe function or block.
+
+Erroneous code example:
+
+```compile_fail,E0133
+unsafe fn f() { return; } // This is the unsafe code
+
+fn main() {
+    f(); // error: call to unsafe function requires unsafe function or block
+}
+```
+
+Using unsafe functionality is potentially dangerous and disallowed by safety
+checks. Examples:
+
+* Dereferencing raw pointers
+* Calling functions via FFI
+* Calling functions marked unsafe
+
+These safety checks can be relaxed for a section of the code by wrapping the
+unsafe instructions with an `unsafe` block. For instance:
+
+```
+unsafe fn f() { return; }
+
+fn main() {
+    unsafe { f(); } // ok!
+}
+```
+
+See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
+"##,
+
 E0158: r##"
+An associated const has been referenced in a pattern.
+
+Erroneous code example:
+
+```compile_fail,E0158
+enum EFoo { A, B, C, D }
+
+trait Foo {
+    const X: EFoo;
+}
+
+fn test<A: Foo>(arg: EFoo) {
+    match arg {
+        A::X => { // error!
+            println!("A::X");
+        }
+    }
+}
+```
+
 `const` and `static` mean different things. A `const` is a compile-time
 constant, an alias for a literal value. This property means you can match it
 directly within a pattern.
@@ -247,6 +422,39 @@ match Some(42) {
 ```
 "##,
 
+E0161: r##"
+A value was moved. However, its size was not known at compile time, and only
+values of a known size can be moved.
+
+Erroneous code example:
+
+```compile_fail,E0161
+#![feature(box_syntax)]
+
+fn main() {
+    let array: &[isize] = &[1, 2, 3];
+    let _x: Box<[isize]> = box *array;
+    // error: cannot move a value of type [isize]: the size of [isize] cannot
+    //        be statically determined
+}
+```
+
+In Rust, you can only move a value when its size is known at compile time.
+
+To work around this restriction, consider "hiding" the value behind a reference:
+either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
+it around as usual. Example:
+
+```
+#![feature(box_syntax)]
+
+fn main() {
+    let array: &[isize] = &[1, 2, 3];
+    let _x: Box<&[isize]> = box array; // ok!
+}
+```
+"##,
+
 E0162: r##"
 #### Note: this error code is no longer emitted by the compiler.
 
@@ -468,158 +676,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases.
 See also https://github.com/rust-lang/rust/issues/14587
 "##,
 
-E0010: r##"
-The value of statics and constants must be known at compile time, and they live
-for the entire lifetime of a program. Creating a boxed value allocates memory on
-the heap at runtime, and therefore cannot be done at compile time. Erroneous
-code example:
-
-```compile_fail,E0010
-#![feature(box_syntax)]
-
-const CON : Box<i32> = box 0;
-```
-"##,
-
-E0013: r##"
-Static and const variables can refer to other const variables. But a const
-variable cannot refer to a static variable. For example, `Y` cannot refer to
-`X` here:
-
-```compile_fail,E0013
-static X: i32 = 42;
-const Y: i32 = X;
-```
-
-To fix this, the value can be extracted as a const and then used:
-
-```
-const A: i32 = 42;
-static X: i32 = A;
-const Y: i32 = A;
-```
-"##,
-
-// FIXME(#57563) Change the language here when const fn stabilizes
-E0015: r##"
-The only functions that can be called in static or constant expressions are
-`const` functions, and struct/enum constructors. `const` functions are only
-available on a nightly compiler. Rust currently does not support more general
-compile-time function execution.
-
-```
-const FOO: Option<u8> = Some(1); // enum constructor
-struct Bar {x: u8}
-const BAR: Bar = Bar {x: 1}; // struct constructor
-```
-
-See [RFC 911] for more details on the design of `const fn`s.
-
-[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
-"##,
-
-E0017: r##"
-References in statics and constants may only refer to immutable values.
-Erroneous code example:
-
-```compile_fail,E0017
-static X: i32 = 1;
-const C: i32 = 2;
-
-// these three are not allowed:
-const CR: &mut i32 = &mut C;
-static STATIC_REF: &'static mut i32 = &mut X;
-static CONST_REF: &'static mut i32 = &mut C;
-```
-
-Statics are shared everywhere, and if they refer to mutable data one might
-violate memory safety since holding multiple mutable references to shared data
-is not allowed.
-
-If you really want global mutable state, try using `static mut` or a global
-`UnsafeCell`.
-"##,
-
-E0019: r##"
-A function call isn't allowed in the const's initialization expression
-because the expression's value must be known at compile-time. Erroneous code
-example:
-
-```compile_fail
-enum Test {
-    V1
-}
-
-impl Test {
-    fn test(&self) -> i32 {
-        12
-    }
-}
-
-fn main() {
-    const FOO: Test = Test::V1;
-
-    const A: i32 = FOO.test(); // You can't call Test::func() here!
-}
-```
-
-Remember: you can't use a function call inside a const's initialization
-expression! However, you can totally use it anywhere else:
-
-```
-enum Test {
-    V1
-}
-
-impl Test {
-    fn func(&self) -> i32 {
-        12
-    }
-}
-
-fn main() {
-    const FOO: Test = Test::V1;
-
-    FOO.func(); // here is good
-    let x = FOO.func(); // or even here!
-}
-```
-"##,
-
-E0133: r##"
-Unsafe code was used outside of an unsafe function or block.
-
-Erroneous code example:
-
-```compile_fail,E0133
-unsafe fn f() { return; } // This is the unsafe code
-
-fn main() {
-    f(); // error: call to unsafe function requires unsafe function or block
-}
-```
-
-Using unsafe functionality is potentially dangerous and disallowed by safety
-checks. Examples:
-
-* Dereferencing raw pointers
-* Calling functions via FFI
-* Calling functions marked unsafe
-
-These safety checks can be relaxed for a section of the code by wrapping the
-unsafe instructions with an `unsafe` block. For instance:
-
-```
-unsafe fn f() { return; }
-
-fn main() {
-    unsafe { f(); } // ok!
-}
-```
-
-See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.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
@@ -672,7 +728,9 @@ about safety.
 "##,
 
 E0381: r##"
-It is not allowed to use or capture an uninitialized variable. For example:
+It is not allowed to use or capture an uninitialized variable.
+
+Erroneous code example:
 
 ```compile_fail,E0381
 fn main() {
@@ -694,7 +752,9 @@ 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:
+have been moved elsewhere.
+
+Erroneous code example:
 
 ```compile_fail,E0382
 struct MyStruct { s: u32 }
@@ -842,7 +902,8 @@ x = Foo { a: 2 };
 
 E0384: r##"
 This error occurs when an attempt is made to reassign an immutable variable.
-For example:
+
+Erroneous code example:
 
 ```compile_fail,E0384
 fn main() {
@@ -862,13 +923,15 @@ fn main() {
 ```
 "##,
 
-/*E0386: r##"
+E0386: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
 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
@@ -892,13 +955,15 @@ let x: i64 = 1;
 let y: Box<Cell<_>> = Box::new(Cell::new(x));
 y.set(2);
 ```
-"##,*/
+"##,
 
 E0387: r##"
 #### Note: this error code is no longer emitted by the compiler.
 
 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:
+that a closure has captured immutably.
+
+Erroneous code example:
 
 ```compile_fail
 // Accepts a function or a closure that captures its environment immutably.
@@ -963,7 +1028,7 @@ 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:
+Erroneous code example:
 
 ```compile_fail
 struct FancyNum {
@@ -1022,43 +1087,11 @@ fn main() {
 ```
 "##,
 
-E0161: r##"
-A value was moved. However, its size was not known at compile time, and only
-values of a known size can be moved.
+E0492: r##"
+A borrow of a constant containing interior mutability was attempted.
 
 Erroneous code example:
 
-```compile_fail
-#![feature(box_syntax)]
-
-fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<[isize]> = box *array;
-    // error: cannot move a value of type [isize]: the size of [isize] cannot
-    //        be statically determined
-}
-```
-
-In Rust, you can only move a value when its size is known at compile time.
-
-To work around this restriction, consider "hiding" the value behind a reference:
-either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
-it around as usual. Example:
-
-```
-#![feature(box_syntax)]
-
-fn main() {
-    let array: &[isize] = &[1, 2, 3];
-    let _x: Box<&[isize]> = box array; // ok!
-}
-```
-"##,
-
-E0492: r##"
-A borrow of a constant containing interior mutability was attempted. Erroneous
-code example:
-
 ```compile_fail,E0492
 use std::sync::atomic::AtomicUsize;
 
@@ -1174,7 +1207,9 @@ static FOO: Foo = Foo { field1: DropType::A }; // We initialize all fields
 "##,
 
 E0499: r##"
-A variable was borrowed as mutable more than once. Erroneous code example:
+A variable was borrowed as mutable more than once.
+
+Erroneous code example:
 
 ```compile_fail,E0499
 let mut i = 0;
@@ -1205,7 +1240,9 @@ a;
 "##,
 
 E0500: r##"
-A borrowed variable was used by a closure. Example of erroneous code:
+A borrowed variable was used by a closure.
+
+Erroneous code example:
 
 ```compile_fail,E0500
 fn you_know_nothing(jon_snow: &mut i32) {
@@ -1256,7 +1293,7 @@ situation, the closure is borrowing the variable. Take a look at
 http://rustbyexample.com/fn/closures/capture.html for more information about
 capturing.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0501
 fn inside_closure(x: &mut i32) {
@@ -1329,7 +1366,7 @@ E0502: r##"
 This error indicates that you are trying to borrow a variable as mutable when it
 has already been borrowed as immutable.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0502
 fn bar(x: &mut i32) {}
@@ -1360,7 +1397,7 @@ https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html.
 E0503: r##"
 A value was used after it was mutably borrowed.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0503
 fn main() {
@@ -1418,7 +1455,7 @@ E0504: r##"
 This error occurs when an attempt is made to move a borrowed variable into a
 closure.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail
 struct FancyNum {
@@ -1609,7 +1646,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
 E0506: r##"
 This error occurs when an attempt is made to assign to a borrowed value.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0506
 struct FancyNum {
@@ -1827,7 +1864,7 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
 E0508: r##"
 A value was moved out of a non-copy fixed-size array.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0508
 struct NonCopy;
@@ -1872,7 +1909,7 @@ E0509: r##"
 This error occurs when an attempt is made to move out of a value whose type
 implements the `Drop` trait.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0509
 struct FancyNum {
@@ -1982,30 +2019,14 @@ Here executing `x = None` would modify the value being matched and require us
 to go "back in time" to the `None` arm.
 "##,
 
-E0579: r##"
-When matching against an exclusive range, the compiler verifies that the range
-is non-empty. Exclusive range patterns include the start point but not the end
-point, so this is equivalent to requiring the start of the range to be less
-than the end of the range.
-
-For example:
-
-```compile_fail
-match 5u32 {
-    // This range is ok, albeit pointless.
-    1 .. 2 => {}
-    // This range is empty, and the compiler can tell.
-    5 .. 5 => {}
-}
-```
-"##,
-
 E0515: r##"
 Cannot return value that references local variable
 
 Local variables, function parameters and temporaries are all dropped before the
 end of the function body. So a reference to them cannot be returned.
 
+Erroneous code example:
+
 ```compile_fail,E0515
 fn get_dangling_reference() -> &'static i32 {
     let x = 0;
@@ -2101,6 +2122,28 @@ fn dragoooon(x: &mut isize) {
 ```
 "##,
 
+E0579: r##"
+When matching against an exclusive range, the compiler verifies that the range
+is non-empty. Exclusive range patterns include the start point but not the end
+point, so this is equivalent to requiring the start of the range to be less
+than the end of the range.
+
+Erroneous code example:
+
+```compile_fail,E0579
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match 5u32 {
+        // This range is ok, albeit pointless.
+        1 .. 2 => {}
+        // This range is empty, and the compiler can tell.
+        5 .. 5 => {} // error!
+    }
+}
+```
+"##,
+
 E0595: r##"
 #### Note: this error code is no longer emitted by the compiler.
 
@@ -2124,7 +2167,7 @@ let mut c = || { x += 1 };
 E0596: r##"
 This error occurs because you tried to mutably borrow a non-mutable variable.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0596
 let x = 1;
@@ -2143,7 +2186,7 @@ let y = &mut x; // ok!
 E0597: r##"
 This error occurs because a value was dropped while it was still borrowed
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0597
 struct Foo<'a> {
@@ -2180,6 +2223,8 @@ E0626: r##"
 This error occurs because a borrow in a generator persists across a
 yield point.
 
+Erroneous code example:
+
 ```compile_fail,E0626
 # #![feature(generators, generator_trait, pin)]
 # use std::ops::Generator;
@@ -2271,7 +2316,7 @@ E0712: r##"
 This error occurs because a borrow of a thread-local variable was made inside a
 function which outlived the lifetime of the function.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0712
 #![feature(thread_local)]
@@ -2293,7 +2338,7 @@ E0713: r##"
 This error occurs when an attempt is made to borrow state past the end of the
 lifetime of a type that implements the `Drop` trait.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0713
 #![feature(nll)]
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 3ea58052877..dc6d4b27886 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -167,13 +167,14 @@ use super::{FieldPat, Pat, PatKind, PatRange};
 use super::{PatternFoldable, PatternFolder, compare_const_vals};
 
 use rustc::hir::def_id::DefId;
-use rustc::hir::RangeEnd;
+use rustc::hir::{RangeEnd, HirId};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
 use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
 
 use rustc::mir::Field;
 use rustc::mir::interpret::{ConstValue, Scalar, truncate, AllocId, Pointer};
 use rustc::util::common::ErrorReported;
+use rustc::lint;
 
 use syntax::attr::{SignedInt, UnsignedInt};
 use syntax_pos::{Span, DUMMY_SP};
@@ -188,8 +189,8 @@ use std::ops::RangeInclusive;
 use std::u128;
 use std::convert::TryInto;
 
-pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> &'a Pat<'tcx> {
-    cx.pattern_arena.alloc(LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat))
+pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
+    LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)
 }
 
 struct LiteralExpander<'tcx> {
@@ -418,7 +419,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug)]
 enum Constructor<'tcx> {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g., struct patterns and fixed-length arrays.
@@ -426,13 +427,30 @@ enum Constructor<'tcx> {
     /// Enum variants.
     Variant(DefId),
     /// Literal values.
-    ConstantValue(&'tcx ty::Const<'tcx>),
+    ConstantValue(&'tcx ty::Const<'tcx>, Span),
     /// Ranges of literal values (`2..=5` and `2..5`).
-    ConstantRange(u128, u128, Ty<'tcx>, RangeEnd),
+    ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span),
     /// Array patterns of length n.
     Slice(u64),
 }
 
+// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
+impl<'tcx> std::cmp::PartialEq for Constructor<'tcx> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Constructor::Single, Constructor::Single) => true,
+            (Constructor::Variant(a), Constructor::Variant(b)) => a == b,
+            (Constructor::ConstantValue(a, _), Constructor::ConstantValue(b, _)) => a == b,
+            (
+                Constructor::ConstantRange(a_start, a_end, a_ty, a_range_end, _),
+                Constructor::ConstantRange(b_start, b_end, b_ty, b_range_end, _),
+            ) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end,
+            (Constructor::Slice(a), Constructor::Slice(b)) => a == b,
+            _ => false,
+        }
+    }
+}
+
 impl<'tcx> Constructor<'tcx> {
     fn is_slice(&self) -> bool {
         match self {
@@ -447,15 +465,33 @@ impl<'tcx> Constructor<'tcx> {
         adt: &'tcx ty::AdtDef,
     ) -> VariantIdx {
         match self {
-            &Variant(id) => adt.variant_index_with_id(id),
-            &Single => {
+            Variant(id) => adt.variant_index_with_id(*id),
+            Single => {
                 assert!(!adt.is_enum());
                 VariantIdx::new(0)
             }
-            &ConstantValue(c) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c),
+            ConstantValue(c, _) => crate::const_eval::const_variant_index(cx.tcx, cx.param_env, c),
             _ => bug!("bad constructor {:?} for adt {:?}", self, adt)
         }
     }
+
+    fn display(&self, tcx: TyCtxt<'tcx>) -> String {
+        match self {
+            Constructor::ConstantValue(val, _) => format!("{}", val),
+            Constructor::ConstantRange(lo, hi, ty, range_end, _) => {
+                // Get the right sign on the output:
+                let ty = ty::ParamEnv::empty().and(*ty);
+                format!(
+                    "{}{}{}",
+                    ty::Const::from_bits(tcx, *lo, ty),
+                    range_end,
+                    ty::Const::from_bits(tcx, *hi, ty),
+                )
+            }
+            Constructor::Slice(val) => format!("[{}]", val),
+            _ => bug!("bad constructor being displayed: `{:?}", self),
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
@@ -484,6 +520,7 @@ pub enum WitnessPreference {
 struct PatCtxt<'tcx> {
     ty: Ty<'tcx>,
     max_slice_length: u64,
+    span: Span,
 }
 
 /// A witness of non-exhaustiveness for error reporting, represented
@@ -610,8 +647,8 @@ impl<'tcx> Witness<'tcx> {
 
                 _ => {
                     match *ctor {
-                        ConstantValue(value) => PatKind::Constant { value },
-                        ConstantRange(lo, hi, ty, end) => PatKind::Range(PatRange {
+                        ConstantValue(value, _) => PatKind::Constant { value },
+                        ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange {
                             lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
                             hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
                             end,
@@ -647,7 +684,7 @@ fn all_constructors<'a, 'tcx>(
     let ctors = match pcx.ty.kind {
         ty::Bool => {
             [true, false].iter().map(|&b| {
-                ConstantValue(ty::Const::from_bool(cx.tcx, b))
+                ConstantValue(ty::Const::from_bool(cx.tcx, b), pcx.span)
             }).collect()
         }
         ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
@@ -679,15 +716,19 @@ fn all_constructors<'a, 'tcx>(
         ty::Char => {
             vec![
                 // The valid Unicode Scalar Value ranges.
-                ConstantRange('\u{0000}' as u128,
-                              '\u{D7FF}' as u128,
-                              cx.tcx.types.char,
-                              RangeEnd::Included
+                ConstantRange(
+                    '\u{0000}' as u128,
+                    '\u{D7FF}' as u128,
+                    cx.tcx.types.char,
+                    RangeEnd::Included,
+                    pcx.span,
                 ),
-                ConstantRange('\u{E000}' as u128,
-                              '\u{10FFFF}' as u128,
-                              cx.tcx.types.char,
-                              RangeEnd::Included
+                ConstantRange(
+                    '\u{E000}' as u128,
+                    '\u{10FFFF}' as u128,
+                    cx.tcx.types.char,
+                    RangeEnd::Included,
+                    pcx.span,
                 ),
             ]
         }
@@ -695,12 +736,12 @@ fn all_constructors<'a, 'tcx>(
             let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
             let min = 1u128 << (bits - 1);
             let max = min - 1;
-            vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)]
+            vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included, pcx.span)]
         }
         ty::Uint(uty) => {
             let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
             let max = truncate(u128::max_value(), size);
-            vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included)]
+            vec![ConstantRange(0, max, pcx.ty, RangeEnd::Included, pcx.span)]
         }
         _ => {
             if cx.is_uninhabited(pcx.ty) {
@@ -827,10 +868,11 @@ where
 ///
 /// `IntRange` is never used to encode an empty range or a "range" that wraps
 /// around the (offset) space: i.e., `range.lo <= range.hi`.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 struct IntRange<'tcx> {
     pub range: RangeInclusive<u128>,
     pub ty: Ty<'tcx>,
+    pub span: Span,
 }
 
 impl<'tcx> IntRange<'tcx> {
@@ -860,6 +902,7 @@ impl<'tcx> IntRange<'tcx> {
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         value: &Const<'tcx>,
+        span: Span,
     ) -> Option<IntRange<'tcx>> {
         if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
             let ty = value.ty;
@@ -877,7 +920,7 @@ impl<'tcx> IntRange<'tcx> {
                 return None
             };
             let val = val ^ bias;
-            Some(IntRange { range: val..=val, ty })
+            Some(IntRange { range: val..=val, ty, span })
         } else {
             None
         }
@@ -890,6 +933,7 @@ impl<'tcx> IntRange<'tcx> {
         hi: u128,
         ty: Ty<'tcx>,
         end: &RangeEnd,
+        span: Span,
     ) -> Option<IntRange<'tcx>> {
         if Self::is_integral(ty) {
             // Perform a shift if the underlying types are signed,
@@ -901,7 +945,7 @@ impl<'tcx> IntRange<'tcx> {
                 None
             } else {
                 let offset = (*end == RangeEnd::Excluded) as u128;
-                Some(IntRange { range: lo..=(hi - offset), ty })
+                Some(IntRange { range: lo..=(hi - offset), ty, span })
             }
         } else {
             None
@@ -916,8 +960,8 @@ impl<'tcx> IntRange<'tcx> {
         // Floating-point ranges are permitted and we don't want
         // to consider them when constructing integer ranges.
         match ctor {
-            ConstantRange(lo, hi, ty, end) => Self::from_range(tcx, *lo, *hi, ty, end),
-            ConstantValue(val) => Self::from_const(tcx, param_env, val),
+            ConstantRange(lo, hi, ty, end, span) => Self::from_range(tcx, *lo, *hi, ty, end, *span),
+            ConstantValue(val, span) => Self::from_const(tcx, param_env, val, *span),
             _ => None,
         }
     }
@@ -930,7 +974,7 @@ impl<'tcx> IntRange<'tcx> {
         loop {
             match pat.kind {
                 box PatKind::Constant { value } => {
-                    return Self::from_const(tcx, param_env, value);
+                    return Self::from_const(tcx, param_env, value, pat.span);
                 }
                 box PatKind::Range(PatRange { lo, hi, end }) => {
                     return Self::from_range(
@@ -939,6 +983,7 @@ impl<'tcx> IntRange<'tcx> {
                         hi.eval_bits(tcx, param_env, hi.ty),
                         &lo.ty,
                         &end,
+                        pat.span,
                     );
                 }
                 box PatKind::AscribeUserType { ref subpattern, .. } => {
@@ -965,14 +1010,15 @@ impl<'tcx> IntRange<'tcx> {
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
         r: RangeInclusive<u128>,
+        span: Span,
     ) -> Constructor<'tcx> {
         let bias = IntRange::signed_bias(tcx, ty);
         let (lo, hi) = r.into_inner();
         if lo == hi {
             let ty = ty::ParamEnv::empty().and(ty);
-            ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty))
+            ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty), span)
         } else {
-            ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included)
+            ConstantRange(lo ^ bias, hi ^ bias, ty, RangeEnd::Included, span)
         }
     }
 
@@ -995,17 +1041,23 @@ impl<'tcx> IntRange<'tcx> {
             if lo > subrange_hi || subrange_lo > hi  {
                 // The pattern doesn't intersect with the subrange at all,
                 // so the subrange remains untouched.
-                remaining_ranges.push(Self::range_to_ctor(tcx, ty, subrange_lo..=subrange_hi));
+                remaining_ranges.push(
+                    Self::range_to_ctor(tcx, ty, subrange_lo..=subrange_hi, self.span),
+                );
             } else {
                 if lo > subrange_lo {
                     // The pattern intersects an upper section of the
                     // subrange, so a lower section will remain.
-                    remaining_ranges.push(Self::range_to_ctor(tcx, ty, subrange_lo..=(lo - 1)));
+                    remaining_ranges.push(
+                        Self::range_to_ctor(tcx, ty, subrange_lo..=(lo - 1), self.span),
+                    );
                 }
                 if hi < subrange_hi {
                     // The pattern intersects a lower section of the
                     // subrange, so an upper section will remain.
-                    remaining_ranges.push(Self::range_to_ctor(tcx, ty, (hi + 1)..=subrange_hi));
+                    remaining_ranges.push(
+                        Self::range_to_ctor(tcx, ty, (hi + 1)..=subrange_hi, self.span),
+                    );
                 }
             }
         }
@@ -1017,11 +1069,29 @@ impl<'tcx> IntRange<'tcx> {
         let (lo, hi) = (*self.range.start(), *self.range.end());
         let (other_lo, other_hi) = (*other.range.start(), *other.range.end());
         if lo <= other_hi && other_lo <= hi {
-            Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty })
+            let span = other.span;
+            Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span })
         } else {
             None
         }
     }
+
+    fn suspicious_intersection(&self, other: &Self) -> bool {
+        // `false` in the following cases:
+        // 1     ----      // 1  ----------   // 1 ----        // 1       ----
+        // 2  ----------   // 2     ----      // 2       ----  // 2 ----
+        //
+        // The following are currently `false`, but could be `true` in the future (#64007):
+        // 1 ---------       // 1     ---------
+        // 2     ----------  // 2 ----------
+        //
+        // `true` in the following cases:
+        // 1 -------          // 1       -------
+        // 2       --------   // 2 -------
+        let (lo, hi) = (*self.range.start(), *self.range.end());
+        let (other_lo, other_hi) = (*other.range.start(), *other.range.end());
+        (lo == other_hi || hi == other_lo)
+    }
 }
 
 // A request for missing constructor data in terms of either:
@@ -1127,6 +1197,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
     matrix: &Matrix<'p, 'tcx>,
     v: &[&Pat<'tcx>],
     witness: WitnessPreference,
+    hir_id: HirId,
 ) -> Usefulness<'tcx> {
     let &Matrix(ref rows) = matrix;
     debug!("is_useful({:#?}, {:#?})", matrix, v);
@@ -1149,6 +1220,10 @@ pub fn is_useful<'p, 'a, 'tcx>(
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
+    let (ty, span) = rows.iter()
+        .map(|r| (r[0].ty, r[0].span))
+        .find(|(ty, _)| !ty.references_error())
+        .unwrap_or((v[0].ty, v[0].span));
     let pcx = PatCtxt {
         // TyErr is used to represent the type of wildcard patterns matching
         // against inaccessible (private) fields of structs, so that we won't
@@ -1169,8 +1244,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
         // FIXME: this might lead to "unstable" behavior with macro hygiene
         // introducing uninhabited patterns for inaccessible fields. We
         // need to figure out how to model that.
-        ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error()).unwrap_or(v[0].ty),
-        max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
+        ty,
+        max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))),
+        span,
     };
 
     debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
@@ -1184,9 +1260,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
             Useful
         } else {
             split_grouped_constructors(
-                cx.tcx, cx.param_env, constructors, matrix, pcx.ty,
+                cx.tcx, cx.param_env, constructors, matrix, pcx.ty, pcx.span, Some(hir_id),
             ).into_iter().map(|c|
-                is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
+                is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id)
             ).find(|result| result.is_useful()).unwrap_or(NotUseful)
         }
     } else {
@@ -1239,8 +1315,11 @@ pub fn is_useful<'p, 'a, 'tcx>(
             (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
 
         if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
-            split_grouped_constructors(cx.tcx, cx.param_env, all_ctors, matrix, pcx.ty)
-                .into_iter().map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness))
+            split_grouped_constructors(
+                cx.tcx, cx.param_env, all_ctors, matrix, pcx.ty, DUMMY_SP, None,
+            )
+                .into_iter()
+                .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id))
                 .find(|result| result.is_useful())
                 .unwrap_or(NotUseful)
         } else {
@@ -1251,7 +1330,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
                     None
                 }
             }).collect();
-            match is_useful(cx, &matrix, &v[1..], witness) {
+            match is_useful(cx, &matrix, &v[1..], witness, hir_id) {
                 UsefulWithWitness(pats) => {
                     let cx = &*cx;
                     // In this case, there's at least one "free"
@@ -1344,6 +1423,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
     ctor: Constructor<'tcx>,
     lty: Ty<'tcx>,
     witness: WitnessPreference,
+    hir_id: HirId,
 ) -> Usefulness<'tcx> {
     debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
     let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
@@ -1361,7 +1441,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
             .collect()
     );
     match specialize(cx, v, &ctor, &wild_patterns) {
-        Some(v) => match is_useful(cx, &matrix, &v, witness) {
+        Some(v) => match is_useful(cx, &matrix, &v, witness, hir_id) {
             UsefulWithWitness(witnesses) => UsefulWithWitness(
                 witnesses.into_iter()
                     .map(|witness| witness.apply_constructor(cx, &ctor, lty))
@@ -1381,11 +1461,11 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
 /// Returns `None` in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
-                          pat: &Pat<'tcx>,
-                          pcx: PatCtxt<'tcx>)
-                          -> Option<Vec<Constructor<'tcx>>>
-{
+fn pat_constructors<'tcx>(
+    cx: &mut MatchCheckCtxt<'_, 'tcx>,
+    pat: &Pat<'tcx>,
+    pcx: PatCtxt<'tcx>,
+) -> Option<Vec<Constructor<'tcx>>> {
     match *pat.kind {
         PatKind::AscribeUserType { ref subpattern, .. } =>
             pat_constructors(cx, subpattern, pcx),
@@ -1394,13 +1474,14 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
         PatKind::Variant { adt_def, variant_index, .. } => {
             Some(vec![Variant(adt_def.variants[variant_index].def_id)])
         }
-        PatKind::Constant { value } => Some(vec![ConstantValue(value)]),
+        PatKind::Constant { value } => Some(vec![ConstantValue(value, pat.span)]),
         PatKind::Range(PatRange { lo, hi, end }) =>
             Some(vec![ConstantRange(
                 lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
                 hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
                 lo.ty,
                 end,
+                pat.span,
             )]),
         PatKind::Array { .. } => match pcx.ty.kind {
             ty::Array(_, length) => Some(vec![
@@ -1433,7 +1514,7 @@ fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty
         ty::Tuple(ref fs) => fs.len() as u64,
         ty::Slice(..) | ty::Array(..) => match *ctor {
             Slice(length) => length,
-            ConstantValue(_) => 0,
+            ConstantValue(..) => 0,
             _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
         }
         ty::Ref(..) => 1,
@@ -1458,7 +1539,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx>(
         ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(),
         ty::Slice(ty) | ty::Array(ty, _) => match *ctor {
             Slice(length) => (0..length).map(|_| ty).collect(),
-            ConstantValue(_) => vec![],
+            ConstantValue(..) => vec![],
             _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
         }
         ty::Ref(_, rty, _) => vec![rty],
@@ -1556,8 +1637,8 @@ fn slice_pat_covered_by_const<'tcx>(
 // constructor is a range or constant with an integer type.
 fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) -> bool {
     let ty = match ctor {
-        ConstantValue(value) => value.ty,
-        ConstantRange(_, _, ty, _) => ty,
+        ConstantValue(value, _) => value.ty,
+        ConstantRange(_, _, ty, _, _) => ty,
         _ => return false,
     };
     if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.kind {
@@ -1599,12 +1680,17 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
 /// boundaries for each interval range, sort them, then create constructors for each new interval
 /// between every pair of boundary points. (This essentially sums up to performing the intuitive
 /// merging operation depicted above.)
+///
+/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
+/// ranges that case.
 fn split_grouped_constructors<'p, 'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ctors: Vec<Constructor<'tcx>>,
     &Matrix(ref m): &Matrix<'p, 'tcx>,
     ty: Ty<'tcx>,
+    span: Span,
+    hir_id: Option<HirId>,
 ) -> Vec<Constructor<'tcx>> {
     let mut split_ctors = Vec::with_capacity(ctors.len());
 
@@ -1621,7 +1707,7 @@ fn split_grouped_constructors<'p, 'tcx>(
                 /// Represents a border between 2 integers. Because the intervals spanning borders
                 /// must be able to cover every integer, we need to be able to represent
                 /// 2^128 + 1 such borders.
-                #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+                #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
                 enum Border {
                     JustBefore(u128),
                     AfterMax,
@@ -1638,16 +1724,38 @@ fn split_grouped_constructors<'p, 'tcx>(
                     vec![from, to].into_iter()
                 }
 
+                // Collect the span and range of all the intersecting ranges to lint on likely
+                // incorrect range patterns. (#63987)
+                let mut overlaps = vec![];
                 // `borders` is the set of borders between equivalence classes: each equivalence
                 // class lies between 2 borders.
                 let row_borders = m.iter()
-                    .flat_map(|row| IntRange::from_pat(tcx, param_env, row[0]))
-                    .flat_map(|range| ctor_range.intersection(&range))
+                    .flat_map(|row| {
+                        IntRange::from_pat(tcx, param_env, row[0]).map(|r| (r, row.len()))
+                    })
+                    .flat_map(|(range, row_len)| {
+                        let intersection = ctor_range.intersection(&range);
+                        let should_lint = ctor_range.suspicious_intersection(&range);
+                        if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
+                            // FIXME: for now, only check for overlapping ranges on simple range
+                            // patterns. Otherwise with the current logic the following is detected
+                            // as overlapping:
+                            //   match (10u8, true) {
+                            //    (0 ..= 125, false) => {}
+                            //    (126 ..= 255, false) => {}
+                            //    (0 ..= 255, true) => {}
+                            //  }
+                            overlaps.push(range.clone());
+                        }
+                        intersection
+                    })
                     .flat_map(|range| range_borders(range));
                 let ctor_borders = range_borders(ctor_range.clone());
                 let mut borders: Vec<_> = row_borders.chain(ctor_borders).collect();
                 borders.sort_unstable();
 
+                lint_overlapping_patterns(tcx, hir_id, ctor_range, ty, overlaps);
+
                 // We're going to iterate through every pair of borders, making sure that each
                 // represents an interval of nonnegative length, and convert each such interval
                 // into a constructor.
@@ -1655,18 +1763,18 @@ fn split_grouped_constructors<'p, 'tcx>(
                     match (window[0], window[1]) {
                         (Border::JustBefore(n), Border::JustBefore(m)) => {
                             if n < m {
-                                Some(IntRange { range: n..=(m - 1), ty })
+                                Some(IntRange { range: n..=(m - 1), ty, span })
                             } else {
                                 None
                             }
                         }
                         (Border::JustBefore(n), Border::AfterMax) => {
-                            Some(IntRange { range: n..=u128::MAX, ty })
+                            Some(IntRange { range: n..=u128::MAX, ty, span })
                         }
                         (Border::AfterMax, _) => None,
                     }
                 }) {
-                    split_ctors.push(IntRange::range_to_ctor(tcx, ty, range));
+                    split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span));
                 }
             }
             // Any other constructor can be used unchanged.
@@ -1677,6 +1785,32 @@ fn split_grouped_constructors<'p, 'tcx>(
     split_ctors
 }
 
+fn lint_overlapping_patterns(
+    tcx: TyCtxt<'tcx>,
+    hir_id: Option<HirId>,
+    ctor_range: IntRange<'tcx>,
+    ty: Ty<'tcx>,
+    overlaps: Vec<IntRange<'tcx>>,
+) {
+    if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
+        let mut err = tcx.struct_span_lint_hir(
+            lint::builtin::OVERLAPPING_PATTERNS,
+            hir_id,
+            ctor_range.span,
+            "multiple patterns covering the same range",
+        );
+        err.span_label(ctor_range.span, "overlapping patterns");
+        for int_range in overlaps {
+            // Use the real type for user display of the ranges:
+            err.span_label(int_range.span, &format!(
+                "this range overlaps on `{}`",
+                IntRange::range_to_ctor(tcx, ty, int_range.range, DUMMY_SP).display(tcx),
+            ));
+        }
+        err.emit();
+    }
+}
+
 fn constructor_covered_by_range<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -1701,13 +1835,13 @@ fn constructor_covered_by_range<'tcx>(
         };
     }
     match *ctor {
-        ConstantValue(value) => {
+        ConstantValue(value, _) => {
             let to = some_or_ok!(cmp_to(value));
             let end = (to == Ordering::Less) ||
                       (end == RangeEnd::Included && to == Ordering::Equal);
             Ok(some_or_ok!(cmp_from(value)) && end)
         },
-        ConstantRange(from, to, ty, RangeEnd::Included) => {
+        ConstantRange(from, to, ty, RangeEnd::Included, _) => {
             let to = some_or_ok!(cmp_to(ty::Const::from_bits(
                 tcx,
                 to,
@@ -1721,7 +1855,7 @@ fn constructor_covered_by_range<'tcx>(
                 ty::ParamEnv::empty().and(ty),
             ))) && end)
         },
-        ConstantRange(from, to, ty, RangeEnd::Excluded) => {
+        ConstantRange(from, to, ty, RangeEnd::Excluded, _) => {
             let to = some_or_ok!(cmp_to(ty::Const::from_bits(
                 tcx,
                 to,
@@ -1915,7 +2049,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
                         None
                     }
                 }
-                ConstantValue(cv) => {
+                ConstantValue(cv, _) => {
                     match slice_pat_covered_by_const(
                         cx.tcx, pat.span, cv, prefix, slice, suffix, cx.param_env,
                     ) {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 9bed4fb66ea..77f3768172f 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -10,6 +10,7 @@ use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::lint;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 
+use rustc::hir::HirId;
 use rustc::hir::def::*;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
@@ -153,7 +154,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
                         self.tables
                     );
                     patcx.include_lint_checks();
-                    let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
+                    let pattern =
+                        cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&pat))) as &_;
                     if !patcx.errors.is_empty() {
                         patcx.report_inlining_errors(pat.span);
                         have_errors = true;
@@ -239,7 +241,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
                 .map(|pat| smallvec![pat.0])
                 .collect();
             let scrut_ty = self.tables.node_type(scrut.hir_id);
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix);
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
         })
     }
 
@@ -252,11 +254,12 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
             patcx.include_lint_checks();
             let pattern = patcx.lower_pattern(pat);
             let pattern_ty = pattern.ty;
+            let pattern = expand_pattern(cx, pattern);
             let pats: Matrix<'_, '_> = vec![smallvec![
-                expand_pattern(cx, pattern)
+                &pattern
             ]].into_iter().collect();
 
-            let witnesses = match check_not_useful(cx, pattern_ty, &pats) {
+            let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
                 Ok(_) => return,
                 Err(err) => err,
             };
@@ -389,7 +392,7 @@ fn check_arms<'tcx>(
         for &(pat, hir_pat) in pats {
             let v = smallvec![pat];
 
-            match is_useful(cx, &seen, &v, LeaveOutWitness) {
+            match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
                 NotUseful => {
                     match source {
                         hir::MatchSource::IfDesugar { .. } |
@@ -465,9 +468,10 @@ fn check_not_useful(
     cx: &mut MatchCheckCtxt<'_, 'tcx>,
     ty: Ty<'tcx>,
     matrix: &Matrix<'_, 'tcx>,
+    hir_id: HirId,
 ) -> Result<(), Vec<super::Pat<'tcx>>> {
     let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
-    match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness) {
+    match is_useful(cx, matrix, &[&wild_pattern], ConstructWitness, hir_id) {
         NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
         UsefulWithWitness(pats) => Err(if pats.is_empty() {
             vec![wild_pattern]
@@ -483,8 +487,9 @@ fn check_exhaustive<'tcx>(
     scrut_ty: Ty<'tcx>,
     sp: Span,
     matrix: &Matrix<'_, 'tcx>,
+    hir_id: HirId,
 ) {
-    let witnesses = match check_not_useful(cx, scrut_ty, matrix) {
+    let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
         Ok(_) => return,
         Err(err) => err,
     };
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 58d741b9295..58480912929 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -312,10 +312,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
             }
             PatKind::Range(PatRange { lo, hi, end }) => {
                 write!(f, "{}", lo)?;
-                match end {
-                    RangeEnd::Included => write!(f, "..=")?,
-                    RangeEnd::Excluded => write!(f, "..")?,
-                }
+                write!(f, "{}", end)?;
                 write!(f, "{}", hi)
             }
             PatKind::Slice { ref prefix, ref slice, ref suffix } |
@@ -1217,7 +1214,7 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
 
         // tracks ADT's previously encountered during search, so that
         // we will not recur on them again.
-        seen: FxHashSet<&'tcx AdtDef>,
+        seen: FxHashSet<hir::def_id::DefId>,
     }
 
     impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
@@ -1257,14 +1254,12 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
                 return true // Halt visiting!
             }
 
-            if self.seen.contains(adt_def) {
+            if !self.seen.insert(adt_def.did) {
                 debug!("Search already seen adt_def: {:?}", adt_def);
                 // let caller continue its search
                 return false;
             }
 
-            self.seen.insert(adt_def);
-
             // `#[structural_match]` does not care about the
             // instantiation of the generics in an ADT (it
             // instead looks directly at its fields outside
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index e1c45132103..d929e958f05 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -35,7 +35,7 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     pub(crate) param_env: ty::ParamEnv<'tcx>,
 
     /// The virtual memory system.
-    pub(crate) memory: Memory<'mir, 'tcx, M>,
+    pub memory: Memory<'mir, 'tcx, M>,
 
     /// The virtual call stack.
     pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
@@ -91,7 +91,7 @@ pub struct Frame<'mir, 'tcx, Tag=(), Extra=()> {
     pub extra: Extra,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Clone, Eq, PartialEq, Debug)] // Miri debug-prints these
 pub enum StackPopCleanup {
     /// Jump to the next block in the caller, or cause UB if None (that's a function
     /// that may never return). Also store layout of return place so
@@ -113,7 +113,7 @@ pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
 }
 
 /// Current value of a local variable
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug)] // Miri debug-prints these
 pub enum LocalValue<Tag=(), Id=AllocId> {
     /// This local is not currently alive, and cannot be used at all.
     Dead,
@@ -212,16 +212,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     #[inline(always)]
-    pub fn memory(&self) -> &Memory<'mir, 'tcx, M> {
-        &self.memory
-    }
-
-    #[inline(always)]
-    pub fn memory_mut(&mut self) -> &mut Memory<'mir, 'tcx, M> {
-        &mut self.memory
-    }
-
-    #[inline(always)]
     pub fn force_ptr(
         &self,
         scalar: Scalar<M::PointerTag>,
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index ec06b6298e1..646d1783c8e 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -73,8 +73,7 @@ fn intern_shallow<'rt, 'mir, 'tcx>(
     );
     // remove allocation
     let tcx = ecx.tcx;
-    let memory = ecx.memory_mut();
-    let (kind, mut alloc) = match memory.alloc_map.remove(&alloc_id) {
+    let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) {
         Some(entry) => entry,
         None => {
             // Pointer not found in local memory map. It is either a pointer to the global
@@ -332,7 +331,7 @@ pub fn intern_const_alloc_recursive(
 
     let mut todo: Vec<_> = leftover_allocations.iter().cloned().collect();
     while let Some(alloc_id) = todo.pop() {
-        if let Some((_, mut alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
+        if let Some((_, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) {
             // We can't call the `intern_shallow` method here, as its logic is tailored to safe
             // references and a `leftover_allocations` set (where we only have a todo-list here).
             // So we hand-roll the interning logic here again.
@@ -350,7 +349,7 @@ pub fn intern_const_alloc_recursive(
                     todo.push(reloc);
                 }
             }
-        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
+        } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
             // dangling pointer
             throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into()))
         }
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 924474c5317..eef1868ec65 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -7,7 +7,7 @@
 //! short-circuiting the empty case!
 
 use std::collections::VecDeque;
-use std::ptr;
+use std::{ptr, iter};
 use std::borrow::Cow;
 
 use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
@@ -22,7 +22,7 @@ use super::{
     Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg,
 };
 
-#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
+#[derive(Debug, PartialEq, Copy, Clone)]
 pub enum MemoryKind<T> {
     /// Error if deallocated except during a stack pop
     Stack,
@@ -785,6 +785,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         self.get(ptr.alloc_id)?.read_c_str(self, ptr)
     }
 
+    /// Writes the given stream of bytes into memory.
+    ///
+    /// Performs appropriate bounds checks.
+    pub fn write_bytes(
+        &mut self,
+        ptr: Scalar<M::PointerTag>,
+        src: impl IntoIterator<Item=u8, IntoIter: iter::ExactSizeIterator>,
+    ) -> InterpResult<'tcx>
+    {
+        let src = src.into_iter();
+        let size = Size::from_bytes(src.len() as u64);
+        let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? {
+            Some(ptr) => ptr,
+            None => return Ok(()), // zero-sized access
+        };
+        let tcx = self.tcx.tcx;
+        self.get_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src)
+    }
+
     /// Expects the caller to have checked bounds and alignment.
     pub fn copy(
         &mut self,
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 4bdd71f9602..4fd5e6a5435 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -26,7 +26,7 @@ pub use rustc::mir::interpret::ScalarMaybeUndef;
 /// operations and fat pointers. This idea was taken from rustc's codegen.
 /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
 /// defined on `Immediate`, and do not have to work with a `Place`.
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum Immediate<Tag=(), Id=AllocId> {
     Scalar(ScalarMaybeUndef<Tag, Id>),
     ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
@@ -123,7 +123,7 @@ impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
 /// An `Operand` is the result of computing a `mir::Operand`. It can be immediate,
 /// or still in memory. The latter is an optimization, to delay reading that chunk of
 /// memory and to avoid having to store arbitrary-sized data here.
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum Operand<Tag=(), Id=AllocId> {
     Immediate(Immediate<Tag, Id>),
     Indirect(MemPlace<Tag, Id>),
@@ -153,7 +153,7 @@ impl<Tag> Operand<Tag> {
     }
 }
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 pub struct OpTy<'tcx, Tag=()> {
     op: Operand<Tag>, // Keep this private, it helps enforce invariants
     pub layout: TyLayout<'tcx>,
@@ -589,8 +589,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let ptr = self.tag_static_base_pointer(Pointer::new(id, offset));
                 Operand::Indirect(MemPlace::from_ptr(ptr, layout.align.abi))
             },
-            ConstValue::Scalar(x) =>
-                Operand::Immediate(tag_scalar(x).into()),
+            ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x).into()),
             ConstValue::Slice { data, start, end } => {
                 // We rely on mutability being set correctly in `data` to prevent writes
                 // where none should happen.
@@ -606,6 +605,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             ConstValue::Param(..) |
             ConstValue::Infer(..) |
+            ConstValue::Bound(..) |
             ConstValue::Placeholder(..) |
             ConstValue::Unevaluated(..) =>
                 bug!("eval_const_to_op: Unexpected ConstValue {:?}", val),
@@ -647,7 +647,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let bits_discr = raw_discr
                     .not_undef()
                     .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size))
-                    .map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?;
+                    .map_err(|_| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?;
                 let real_discr = if discr_val.layout.ty.is_signed() {
                     // going from layout tag type to typeck discriminant type
                     // requires first sign extending with the discriminant layout
@@ -677,7 +677,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     _ => bug!("tagged layout for non-adt non-generator"),
 
                 }.ok_or_else(
-                    || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag()))
+                    || err_ub!(InvalidDiscriminant(raw_discr.erase_tag()))
                 )?;
                 (real_discr, index.0)
             },
@@ -689,7 +689,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let variants_start = niche_variants.start().as_u32();
                 let variants_end = niche_variants.end().as_u32();
                 let raw_discr = raw_discr.not_undef().map_err(|_| {
-                    err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef))
+                    err_ub!(InvalidDiscriminant(ScalarMaybeUndef::Undef))
                 })?;
                 match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
                     Err(ptr) => {
@@ -697,7 +697,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let ptr_valid = niche_start == 0 && variants_start == variants_end &&
                             !self.memory.ptr_may_be_null(ptr);
                         if !ptr_valid {
-                            throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag().into()))
+                            throw_ub!(InvalidDiscriminant(raw_discr.erase_tag().into()))
                         }
                         (dataful_variant.as_u32() as u128, dataful_variant)
                     },
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 3ba989529f1..0289c52fd37 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -9,7 +9,7 @@ use rustc::mir;
 use rustc::mir::interpret::truncate;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{
-    self, Size, Abi, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt
+    self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt
 };
 use rustc::ty::TypeFoldable;
 
@@ -377,20 +377,17 @@ where
             layout::FieldPlacement::Array { stride, .. } => {
                 let len = base.len(self)?;
                 if field >= len {
-                    // This can be violated because this runs during promotion on code where the
-                    // type system has not yet ensured that such things don't happen.
+                    // This can be violated because the index (field) can be a runtime value
+                    // provided by the user.
                     debug!("tried to access element {} of array/slice with length {}", field, len);
                     throw_panic!(BoundsCheck { len, index: field });
                 }
                 stride * field
             }
             layout::FieldPlacement::Union(count) => {
-                // FIXME(#64506) `UninhabitedValue` can be removed when this issue is resolved
-                if base.layout.abi == Abi::Uninhabited {
-                    throw_unsup!(UninhabitedValue);
-                }
                 assert!(field < count as u64,
-                        "Tried to access field {} of union with {} fields", field, count);
+                        "Tried to access field {} of union {:#?} with {} fields",
+                        field, base.layout, count);
                 // Offset is always 0
                 Size::from_bytes(0)
             }
@@ -1034,9 +1031,13 @@ where
         variant_index: VariantIdx,
         dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
+        let variant_scalar = Scalar::from_u32(variant_index.as_u32()).into();
+
         match dest.layout.variants {
             layout::Variants::Single { index } => {
-                assert_eq!(index, variant_index);
+                if index != variant_index {
+                    throw_ub!(InvalidDiscriminant(variant_scalar));
+                }
             }
             layout::Variants::Multiple {
                 discr_kind: layout::DiscriminantKind::Tag,
@@ -1044,7 +1045,9 @@ where
                 discr_index,
                 ..
             } => {
-                assert!(dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index));
+                if !dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index) {
+                    throw_ub!(InvalidDiscriminant(variant_scalar));
+                }
                 let discr_val =
                     dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
 
@@ -1067,9 +1070,9 @@ where
                 discr_index,
                 ..
             } => {
-                assert!(
-                    variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
-                );
+                if !variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len() {
+                    throw_ub!(InvalidDiscriminant(variant_scalar));
+                }
                 if variant_index != dataful_variant {
                     let variants_start = niche_variants.start().as_u32();
                     let variant_index_relative = variant_index.as_u32()
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 11c7cd0d901..7f6baf0bb49 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -140,12 +140,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                                 .read_immediate(self.eval_operand(len, None)?)
                                 .expect("can't eval len")
                                 .to_scalar()?
-                                .to_bits(self.memory().pointer_size())? as u64;
+                                .to_bits(self.memory.pointer_size())? as u64;
                             let index = self
                                 .read_immediate(self.eval_operand(index, None)?)
                                 .expect("can't eval index")
                                 .to_scalar()?
-                                .to_bits(self.memory().pointer_size())? as u64;
+                                .to_bits(self.memory.pointer_size())? as u64;
                             err_panic!(BoundsCheck { len, index })
                         }
                         Overflow(op) => err_panic!(Overflow(*op)),
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 853fcb1beab..3444fb60f33 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -344,7 +344,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         match self.walk_value(op) {
             Ok(()) => Ok(()),
             Err(err) => match err.kind {
-                err_unsup!(InvalidDiscriminant(val)) =>
+                err_ub!(InvalidDiscriminant(val)) =>
                     throw_validation_failure!(
                         val, self.path, "a valid enum discriminant"
                     ),
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index a837c34e8d4..98d5487870a 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -14,6 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(core_intrinsics)]
 #![feature(const_fn)]
 #![feature(decl_macro)]
+#![feature(drain_filter)]
 #![feature(exhaustive_patterns)]
 #![feature(never_type)]
 #![feature(specialization)]
diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs
index da3fead1f9d..158b730b9bd 100644
--- a/src/librustc_mir/lints.rs
+++ b/src/librustc_mir/lints.rs
@@ -72,13 +72,11 @@ fn check_fn_for_unconditional_recursion(
     let caller_substs = &InternalSubsts::identity_for_item(tcx, def_id)[..trait_substs_count];
 
     while let Some(bb) = reachable_without_self_call_queue.pop() {
-        if visited.contains(bb) {
+        if !visited.insert(bb) {
             //already done
             continue;
         }
 
-        visited.insert(bb);
-
         let block = &basic_blocks[bb];
 
         if let Some(ref terminator) = block.terminator {
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index ee7452d3e8b..5e31b80bec6 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -199,7 +199,7 @@ use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter};
 
 use std::iter;
 
-#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
+#[derive(PartialEq)]
 pub enum MonoItemCollectionMode {
     Eager,
     Lazy
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 49ac1de8fef..108c6c9786b 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -8,7 +8,7 @@ use rustc::hir::def::DefKind;
 use rustc::hir::def_id::DefId;
 use rustc::mir::{
     AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
-    Local, NullOp, UnOp, StatementKind, Statement, LocalKind,
+    Local, UnOp, StatementKind, Statement, LocalKind,
     TerminatorKind, Terminator,  ClearCrossCrate, SourceInfo, BinOp,
     SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
 };
@@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
 struct ConstPropMachine;
 
 impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
-    type MemoryKinds= !;
+    type MemoryKinds = !;
     type PointerTag = ();
     type ExtraFnVal = !;
 
@@ -431,35 +431,26 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         place_layout: TyLayout<'tcx>,
         source_info: SourceInfo,
         place: &Place<'tcx>,
-    ) -> Option<Const<'tcx>> {
+    ) -> Option<()> {
         let span = source_info.span;
 
-        // if this isn't a supported operation, then return None
-        match rvalue {
-            Rvalue::Repeat(..) |
-            Rvalue::Aggregate(..) |
-            Rvalue::NullaryOp(NullOp::Box, _) |
-            Rvalue::Discriminant(..) => return None,
-
-            Rvalue::Use(_) |
-            Rvalue::Len(_) |
-            Rvalue::Cast(..) |
-            Rvalue::NullaryOp(..) |
-            Rvalue::CheckedBinaryOp(..) |
-            Rvalue::Ref(..) |
-            Rvalue::UnaryOp(..) |
-            Rvalue::BinaryOp(..) => { }
-        }
+        let overflow_check = self.tcx.sess.overflow_checks();
 
-        // perform any special checking for specific Rvalue types
-        if let Rvalue::UnaryOp(op, arg) = rvalue {
-            trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
-            let overflow_check = self.tcx.sess.overflow_checks();
+        // Perform any special handling for specific Rvalue types.
+        // Generally, checks here fall into one of two categories:
+        //   1. Additional checking to provide useful lints to the user
+        //        - In this case, we will do some validation and then fall through to the
+        //          end of the function which evals the assignment.
+        //   2. Working around bugs in other parts of the compiler
+        //        - In this case, we'll return `None` from this function to stop evaluation.
+        match rvalue {
+            // Additional checking: if overflow checks are disabled (which is usually the case in
+            // release mode), then we need to do additional checking here to give lints to the user
+            // if an overflow would occur.
+            Rvalue::UnaryOp(UnOp::Neg, arg) if !overflow_check => {
+                trace!("checking UnaryOp(op = Neg, arg = {:?})", arg);
 
-            self.use_ecx(source_info, |this| {
-                // We check overflow in debug mode already
-                // so should only check in release mode.
-                if *op == UnOp::Neg && !overflow_check {
+                self.use_ecx(source_info, |this| {
                     let ty = arg.ty(&this.local_decls, this.tcx);
 
                     if ty.is_integral() {
@@ -471,76 +462,91 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                             throw_panic!(OverflowNeg)
                         }
                     }
+
+                    Ok(())
+                })?;
+            }
+
+            // Additional checking: check for overflows on integer binary operations and report
+            // them to the user as lints.
+            Rvalue::BinaryOp(op, left, right) => {
+                trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
+
+                let r = self.use_ecx(source_info, |this| {
+                    this.ecx.read_immediate(this.ecx.eval_operand(right, None)?)
+                })?;
+                if *op == BinOp::Shr || *op == BinOp::Shl {
+                    let left_bits = place_layout.size.bits();
+                    let right_size = r.layout.size;
+                    let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
+                    if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
+                        let source_scope_local_data = match self.source_scope_local_data {
+                            ClearCrossCrate::Set(ref data) => data,
+                            ClearCrossCrate::Clear => return None,
+                        };
+                        let dir = if *op == BinOp::Shr {
+                            "right"
+                        } else {
+                            "left"
+                        };
+                        let hir_id = source_scope_local_data[source_info.scope].lint_root;
+                        self.tcx.lint_hir(
+                            ::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
+                            hir_id,
+                            span,
+                            &format!("attempt to shift {} with overflow", dir));
+                        return None;
+                    }
                 }
 
-                Ok(())
-            })?;
-        } else if let Rvalue::BinaryOp(op, left, right) = rvalue {
-            trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
-
-            let r = self.use_ecx(source_info, |this| {
-                this.ecx.read_immediate(this.ecx.eval_operand(right, None)?)
-            })?;
-            if *op == BinOp::Shr || *op == BinOp::Shl {
-                let left_bits = place_layout.size.bits();
-                let right_size = r.layout.size;
-                let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
-                if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
-                    let source_scope_local_data = match self.source_scope_local_data {
-                        ClearCrossCrate::Set(ref data) => data,
-                        ClearCrossCrate::Clear => return None,
-                    };
-                    let dir = if *op == BinOp::Shr {
-                        "right"
-                    } else {
-                        "left"
-                    };
-                    let hir_id = source_scope_local_data[source_info.scope].lint_root;
-                    self.tcx.lint_hir(
-                        ::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
-                        hir_id,
-                        span,
-                        &format!("attempt to shift {} with overflow", dir));
-                    return None;
+                // If overflow checking is enabled (like in debug mode by default),
+                // then we'll already catch overflow when we evaluate the `Assert` statement
+                // in MIR. However, if overflow checking is disabled, then there won't be any
+                // `Assert` statement and so we have to do additional checking here.
+                if !overflow_check {
+                    self.use_ecx(source_info, |this| {
+                        let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
+                        let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?;
+
+                        if overflow {
+                            let err = err_panic!(Overflow(*op)).into();
+                            return Err(err);
+                        }
+
+                        Ok(())
+                    })?;
                 }
             }
-            self.use_ecx(source_info, |this| {
-                let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
-                let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?;
-
-                // We check overflow in debug mode already
-                // so should only check in release mode.
-                if !this.tcx.sess.overflow_checks() && overflow {
-                    let err = err_panic!(Overflow(*op)).into();
-                    return Err(err);
-                }
 
-                Ok(())
-            })?;
-        } else if let Rvalue::Ref(_, _, place) = rvalue {
-            trace!("checking Ref({:?})", place);
-            // FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
-            // from a function argument that hasn't been assigned to in this function.
-            if let Place {
-                base: PlaceBase::Local(local),
-                projection: box []
-            } = place {
+            // Work around: avoid ICE in miri. FIXME(wesleywiser)
+            // The Miri engine ICEs when taking a reference to an uninitialized unsized
+            // local. There's nothing it can do here: taking a reference needs an allocation
+            // which needs to know the size. Normally that's okay as during execution
+            // (e.g. for CTFE) it can never happen. But here in const_prop
+            // unknown data is uninitialized, so if e.g. a function argument is unsized
+            // and has a reference taken, we get an ICE.
+            Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => {
+                trace!("checking Ref({:?})", place);
                 let alive =
                     if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
                         true
-                    } else { false };
+                    } else {
+                        false
+                    };
 
-                if local.as_usize() <= self.ecx.frame().body.arg_count && !alive {
-                    trace!("skipping Ref({:?})", place);
+                if !alive {
+                    trace!("skipping Ref({:?}) to uninitialized local", place);
                     return None;
                 }
             }
+
+            _ => { }
         }
 
         self.use_ecx(source_info, |this| {
             trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
             this.ecx.eval_rvalue_into_place(rvalue, place)?;
-            this.ecx.eval_place_to_op(place, Some(place_layout))
+            Ok(())
         })
     }
 
@@ -704,16 +710,15 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                     base: PlaceBase::Local(local),
                     projection: box [],
                 } = *place {
-                    if let Some(value) = self.const_prop(rval,
-                                                         place_layout,
-                                                         statement.source_info,
-                                                         place) {
-                        trace!("checking whether {:?} can be stored to {:?}", value, local);
+                    let source = statement.source_info;
+                    if let Some(()) = self.const_prop(rval, place_layout, source, place) {
                         if self.can_const_prop[local] {
-                            trace!("stored {:?} to {:?}", value, local);
-                            assert_eq!(self.get_const(local), Some(value));
+                            trace!("propagated into {:?}", local);
 
                             if self.should_const_prop() {
+                                let value =
+                                    self.get_const(local).expect("local was dead/uninitialized");
+                                trace!("replacing {:?} with {:?}", rval, value);
                                 self.replace_with_const(
                                     rval,
                                     value,
@@ -721,7 +726,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                                 );
                             }
                         } else {
-                            trace!("can't propagate {:?} to {:?}", value, local);
+                            trace!("can't propagate into {:?}", local);
                             self.remove_const(local);
                         }
                     }
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 38a04ce8f38..439cae2093a 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -25,7 +25,6 @@ impl EraseRegionsVisitor<'tcx> {
 impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
         *ty = self.tcx.erase_regions(ty);
-        self.super_ty(ty);
     }
 
     fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
@@ -39,6 +38,21 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
     fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) {
         *substs = self.tcx.erase_regions(substs);
     }
+
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        if let PlaceElem::Field(field, ty) = elem {
+            let new_ty = self.tcx.erase_regions(ty);
+
+            if new_ty != *ty {
+                return Some(PlaceElem::Field(*field, new_ty));
+            }
+        }
+
+        None
+    }
 }
 
 pub struct EraseRegions;
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 865fa012c29..6533e3c5ba8 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -88,6 +88,18 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
             *local = self.to;
         }
     }
+
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Index(local) if *local == self.from => {
+                Some(PlaceElem::Index(self.to))
+            }
+            _ => None,
+        }
+    }
 }
 
 struct DerefArgVisitor;
@@ -110,7 +122,13 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
                 projection: Box::new([ProjectionElem::Deref]),
             });
         } else {
-            self.super_place(place, context, location);
+            self.visit_place_base(&mut place.base, context, location);
+
+            for elem in place.projection.iter() {
+                if let PlaceElem::Index(local) = elem {
+                    assert_ne!(*local, self_arg());
+                }
+            }
         }
     }
 }
@@ -137,7 +155,13 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
                 projection: Box::new([ProjectionElem::Field(Field::new(0), self.ref_gen_ty)]),
             });
         } else {
-            self.super_place(place, context, location);
+            self.visit_place_base(&mut place.base, context, location);
+
+            for elem in place.projection.iter() {
+                if let PlaceElem::Index(local) = elem {
+                    assert_ne!(*local, self_arg());
+                }
+            }
         }
     }
 }
@@ -247,17 +271,25 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
         assert_eq!(self.remap.get(local), None);
     }
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    context: PlaceContext,
-                    location: Location) {
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
         if let PlaceBase::Local(l) = place.base {
             // Replace an Local in the remap with a generator struct access
             if let Some(&(ty, variant_index, idx)) = self.remap.get(&l) {
                 replace_base(place, self.make_field(variant_index, idx, ty));
             }
         } else {
-            self.super_place(place, context, location);
+            self.visit_place_base(&mut place.base, context, location);
+
+            for elem in place.projection.iter() {
+                if let PlaceElem::Index(local) = elem {
+                    assert_ne!(*local, self_arg());
+                }
+            }
         }
     }
 
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 9830ed35ffc..0cbdcedff47 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -647,38 +647,45 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
         debug!("updating target `{:?}`, new: `{:?}`", tgt, new);
         new
     }
-}
 
-impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
-    fn visit_local(&mut self,
-                   local: &mut Local,
-                   _ctxt: PlaceContext,
-                   _location: Location) {
+    fn make_integrate_local(&self, local: &Local) -> Local {
         if *local == RETURN_PLACE {
             match self.destination {
                 Place {
                     base: PlaceBase::Local(l),
                     projection: box [],
                 } => {
-                    *local = l;
-                    return;
+                    return l;
                 },
                 ref place => bug!("Return place is {:?}, not local", place)
             }
         }
+
         let idx = local.index() - 1;
         if idx < self.args.len() {
-            *local = self.args[idx];
-            return;
+            return self.args[idx];
         }
-        *local = self.local_map[Local::new(idx - self.args.len())];
+
+        self.local_map[Local::new(idx - self.args.len())]
     }
+}
 
-    fn visit_place(&mut self,
-                    place: &mut Place<'tcx>,
-                    _ctxt: PlaceContext,
-                    _location: Location) {
+impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
+    fn visit_local(
+        &mut self,
+        local: &mut Local,
+        _ctxt: PlaceContext,
+        _location: Location,
+    ) {
+        *local = self.make_integrate_local(local);
+    }
 
+    fn visit_place(
+        &mut self,
+        place: &mut Place<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
         match place {
             Place {
                 base: PlaceBase::Local(RETURN_PLACE),
@@ -687,10 +694,27 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 // Return pointer; update the place itself
                 *place = self.destination.clone();
             },
-            _ => self.super_place(place, _ctxt, _location)
+            _ => {
+                self.super_place(place, context, location);
+            }
         }
     }
 
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        if let PlaceElem::Index(local) = elem {
+            let new_local = self.make_integrate_local(local);
+
+            if new_local != *local {
+                return Some(PlaceElem::Index(new_local))
+            }
+        }
+
+        None
+    }
+
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         self.in_cleanup_block = data.is_cleanup;
         self.super_basic_block_data(block, data);
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 5d241ffe1c0..ad1785417cd 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -191,6 +191,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
         });
     }
 
+    fn is_temp_kind(&self, local: Local) -> bool {
+        self.source.local_kind(local) == LocalKind::Temp
+    }
+
     /// Copies the initialization of this temp to the
     /// promoted MIR, recursing through temps.
     fn promote_temp(&mut self, temp: Local) -> Local {
@@ -396,10 +400,22 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
                    local: &mut Local,
                    _: PlaceContext,
                    _: Location) {
-        if self.source.local_kind(*local) == LocalKind::Temp {
+        if self.is_temp_kind(*local) {
             *local = self.promote_temp(*local);
         }
     }
+
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Index(local) if self.is_temp_kind(*local) => {
+                Some(PlaceElem::Index(self.promote_temp(*local)))
+            }
+            _ => None,
+        }
+    }
 }
 
 pub fn promote_candidates<'tcx>(
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index fbcf9c8cb5e..da1abb9747c 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1024,23 +1024,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
             new_errors.dedup();
 
             if self.errors != new_errors {
-                error!("old validator: {:?}", self.errors);
-                error!("new validator: {:?}", new_errors);
-
-                // ICE on nightly if the validators do not emit exactly the same errors.
-                // Users can supress this panic with an unstable compiler flag (hopefully after
-                // filing an issue).
-                let opts = &self.tcx.sess.opts;
-                let trigger_ice = opts.unstable_features.is_nightly_build()
-                    && !opts.debugging_opts.suppress_const_validation_back_compat_ice;
-
-                if trigger_ice {
-                    span_bug!(
-                        body.span,
-                        "{}",
-                        VALIDATOR_MISMATCH_ERR,
-                    );
-                }
+                validator_mismatch(
+                    self.tcx,
+                    body,
+                    std::mem::replace(&mut self.errors, vec![]),
+                    new_errors,
+                );
             }
         }
 
@@ -1870,6 +1859,58 @@ fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<FxHashSet<usize
     Some(ret)
 }
 
+fn validator_mismatch(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    mut old_errors: Vec<(Span, String)>,
+    mut new_errors: Vec<(Span, String)>,
+) {
+    error!("old validator: {:?}", old_errors);
+    error!("new validator: {:?}", new_errors);
+
+    // ICE on nightly if the validators do not emit exactly the same errors.
+    // Users can supress this panic with an unstable compiler flag (hopefully after
+    // filing an issue).
+    let opts = &tcx.sess.opts;
+    let strict_validation_enabled = opts.unstable_features.is_nightly_build()
+        && !opts.debugging_opts.suppress_const_validation_back_compat_ice;
+
+    if !strict_validation_enabled {
+        return;
+    }
+
+    // If this difference would cause a regression from the old to the new or vice versa, trigger
+    // the ICE.
+    if old_errors.is_empty() || new_errors.is_empty() {
+        span_bug!(body.span, "{}", VALIDATOR_MISMATCH_ERR);
+    }
+
+    // HACK: Borrows that would allow mutation are forbidden in const contexts, but they cause the
+    // new validator to be more conservative about when a dropped local has been moved out of.
+    //
+    // Supress the mismatch ICE in cases where the validators disagree only on the number of
+    // `LiveDrop` errors and both observe the same sequence of `MutBorrow`s.
+
+    let is_live_drop = |(_, s): &mut (_, String)| s.starts_with("LiveDrop");
+    let is_mut_borrow = |(_, s): &&(_, String)| s.starts_with("MutBorrow");
+
+    let old_live_drops: Vec<_> = old_errors.drain_filter(is_live_drop).collect();
+    let new_live_drops: Vec<_> = new_errors.drain_filter(is_live_drop).collect();
+
+    let only_live_drops_differ = old_live_drops != new_live_drops && old_errors == new_errors;
+
+    let old_mut_borrows = old_errors.iter().filter(is_mut_borrow);
+    let new_mut_borrows = new_errors.iter().filter(is_mut_borrow);
+
+    let at_least_one_mut_borrow = old_mut_borrows.clone().next().is_some();
+
+    if only_live_drops_differ && at_least_one_mut_borrow && old_mut_borrows.eq(new_mut_borrows) {
+        return;
+    }
+
+    span_bug!(body.span, "{}", VALIDATOR_MISMATCH_ERR);
+}
+
 const VALIDATOR_MISMATCH_ERR: &str =
     r"Disagreement between legacy and dataflow-based const validators.
     After filing an issue, use `-Zsuppress-const-validation-back-compat-ice` to compile your code.";
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index cf0ee1bf092..7b6255defd1 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -14,7 +14,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
     let mut current = def_id;
     loop {
         let predicates = tcx.predicates_of(current);
-        for (predicate, _) in &predicates.predicates {
+        for (predicate, _) in predicates.predicates {
             match predicate {
                 | Predicate::RegionOutlives(_)
                 | Predicate::TypeOutlives(_)
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 9ffff9a92fa..e41b4678dbd 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -31,7 +31,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc::ty::TyCtxt;
 use rustc::mir::*;
-use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
+use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
 use rustc::session::config::DebugInfo;
 use std::borrow::Cow;
 use crate::transform::{MirPass, MirSource};
@@ -293,23 +293,31 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
-        let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) };
-        marker.visit_body(body);
-        // Return pointer and arguments are always live
-        marker.locals.insert(RETURN_PLACE);
-        for arg in body.args_iter() {
-            marker.locals.insert(arg);
-        }
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+        trace!("running SimplifyLocals on {:?}", source);
+        let locals = {
+            let mut marker = DeclMarker {
+                locals: BitSet::new_empty(body.local_decls.len()),
+                body,
+            };
+            marker.visit_body(body);
+            // Return pointer and arguments are always live
+            marker.locals.insert(RETURN_PLACE);
+            for arg in body.args_iter() {
+                marker.locals.insert(arg);
+            }
 
-        // We may need to keep dead user variables live for debuginfo.
-        if tcx.sess.opts.debuginfo == DebugInfo::Full {
-            for local in body.vars_iter() {
-                marker.locals.insert(local);
+            // We may need to keep dead user variables live for debuginfo.
+            if tcx.sess.opts.debuginfo == DebugInfo::Full {
+                for local in body.vars_iter() {
+                    marker.locals.insert(local);
+                }
             }
-        }
 
-        let map = make_local_map(&mut body.local_decls, marker.locals);
+            marker.locals
+        };
+
+        let map = make_local_map(&mut body.local_decls, locals);
         // Update references to all vars and tmps now
         LocalUpdater { map }.visit_body(body);
         body.local_decls.shrink_to_fit();
@@ -334,18 +342,35 @@ fn make_local_map<V>(
     map
 }
 
-struct DeclMarker {
+struct DeclMarker<'a, 'tcx> {
     pub locals: BitSet<Local>,
+    pub body: &'a Body<'tcx>,
 }
 
-impl<'tcx> Visitor<'tcx> for DeclMarker {
-    fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) {
+impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
+    fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) {
         // Ignore storage markers altogether, they get removed along with their otherwise unused
         // decls.
         // FIXME: Extend this to all non-uses.
-        if !ctx.is_storage_marker() {
-            self.locals.insert(*local);
+        if ctx.is_storage_marker() {
+            return;
+        }
+
+        // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
+        // of these locals. However, if the local is still needed, then it will be referenced in
+        // another place and we'll mark it as being used there.
+        if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) {
+            let stmt =
+                &self.body.basic_blocks()[location.block].statements[location.statement_index];
+            if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind {
+                if p.as_local().is_some() {
+                    trace!("skipping store of const value {:?} to {:?}", c, local);
+                    return;
+                }
+            }
         }
+
+        self.locals.insert(*local);
     }
 }
 
@@ -357,16 +382,36 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
     fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
         // Remove unnecessary StorageLive and StorageDead annotations.
         data.statements.retain(|stmt| {
-            match stmt.kind {
+            match &stmt.kind {
                 StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
-                    self.map[l].is_some()
+                    self.map[*l].is_some()
+                }
+                StatementKind::Assign(box (place, _)) => {
+                    if let Some(local) = place.as_local() {
+                        self.map[local].is_some()
+                    } else {
+                        true
+                    }
                 }
                 _ => true
             }
         });
         self.super_basic_block_data(block, data);
     }
+
     fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
         *l = self.map[*l].unwrap();
     }
+
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Index(local) => {
+                Some(PlaceElem::Index(self.map[*local].unwrap()))
+            }
+            _ => None
+        }
+    }
 }
diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs
index 3aea25fa876..cdd07ad4b8f 100644
--- a/src/librustc_mir/util/def_use.rs
+++ b/src/librustc_mir/util/def_use.rs
@@ -1,6 +1,6 @@
 //! Def-use analysis.
 
-use rustc::mir::{Local, Location, Body};
+use rustc::mir::{Body, Local, Location, PlaceElem};
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
 use rustc_index::vec::IndexVec;
 use std::mem;
@@ -47,13 +47,10 @@ impl DefUseAnalysis {
         &self.info[local]
     }
 
-    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, mut callback: F)
-                               where F: for<'a> FnMut(&'a mut Local,
-                                                      PlaceContext,
-                                                      Location) {
+    fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
         for place_use in &self.info[local].defs_and_uses {
             MutateUseVisitor::new(local,
-                                  &mut callback,
+                                  new_local,
                                   body).visit_location(body, place_use.location)
         }
     }
@@ -63,7 +60,7 @@ impl DefUseAnalysis {
                                           local: Local,
                                           body: &mut Body<'_>,
                                           new_local: Local) {
-        self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local)
+        self.mutate_defs_and_uses(local, body, new_local)
     }
 }
 
@@ -117,30 +114,39 @@ impl Info {
     }
 }
 
-struct MutateUseVisitor<F> {
+struct MutateUseVisitor {
     query: Local,
-    callback: F,
+    new_local: Local,
 }
 
-impl<F> MutateUseVisitor<F> {
-    fn new(query: Local, callback: F, _: &Body<'_>)
-           -> MutateUseVisitor<F>
-           where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
+impl MutateUseVisitor {
+    fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
         MutateUseVisitor {
             query,
-            callback,
+            new_local,
         }
     }
 }
 
-impl<F> MutVisitor<'_> for MutateUseVisitor<F>
-              where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
+impl MutVisitor<'_> for MutateUseVisitor {
     fn visit_local(&mut self,
                     local: &mut Local,
-                    context: PlaceContext,
-                    location: Location) {
+                    _context: PlaceContext,
+                    _location: Location) {
         if *local == self.query {
-            (self.callback)(local, context, location)
+            *local = self.new_local;
+        }
+    }
+
+    fn process_projection_elem(
+        &mut self,
+        elem: &PlaceElem<'tcx>,
+    ) -> Option<PlaceElem<'tcx>> {
+        match elem {
+            PlaceElem::Index(local) if *local == self.query => {
+                Some(PlaceElem::Index(self.new_local))
+            }
+            _ => None,
         }
     }
 }
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index 9d29a230314..118deb560d6 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -13,6 +13,7 @@ log = "0.4"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_target = { path = "../librustc_target" }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 0339b85ca55..74de31263d3 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -14,7 +14,7 @@ use rustc::session::Session;
 use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::*;
 use syntax::attr;
-use syntax::ext::proc_macro::is_proc_macro_attr;
+use syntax_expand::proc_macro::is_proc_macro_attr;
 use syntax::feature_gate::is_builtin_attr;
 use syntax::source_map::Spanned;
 use syntax::symbol::{kw, sym};
@@ -263,7 +263,8 @@ impl<'a> AstValidator<'a> {
                 let mut err = self.err_handler().struct_span_err(poly.span,
                     &format!("`?Trait` is not permitted in {}", where_));
                 if is_trait {
-                    err.note(&format!("traits are `?{}` by default", poly.trait_ref.path));
+                    let path_str = pprust::path_to_string(&poly.trait_ref.path);
+                    err.note(&format!("traits are `?{}` by default", path_str));
                 }
                 err.emit();
             }
diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml
index 3f11430dc82..e8bf4e7ea8f 100644
--- a/src/librustc_plugin/Cargo.toml
+++ b/src/librustc_plugin/Cargo.toml
@@ -14,4 +14,5 @@ doctest = false
 rustc = { path = "../librustc" }
 rustc_metadata = { path = "../librustc_metadata" }
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs
index 4e1a47c503e..38738e20630 100644
--- a/src/librustc_plugin/lib.rs
+++ b/src/librustc_plugin/lib.rs
@@ -21,7 +21,7 @@
 //! extern crate syntax_pos;
 //!
 //! use rustc_driver::plugin::Registry;
-//! use syntax::ext::base::{ExtCtxt, MacResult};
+//! use syntax_expand::base::{ExtCtxt, MacResult};
 //! use syntax_pos::Span;
 //! use syntax::tokenstream::TokenTree;
 //!
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index bb3c950edae..b826dd91198 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -4,8 +4,8 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
 use rustc::session::Session;
 use rustc::util::nodemap::FxHashMap;
 
-use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
-use syntax::ext::base::MacroExpanderFn;
+use syntax_expand::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
+use syntax_expand::base::MacroExpanderFn;
 use syntax::symbol::Symbol;
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index f44692b7aea..34cdec229af 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -64,7 +64,7 @@ trait DefIdVisitor<'tcx> {
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
         self.skeleton().visit_trait(trait_ref)
     }
-    fn visit_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> bool {
+    fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
         self.skeleton().visit_predicates(predicates)
     }
 }
@@ -88,7 +88,7 @@ where
         (!self.def_id_visitor.shallow() && substs.visit_with(self))
     }
 
-    fn visit_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>) -> bool {
+    fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
         let ty::GenericPredicates { parent: _, predicates } = predicates;
         for (predicate, _span) in predicates {
             match predicate {
@@ -880,11 +880,11 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             self.tcx,
             self.tcx.hir().local_def_id(md.hir_id)
         ).unwrap();
-        let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap();
-        if !self.tcx.hir().is_hir_id_module(module_id) {
-            // `module_id` doesn't correspond to a `mod`, return early (#63164).
-            return;
-        }
+        let mut module_id = match self.tcx.hir().as_local_hir_id(macro_module_def_id) {
+            Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
+            // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
+            _ => return,
+        };
         let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
         let new_level = self.update(md.hir_id, level);
         if new_level.is_none() {
diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml
index 936e72ef2c5..06bf3085989 100644
--- a/src/librustc_resolve/Cargo.toml
+++ b/src/librustc_resolve/Cargo.toml
@@ -14,6 +14,7 @@ doctest = false
 bitflags = "1.0"
 log = "0.4"
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 rustc = { path = "../librustc" }
 arena = { path = "../libarena" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 030f9b97eb8..e261d3af61f 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -32,11 +32,12 @@ use syntax::attr;
 
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
 use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
-use syntax::ext::base::{MacroKind, SyntaxExtension};
-use syntax::ext::expand::AstFragment;
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::base::{MacroKind, SyntaxExtension};
+use syntax_expand::expand::AstFragment;
+use syntax_expand::hygiene::ExpnId;
 use syntax::feature_gate::is_builtin_attr;
 use syntax::parse::token::{self, Token};
+use syntax::print::pprust;
 use syntax::{span_err, struct_span_err};
 use syntax::source_map::{respan, Spanned};
 use syntax::symbol::{kw, sym};
@@ -93,7 +94,8 @@ impl<'a> Resolver<'a> {
         where T: ToNameBinding<'a>,
     {
         let binding = def.to_name_binding(self.arenas);
-        if let Err(old_binding) = self.try_define(parent, ident, ns, binding) {
+        let key = self.new_key(ident, ns);
+        if let Err(old_binding) = self.try_define(parent, key, binding) {
             self.report_conflict(parent, ident, ns, old_binding, &binding);
         }
     }
@@ -103,8 +105,7 @@ impl<'a> Resolver<'a> {
             return self.module_map[&def_id]
         }
 
-        let macros_only = self.cstore.dep_kind_untracked(def_id.krate).macros_only();
-        if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) {
+        if let Some(&module) = self.extern_module_map.get(&def_id) {
             return module;
         }
 
@@ -120,7 +121,7 @@ impl<'a> Resolver<'a> {
         let module = self.arenas.alloc_module(ModuleData::new(
             parent, kind, def_id, ExpnId::root(), DUMMY_SP
         ));
-        self.extern_module_map.insert((def_id, macros_only), module);
+        self.extern_module_map.insert(def_id, module);
         module
     }
 
@@ -162,25 +163,15 @@ impl<'a> Resolver<'a> {
         Some(ext)
     }
 
-    // FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
     crate fn build_reduced_graph(
         &mut self,
         fragment: &AstFragment,
-        extra_placeholders: &[NodeId],
         parent_scope: ParentScope<'a>,
     ) -> LegacyScope<'a> {
         let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion);
         fragment.visit_with(&mut def_collector);
-        for placeholder in extra_placeholders {
-            def_collector.visit_macro_invoc(*placeholder);
-        }
-
         let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
         fragment.visit_with(&mut visitor);
-        for placeholder in extra_placeholders {
-            visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder);
-        }
-
         visitor.parent_scope.legacy
     }
 
@@ -228,7 +219,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         .span_suggestion(
                             path.span,
                             "try",
-                            format!("crate::{}", path),
+                            format!("crate::{}", pprust::path_to_string(&path)),
                             Applicability::MaybeIncorrect,
                         )
                         .emit();
@@ -349,9 +340,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
 
         self.r.indeterminate_imports.push(directive);
         match directive.subclass {
+            // Don't add unresolved underscore imports to modules
+            SingleImport { target: Ident { name: kw::Underscore, .. }, .. } => {}
             SingleImport { target, type_ns_only, .. } => {
                 self.r.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
-                    let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
+                    let key = this.new_key(target, ns);
+                    let mut resolution = this.resolution(current_module, key).borrow_mut();
                     resolution.add_single_import(directive);
                 });
             }
@@ -407,7 +401,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         };
         match use_tree.kind {
             ast::UseTreeKind::Simple(rename, ..) => {
-                let mut ident = use_tree.ident().gensym_if_underscore();
+                let mut ident = use_tree.ident();
                 let mut module_path = prefix;
                 let mut source = module_path.pop().unwrap();
                 let mut type_ns_only = false;
@@ -585,7 +579,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         let parent_scope = &self.parent_scope;
         let parent = parent_scope.module;
         let expansion = parent_scope.expansion;
-        let ident = item.ident.gensym_if_underscore();
+        let ident = item.ident;
         let sp = item.span;
         let vis = self.resolve_visibility(&item.vis);
 
@@ -617,6 +611,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     let crate_id = self.r.crate_loader.process_extern_crate(
                         item, &self.r.definitions
                     );
+                    self.r.extern_crate_map.insert(item.id, crate_id);
                     self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
                 };
 
@@ -850,10 +845,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
     fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
         let parent = self.parent_scope.module;
         let Export { ident, res, vis, span } = child;
-        // FIXME: We shouldn't create the gensym here, it should come from metadata,
-        // but metadata cannot encode gensyms currently, so we create it here.
-        // This is only a guess, two equivalent idents may incorrectly get different gensyms here.
-        let ident = ident.gensym_if_underscore();
         let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
         // Record primary definitions.
         match res {
@@ -1063,8 +1054,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         None
     }
 
+    // Mark the given macro as unused unless its name starts with `_`.
+    // Macro uses will remove items from this set, and the remaining
+    // items will be reported as `unused_macros`.
+    fn insert_unused_macro(&mut self, ident: Ident, node_id: NodeId, span: Span) {
+        if !ident.as_str().starts_with("_") {
+            self.r.unused_macros.insert(node_id, span);
+        }
+    }
+
     fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> {
-        let parent_scope = &self.parent_scope;
+        let parent_scope = self.parent_scope;
         let expansion = parent_scope.expansion;
         let (ext, ident, span, is_legacy) = match &item.kind {
             ItemKind::MacroDef(def) => {
@@ -1104,7 +1104,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                             (res, vis, span, expansion, IsMacroExport));
             } else {
                 self.r.check_reserved_macro_name(ident, res);
-                self.r.unused_macros.insert(item.id, span);
+                self.insert_unused_macro(ident, item.id, span);
             }
             LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding {
                 parent_legacy_scope: parent_scope.legacy, binding, ident
@@ -1113,7 +1113,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             let module = parent_scope.module;
             let vis = self.resolve_visibility(&item.vis);
             if vis != ty::Visibility::Public {
-                self.r.unused_macros.insert(item.id, span);
+                self.insert_unused_macro(ident, item.id, span);
             }
             self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
             self.parent_scope.legacy
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index d713315decb..5647d5b2794 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -10,7 +10,7 @@ use rustc::session::Session;
 use rustc::ty::{self, DefIdTree};
 use rustc::util::nodemap::FxHashSet;
 use syntax::ast::{self, Ident, Path};
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::feature_gate::BUILTIN_ATTRIBUTES;
 use syntax::source_map::SourceMap;
 use syntax::struct_span_err;
@@ -80,11 +80,11 @@ impl<'a> Resolver<'a> {
         names: &mut Vec<TypoSuggestion>,
         filter_fn: &impl Fn(Res) -> bool,
     ) {
-        for (&(ident, _), resolution) in self.resolutions(module).borrow().iter() {
+        for (key, resolution) in self.resolutions(module).borrow().iter() {
             if let Some(binding) = resolution.borrow().binding {
                 let res = binding.res();
                 if filter_fn(res) {
-                    names.push(TypoSuggestion::from_res(ident.name, res));
+                    names.push(TypoSuggestion::from_res(key.ident.name, res));
                 }
             }
         }
@@ -849,7 +849,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         }
 
         let resolutions = self.r.resolutions(crate_module).borrow();
-        let resolution = resolutions.get(&(ident, MacroNS))?;
+        let resolution = resolutions.get(&self.r.new_key(ident, MacroNS))?;
         let binding = resolution.borrow().binding()?;
         if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
             let module_name = crate_module.kind.name().unwrap();
diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs
index 47346774180..b82cba8c83d 100644
--- a/src/librustc_resolve/error_codes.rs
+++ b/src/librustc_resolve/error_codes.rs
@@ -1013,7 +1013,8 @@ fn h1() -> i32 {
 "##,
 
 E0424: r##"
-The `self` keyword was used in a static method.
+The `self` keyword was used inside of an associated function without a "`self`
+receiver" parameter.
 
 Erroneous code example:
 
@@ -1021,25 +1022,33 @@ Erroneous code example:
 struct Foo;
 
 impl Foo {
-    fn bar(self) {}
+    // `bar` is a method, because it has a receiver parameter.
+    fn bar(&self) {}
 
+    // `foo` is not a method, because it has no receiver parameter.
     fn foo() {
-        self.bar(); // error: `self` is not available in a static method.
+        self.bar(); // error: `self` value is a keyword only available in
+                    //        methods with a `self` parameter
     }
 }
 ```
 
-Please check if the method's argument list should have contained `self`,
-`&self`, or `&mut self` (in case you didn't want to create a static
-method), and add it if so. Example:
+The `self` keyword can only be used inside methods, which are associated
+functions (functions defined inside of a `trait` or `impl` block) that have a
+`self` receiver as its first parameter, like `self`, `&self`, `&mut self` or
+`self: &mut Pin<Self>` (this last one is an example of an ["abitrary `self`
+type"](https://github.com/rust-lang/rust/issues/44874)).
+
+Check if the associated function's parameter list should have contained a `self`
+receiver for it to be a method, and add it if so. Example:
 
 ```
 struct Foo;
 
 impl Foo {
-    fn bar(self) {}
+    fn bar(&self) {}
 
-    fn foo(self) {
+    fn foo(self) { // `foo` is now a method.
         self.bar(); // ok!
     }
 }
@@ -1611,6 +1620,183 @@ fn print_on_failure(state: &State) {
 ```
 "##,
 
+E0573: r##"
+Something other than a type has been used when one was expected.
+
+Erroneous code examples:
+
+```compile_fail,E0573
+enum Dragon {
+    Born,
+}
+
+fn oblivion() -> Dragon::Born { // error!
+    Dragon::Born
+}
+
+const HOBBIT: u32 = 2;
+impl HOBBIT {} // error!
+
+enum Wizard {
+    Gandalf,
+    Saruman,
+}
+
+trait Isengard {
+    fn wizard(_: Wizard::Saruman); // error!
+}
+```
+
+In all these errors, a type was expected. For example, in the first error, if
+we want to return the `Born` variant from the `Dragon` enum, we must set the
+function to return the enum and not its variant:
+
+```
+enum Dragon {
+    Born,
+}
+
+fn oblivion() -> Dragon { // ok!
+    Dragon::Born
+}
+```
+
+In the second error, you can't implement something on an item, only on types.
+We would need to create a new type if we wanted to do something similar:
+
+```
+struct Hobbit(u32); // we create a new type
+
+const HOBBIT: Hobbit = Hobbit(2);
+impl Hobbit {} // ok!
+```
+
+In the third case, we tried to only expect one variant of the `Wizard` enum,
+which is not possible. To make this work, we need to using pattern matching
+over the `Wizard` enum:
+
+```
+enum Wizard {
+    Gandalf,
+    Saruman,
+}
+
+trait Isengard {
+    fn wizard(w: Wizard) { // ok!
+        match w {
+            Wizard::Saruman => {
+                // do something
+            }
+            _ => {} // ignore everything else
+        }
+    }
+}
+```
+"##,
+
+E0574: r##"
+Something other than a struct, variant or union has been used when one was
+expected.
+
+Erroneous code example:
+
+```compile_fail,E0574
+mod Mordor {}
+
+let sauron = Mordor { x: () }; // error!
+
+enum Jak {
+    Daxter { i: isize },
+}
+
+let eco = Jak::Daxter { i: 1 };
+match eco {
+    Jak { i } => {} // error!
+}
+```
+
+In all these errors, a type was expected. For example, in the first error,
+we tried to instantiate the `Mordor` module, which is impossible. If you want
+to instantiate a type inside a module, you can do it as follow:
+
+```
+mod Mordor {
+    pub struct TheRing {
+        pub x: usize,
+    }
+}
+
+let sauron = Mordor::TheRing { x: 1 }; // ok!
+```
+
+In the second error, we tried to bind the `Jak` enum directly, which is not
+possible: you can only bind one of its variants. To do so:
+
+```
+enum Jak {
+    Daxter { i: isize },
+}
+
+let eco = Jak::Daxter { i: 1 };
+match eco {
+    Jak::Daxter { i } => {} // ok!
+}
+```
+"##,
+
+E0575: r##"
+Something other than a type or an associated type was given.
+
+Erroneous code example:
+
+```compile_fail,E0575
+enum Rick { Morty }
+
+let _: <u8 as Rick>::Morty; // error!
+
+trait Age {
+    type Empire;
+    fn Mythology() {}
+}
+
+impl Age for u8 {
+    type Empire = u16;
+}
+
+let _: <u8 as Age>::Mythology; // error!
+```
+
+In both cases, we're declaring a variable (called `_`) and we're giving it a
+type. However, `<u8 as Rick>::Morty` and `<u8 as Age>::Mythology` aren't types,
+therefore the compiler throws an error.
+
+`<u8 as Rick>::Morty` is an enum variant, you cannot use a variant as a type,
+you have to use the enum directly:
+
+```
+enum Rick { Morty }
+
+let _: Rick; // ok!
+```
+
+`<u8 as Age>::Mythology` is a trait method, which is definitely not a type.
+However, the `Age` trait provides an associated type `Empire` which can be
+used as a type:
+
+```
+trait Age {
+    type Empire;
+    fn Mythology() {}
+}
+
+impl Age for u8 {
+    type Empire = u16;
+}
+
+let _: <u8 as Age>::Empire; // ok!
+```
+"##,
+
 E0603: r##"
 A private item was used outside its scope.
 
@@ -1738,9 +1924,6 @@ struct Foo<X = Box<Self>> {
 //  E0427, merged into 530
 //  E0467, removed
 //  E0470, removed
-    E0573,
-    E0574,
-    E0575,
     E0576,
     E0577,
     E0578,
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index bb9f895c5f3..73a282b1a0e 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -345,6 +345,9 @@ struct LateResolutionVisitor<'a, 'b> {
     /// The current self item if inside an ADT (used for better errors).
     current_self_item: Option<NodeId>,
 
+    /// The current enclosing funciton (used for better errors).
+    current_function: Option<Span>,
+
     /// A list of labels as of yet unused. Labels will be removed from this map when
     /// they are used (in a `break` or `continue` statement)
     unused_labels: FxHashMap<NodeId, Span>,
@@ -415,7 +418,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
             }
         }
     }
-    fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) {
+    fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, sp: Span, _: NodeId) {
+        let previous_value = replace(&mut self.current_function, Some(sp));
         debug!("(resolving function) entering function");
         let rib_kind = match fn_kind {
             FnKind::ItemFn(..) => FnItemRibKind,
@@ -441,6 +445,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
                 debug!("(resolving function) leaving function");
             })
         });
+        self.current_function = previous_value;
     }
 
     fn visit_generics(&mut self, generics: &'tcx Generics) {
@@ -546,6 +551,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
             current_trait_assoc_types: Vec::new(),
             current_self_type: None,
             current_self_item: None,
+            current_function: None,
             unused_labels: Default::default(),
             current_type_ascription: Vec::new(),
         }
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index ace9903a835..2721df4c687 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -13,7 +13,7 @@ use rustc::hir::PrimTy;
 use rustc::session::config::nightly_options;
 use rustc::util::nodemap::FxHashSet;
 use syntax::ast::{self, Expr, ExprKind, Ident, NodeId, Path, Ty, TyKind};
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::symbol::kw;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
@@ -115,8 +115,10 @@ impl<'a> LateResolutionVisitor<'a, '_> {
         if is_self_type(path, ns) {
             syntax::diagnostic_used!(E0411);
             err.code(DiagnosticId::Error("E0411".into()));
-            err.span_label(span, format!("`Self` is only available in impls, traits, \
-                                          and type definitions"));
+            err.span_label(
+                span,
+                format!("`Self` is only available in impls, traits, and type definitions"),
+            );
             return (err, Vec::new());
         }
         if is_self_value(path, ns) {
@@ -125,17 +127,16 @@ impl<'a> LateResolutionVisitor<'a, '_> {
             syntax::diagnostic_used!(E0424);
             err.code(DiagnosticId::Error("E0424".into()));
             err.span_label(span, match source {
-                PathSource::Pat => {
-                    format!("`self` value is a keyword \
-                             and may not be bound to \
-                             variables or shadowed")
-                }
-                _ => {
-                    format!("`self` value is a keyword \
-                             only available in methods \
-                             with `self` parameter")
-                }
+                PathSource::Pat => format!(
+                    "`self` value is a keyword and may not be bound to variables or shadowed",
+                ),
+                _ => format!(
+                    "`self` value is a keyword only available in methods with a `self` parameter",
+                ),
             });
+            if let Some(span) = &self.current_function {
+                err.span_label(*span, "this function doesn't have a `self` parameter");
+            }
             return (err, Vec::new());
         }
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e0ff1539009..17d8f0f211a 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -26,7 +26,7 @@ use rustc::session::Session;
 use rustc::lint;
 use rustc::hir::def::{self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap};
 use rustc::hir::def::Namespace::*;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
+use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
 use rustc::hir::{TraitMap, GlobMap};
 use rustc::ty::{self, DefIdTree};
 use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
@@ -35,17 +35,16 @@ use rustc::span_bug;
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::CStore;
 
-use syntax::ext::hygiene::{ExpnId, Transparency, SyntaxContext};
+use syntax_expand::hygiene::{ExpnId, Transparency, SyntaxContext};
+use syntax_expand::base::{SyntaxExtension, MacroKind, SpecialDerives};
+use syntax::{struct_span_err, unwrap_or};
+use syntax::attr;
 use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
-use syntax::ext::base::{SyntaxExtension, MacroKind, SpecialDerives};
+use syntax::ast::{ItemKind, Path, CRATE_NODE_ID, Crate};
+use syntax::print::pprust;
 use syntax::symbol::{kw, sym};
-
-use syntax::visit::{self, Visitor};
-use syntax::attr;
-use syntax::ast::{CRATE_NODE_ID, Crate};
-use syntax::ast::{ItemKind, Path};
-use syntax::{struct_span_err, unwrap_or};
 use syntax::source_map::Spanned;
+use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
 use errors::{Applicability, DiagnosticBuilder};
@@ -431,7 +430,22 @@ impl ModuleKind {
     }
 }
 
-type Resolutions<'a> = RefCell<FxIndexMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>;
+/// A key that identifies a binding in a given `Module`.
+///
+/// Multiple bindings in the same module can have the same key (in a valid
+/// program) if all but one of them come from glob imports.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+struct BindingKey {
+    /// The identifier for the binding, aways the `modern` version of the
+    /// identifier.
+    ident: Ident,
+    ns: Namespace,
+    /// 0 if ident is not `_`, otherwise a value that's unique to the specific
+    /// `_` in the expanded AST that introduced this binding.
+    disambiguator: u32,
+}
+
+type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>;
 
 /// One node in the tree of modules.
 pub struct ModuleData<'a> {
@@ -491,8 +505,8 @@ impl<'a> ModuleData<'a> {
     fn for_each_child<R, F>(&'a self, resolver: &mut R, mut f: F)
         where R: AsMut<Resolver<'a>>, F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>)
     {
-        for (&(ident, ns), name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
-            name_resolution.borrow().binding.map(|binding| f(resolver, ident, ns, binding));
+        for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
+            name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding));
         }
     }
 
@@ -854,6 +868,8 @@ pub struct Resolver<'a> {
     /// Resolutions for labels (node IDs of their corresponding blocks or loops).
     label_res_map: NodeMap<NodeId>,
 
+    /// `CrateNum` resolutions of `extern crate` items.
+    pub extern_crate_map: NodeMap<CrateNum>,
     pub export_map: ExportMap<NodeId>,
     pub trait_map: TraitMap,
 
@@ -877,8 +893,9 @@ pub struct Resolver<'a> {
     /// language items.
     empty_module: Module<'a>,
     module_map: FxHashMap<DefId, Module<'a>>,
-    extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
+    extern_module_map: FxHashMap<DefId, Module<'a>>,
     binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
+    underscore_disambiguator: u32,
 
     /// Maps glob imports to the names of items actually imported.
     pub glob_map: GlobMap,
@@ -899,7 +916,7 @@ pub struct Resolver<'a> {
     arenas: &'a ResolverArenas<'a>,
     dummy_binding: &'a NameBinding<'a>,
 
-    crate_loader: &'a mut CrateLoader<'a>,
+    crate_loader: &'a CrateLoader<'a>,
     macro_names: FxHashSet<Ident>,
     builtin_macros: FxHashMap<Name, SyntaxExtension>,
     macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
@@ -1069,7 +1086,7 @@ impl<'a> Resolver<'a> {
                cstore: &'a CStore,
                krate: &Crate,
                crate_name: &str,
-               crate_loader: &'a mut CrateLoader<'a>,
+               crate_loader: &'a CrateLoader<'a>,
                arenas: &'a ResolverArenas<'a>)
                -> Resolver<'a> {
         let root_def_id = DefId::local(CRATE_DEF_INDEX);
@@ -1154,8 +1171,10 @@ impl<'a> Resolver<'a> {
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
             label_res_map: Default::default(),
+            extern_crate_map: Default::default(),
             export_map: FxHashMap::default(),
             trait_map: Default::default(),
+            underscore_disambiguator: 0,
             empty_module,
             module_map,
             block_map: Default::default(),
@@ -1280,6 +1299,17 @@ impl<'a> Resolver<'a> {
         self.arenas.alloc_module(module)
     }
 
+    fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
+        let ident = ident.modern();
+        let disambiguator = if ident.name == kw::Underscore {
+            self.underscore_disambiguator += 1;
+            self.underscore_disambiguator
+        } else {
+            0
+        };
+        BindingKey { ident, ns, disambiguator }
+    }
+
     fn resolutions(&mut self, module: Module<'a>) -> &'a Resolutions<'a> {
         if module.populate_on_access.get() {
             module.populate_on_access.set(false);
@@ -1288,9 +1318,9 @@ impl<'a> Resolver<'a> {
         &module.lazy_resolutions
     }
 
-    fn resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace)
+    fn resolution(&mut self, module: Module<'a>, key: BindingKey)
                   -> &'a RefCell<NameResolution<'a>> {
-        *self.resolutions(module).borrow_mut().entry((ident.modern(), ns))
+        *self.resolutions(module).borrow_mut().entry(key)
                .or_insert_with(|| self.arenas.alloc_name_resolution())
     }
 
@@ -2011,13 +2041,13 @@ impl<'a> Resolver<'a> {
                         let mut candidates =
                             self.lookup_import_candidates(ident, TypeNS, is_mod);
                         candidates.sort_by_cached_key(|c| {
-                            (c.path.segments.len(), c.path.to_string())
+                            (c.path.segments.len(), pprust::path_to_string(&c.path))
                         });
                         if let Some(candidate) = candidates.get(0) {
                             (
                                 String::from("unresolved import"),
                                 Some((
-                                    vec![(ident.span, candidate.path.to_string())],
+                                    vec![(ident.span, pprust::path_to_string(&candidate.path))],
                                     String::from("a similar path exists"),
                                     Applicability::MaybeIncorrect,
                                 )),
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 2b87bba8386..94fe0cc5740 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -14,13 +14,14 @@ use rustc::{ty, lint, span_bug};
 use syntax::ast::{self, NodeId, Ident};
 use syntax::attr::StabilityLevel;
 use syntax::edition::Edition;
-use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives};
-use syntax::ext::base::{MacroKind, SyntaxExtension};
-use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
-use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind};
-use syntax::ext::compile_declarative_macro;
+use syntax_expand::base::{self, InvocationRes, Indeterminate, SpecialDerives};
+use syntax_expand::base::{MacroKind, SyntaxExtension};
+use syntax_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
+use syntax_expand::hygiene::{self, ExpnId, ExpnData, ExpnKind};
+use syntax_expand::compile_declarative_macro;
 use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
 use syntax::feature_gate::GateIssue;
+use syntax::print::pprust;
 use syntax::symbol::{Symbol, kw, sym};
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -107,15 +108,11 @@ impl<'a> base::Resolver for Resolver<'a> {
         });
     }
 
-    // FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
-    fn visit_ast_fragment_with_placeholders(
-        &mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
-    ) {
+    fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) {
         // Integrate the new AST fragment into all the definition and module structures.
         // We are inside the `expansion` now, but other parent scope components are still the same.
         let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
-        let output_legacy_scope =
-            self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
+        let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope);
         self.output_legacy_scopes.insert(expansion, output_legacy_scope);
 
         parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
@@ -324,7 +321,8 @@ impl<'a> Resolver<'a> {
 
         Ok(if ext.macro_kind() != kind {
             let expected = kind.descr_expected();
-            let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path);
+            let path_str = pprust::path_to_string(path);
+            let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str);
             self.session.struct_span_err(path.span, &msg)
                         .span_label(path.span, format!("not {} {}", kind.article(), expected))
                         .emit();
@@ -805,14 +803,16 @@ impl<'a> Resolver<'a> {
                 }
             }
             if let Some(depr) = &stability.rustc_depr {
-                let (message, lint) = stability::rustc_deprecation_message(depr, &path.to_string());
+                let path = pprust::path_to_string(path);
+                let (message, lint) = stability::rustc_deprecation_message(depr, &path);
                 stability::early_report_deprecation(
                     self.session, &message, depr.suggestion, lint, span
                 );
             }
         }
         if let Some(depr) = &ext.deprecation {
-            let (message, lint) = stability::deprecation_message(depr, &path.to_string());
+            let path = pprust::path_to_string(&path);
+            let (message, lint) = stability::deprecation_message(depr, &path);
             stability::early_report_deprecation(self.session, &message, None, lint, span);
         }
     }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 360343169bc..34edd5eaf4f 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -7,7 +7,7 @@ use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, ParentScope
 use crate::Determinacy::{self, *};
 use crate::Namespace::{self, TypeNS, MacroNS};
 use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
-use crate::{Resolver, ResolutionError, Segment, ModuleKind};
+use crate::{Resolver, ResolutionError, BindingKey, Segment, ModuleKind};
 use crate::{names_to_string, module_to_string};
 use crate::diagnostics::Suggestion;
 
@@ -28,7 +28,7 @@ use rustc::util::nodemap::FxHashSet;
 use rustc::{bug, span_bug};
 
 use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
-use syntax::ext::hygiene::ExpnId;
+use syntax_expand::hygiene::ExpnId;
 use syntax::symbol::kw;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::{struct_span_err, unwrap_or};
@@ -235,7 +235,8 @@ impl<'a> Resolver<'a> {
             }
         };
 
-        let resolution = self.resolution(module, ident, ns)
+        let key = self.new_key(ident, ns);
+        let resolution = self.resolution(module, key)
             .try_borrow_mut()
             .map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
 
@@ -447,17 +448,16 @@ impl<'a> Resolver<'a> {
     }
 
     // Define the name or return the existing binding if there is a collision.
-    pub fn try_define(
+    crate fn try_define(
         &mut self,
         module: Module<'a>,
-        ident: Ident,
-        ns: Namespace,
+        key: BindingKey,
         binding: &'a NameBinding<'a>,
     ) -> Result<(), &'a NameBinding<'a>> {
         let res = binding.res();
-        self.check_reserved_macro_name(ident, res);
+        self.check_reserved_macro_name(key.ident, res);
         self.set_binding_parent_module(binding, module);
-        self.update_resolution(module, ident, ns, |this, resolution| {
+        self.update_resolution(module, key, |this, resolution| {
             if let Some(old_binding) = resolution.binding {
                 if res == Res::Err {
                     // Do not override real bindings with `Res::Err`s from error recovery.
@@ -479,8 +479,9 @@ impl<'a> Resolver<'a> {
                         } else {
                             (binding, old_binding)
                         };
-                        if glob_binding.res() != nonglob_binding.res() &&
-                           ns == MacroNS && nonglob_binding.expansion != ExpnId::root() {
+                        if glob_binding.res() != nonglob_binding.res()
+                            && key.ns == MacroNS && nonglob_binding.expansion != ExpnId::root()
+                        {
                             resolution.binding = Some(this.ambiguity(
                                 AmbiguityKind::GlobVsExpanded,
                                 nonglob_binding,
@@ -499,9 +500,9 @@ impl<'a> Resolver<'a> {
                                 DUPLICATE_MACRO_EXPORTS,
                                 CRATE_NODE_ID,
                                 binding.span,
-                                &format!("a macro named `{}` has already been exported", ident),
+                                &format!("a macro named `{}` has already been exported", key.ident),
                                 BuiltinLintDiagnostics::DuplicatedMacroExports(
-                                    ident, old_binding.span, binding.span));
+                                    key.ident, old_binding.span, binding.span));
 
                             resolution.binding = Some(binding);
                         } else {
@@ -531,9 +532,9 @@ impl<'a> Resolver<'a> {
     // Use `f` to mutate the resolution of the name in the module.
     // If the resolution becomes a success, define it in the module's glob importers.
     fn update_resolution<T, F>(
-        &mut self, module: Module<'a>,
-        ident: Ident,
-        ns: Namespace,
+        &mut self,
+        module: Module<'a>,
+        key: BindingKey,
         f: F,
     ) -> T
         where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
@@ -541,7 +542,7 @@ impl<'a> Resolver<'a> {
         // Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
         // during which the resolution might end up getting re-defined via a glob cycle.
         let (binding, t) = {
-            let resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
+            let resolution = &mut *self.resolution(module, key).borrow_mut();
             let old_binding = resolution.binding();
 
             let t = f(self, resolution);
@@ -558,7 +559,7 @@ impl<'a> Resolver<'a> {
 
         // Define `binding` in `module`s glob importers.
         for directive in module.glob_importers.borrow_mut().iter() {
-            let mut ident = ident.modern();
+            let mut ident = key.ident;
             let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
                 Some(Some(def)) => self.macro_def_scope(def),
                 Some(None) => directive.parent_scope.module,
@@ -566,7 +567,8 @@ impl<'a> Resolver<'a> {
             };
             if self.is_accessible_from(binding.vis, scope) {
                 let imported_binding = self.import(binding, directive);
-                let _ = self.try_define(directive.parent_scope.module, ident, ns, imported_binding);
+                let key = BindingKey { ident, ..key };
+                let _ = self.try_define(directive.parent_scope.module, key, imported_binding);
             }
         }
 
@@ -580,7 +582,8 @@ impl<'a> Resolver<'a> {
             let dummy_binding = self.dummy_binding;
             let dummy_binding = self.import(dummy_binding, directive);
             self.per_ns(|this, ns| {
-                let _ = this.try_define(directive.parent_scope.module, target, ns, dummy_binding);
+                let key = this.new_key(target, ns);
+                let _ = this.try_define(directive.parent_scope.module, key, dummy_binding);
                 // Consider erroneous imports used to avoid duplicate diagnostics.
                 this.record_use(target, ns, dummy_binding, false);
             });
@@ -670,13 +673,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     self.throw_unresolved_import_error(errors, None);
                     errors = vec![];
                 }
-                if !seen_spans.contains(&err.span) {
+                if seen_spans.insert(err.span) {
                     let path = import_path_to_string(
                         &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
                         &import.subclass,
                         err.span,
                     );
-                    seen_spans.insert(err.span);
                     errors.push((path, err));
                     prev_root_id = import.root_id;
                 }
@@ -820,8 +822,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             let parent = directive.parent_scope.module;
             match source_bindings[ns].get() {
                 Err(Undetermined) => indeterminate = true,
+                // Don't update the resolution, because it was never added.
+                Err(Determined) if target.name == kw::Underscore => {}
                 Err(Determined) => {
-                    this.update_resolution(parent, target, ns, |_, resolution| {
+                    let key = this.new_key(target, ns);
+                    this.update_resolution(parent, key, |_, resolution| {
                         resolution.single_imports.remove(&PtrKey(directive));
                     });
                 }
@@ -1052,7 +1057,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     _ => None,
                 };
                 let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
-                let names = resolutions.filter_map(|(&(ref i, _), resolution)| {
+                let names = resolutions.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
                     if *i == ident { return None; } // Never suggest the same name
                     match *resolution.borrow() {
                         NameResolution { binding: Some(name_binding), .. } => {
@@ -1301,19 +1306,18 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         // Ensure that `resolutions` isn't borrowed during `try_define`,
         // since it might get updated via a glob cycle.
-        let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(ident, resolution)| {
-            resolution.borrow().binding().map(|binding| (*ident, binding))
+        let bindings = self.r.resolutions(module).borrow().iter().filter_map(|(key, resolution)| {
+            resolution.borrow().binding().map(|binding| (*key, binding))
         }).collect::<Vec<_>>();
-        for ((mut ident, ns), binding) in bindings {
-            let scope = match ident.span.reverse_glob_adjust(module.expansion, directive.span) {
+        for (mut key, binding) in bindings {
+            let scope = match key.ident.span.reverse_glob_adjust(module.expansion, directive.span) {
                 Some(Some(def)) => self.r.macro_def_scope(def),
                 Some(None) => directive.parent_scope.module,
                 None => continue,
             };
             if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
                 let imported_binding = self.r.import(binding, directive);
-                let _ =
-                    self.r.try_define(directive.parent_scope.module, ident, ns, imported_binding);
+                let _ = self.r.try_define(directive.parent_scope.module, key, imported_binding);
             }
         }
 
@@ -1329,29 +1333,23 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         let mut reexports = Vec::new();
 
-        for (&(ident, ns), resolution) in self.r.resolutions(module).borrow().iter() {
-            let resolution = &mut *resolution.borrow_mut();
-            let binding = match resolution.binding {
-                Some(binding) => binding,
-                None => continue,
-            };
-
+        module.for_each_child(self.r, |this, ident, ns, binding| {
             // Filter away ambiguous imports and anything that has def-site
             // hygiene.
             // FIXME: Implement actual cross-crate hygiene.
             let is_good_import = binding.is_import() && !binding.is_ambiguity()
-                && !ident.span.modern().from_expansion();
+                && !ident.span.from_expansion();
             if is_good_import || binding.is_macro_def() {
                 let res = binding.res();
                 if res != Res::Err {
                     if let Some(def_id) = res.opt_def_id() {
                         if !def_id.is_local() {
-                            self.r.cstore.export_macros_untracked(def_id.krate);
+                            this.cstore.export_macros_untracked(def_id.krate);
                         }
                     }
                     reexports.push(Export {
-                        ident: ident.modern(),
-                        res: res,
+                        ident,
+                        res,
                         span: binding.span,
                         vis: binding.vis,
                     });
@@ -1360,7 +1358,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
             if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
                 if ns == TypeNS && orig_binding.is_variant() &&
-                    !orig_binding.vis.is_at_least(binding.vis, &*self) {
+                    !orig_binding.vis.is_at_least(binding.vis, &*this) {
                         let msg = match directive.subclass {
                             ImportDirectiveSubclass::SingleImport { .. } => {
                                 format!("variant `{}` is private and cannot be re-exported",
@@ -1372,33 +1370,34 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                 let error_id = (DiagnosticMessageId::ErrorId(0), // no code?!
                                                 Some(binding.span),
                                                 msg.clone());
-                                let fresh = self.r.session.one_time_diagnostics
+                                let fresh = this.session.one_time_diagnostics
                                     .borrow_mut().insert(error_id);
                                 if !fresh {
-                                    continue;
+                                    return;
                                 }
                                 msg
                             },
                             ref s @ _ => bug!("unexpected import subclass {:?}", s)
                         };
-                        let mut err = self.r.session.struct_span_err(binding.span, &msg);
+                        let mut err = this.session.struct_span_err(binding.span, &msg);
 
                         let imported_module = match directive.imported_module.get() {
                             Some(ModuleOrUniformRoot::Module(module)) => module,
                             _ => bug!("module should exist"),
                         };
                         let parent_module = imported_module.parent.expect("parent should exist");
-                        let resolutions = self.r.resolutions(parent_module).borrow();
+                        let resolutions = this.resolutions(parent_module).borrow();
                         let enum_path_segment_index = directive.module_path.len() - 1;
                         let enum_ident = directive.module_path[enum_path_segment_index].ident;
 
-                        let enum_resolution = resolutions.get(&(enum_ident, TypeNS))
+                        let key = this.new_key(enum_ident, TypeNS);
+                        let enum_resolution = resolutions.get(&key)
                             .expect("resolution should exist");
                         let enum_span = enum_resolution.borrow()
                             .binding.expect("binding should exist")
                             .span;
-                        let enum_def_span = self.r.session.source_map().def_span(enum_span);
-                        let enum_def_snippet = self.r.session.source_map()
+                        let enum_def_span = this.session.source_map().def_span(enum_span);
+                        let enum_def_snippet = this.session.source_map()
                             .span_to_snippet(enum_def_span).expect("snippet should exist");
                         // potentially need to strip extant `crate`/`pub(path)` for suggestion
                         let after_vis_index = enum_def_snippet.find("enum")
@@ -1406,7 +1405,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         let suggestion = format!("pub {}",
                                                  &enum_def_snippet[after_vis_index..]);
 
-                        self.r.session
+                        this.session
                             .diag_span_suggestion_once(&mut err,
                                                        DiagnosticMessageId::ErrorId(0),
                                                        enum_def_span,
@@ -1415,7 +1414,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         err.emit();
                 }
             }
-        }
+        });
 
         if reexports.len() > 0 {
             if let Some(def_id) = module.def_id() {
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index edd2db3c8f7..e282936b5d9 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -115,15 +115,17 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         F: FnOnce(&mut Self),
     {
         let item_def_id = self.tcx.hir().local_def_id_from_node_id(item_id);
-        if self.tcx.has_typeck_tables(item_def_id) {
-            let tables = self.tcx.typeck_tables_of(item_def_id);
-            let old_tables = self.save_ctxt.tables;
-            self.save_ctxt.tables = tables;
-            f(self);
-            self.save_ctxt.tables = old_tables;
+
+        let tables = if self.tcx.has_typeck_tables(item_def_id) {
+            self.tcx.typeck_tables_of(item_def_id)
         } else {
-            f(self);
-        }
+            self.save_ctxt.empty_tables
+        };
+
+        let old_tables = self.save_ctxt.tables;
+        self.save_ctxt.tables = tables;
+        f(self);
+        self.save_ctxt.tables = old_tables;
     }
 
     fn span_from_span(&self, span: Span) -> SpanData {
@@ -530,12 +532,14 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
             );
         }
 
-        for field in def.fields() {
-            self.process_struct_field_def(field, item.id);
-            self.visit_ty(&field.ty);
-        }
+        self.nest_tables(item.id, |v| {
+            for field in def.fields() {
+                v.process_struct_field_def(field, item.id);
+                v.visit_ty(&field.ty);
+            }
 
-        self.process_generic_params(ty_params, &qualname, item.id);
+            v.process_generic_params(ty_params, &qualname, item.id);
+        });
     }
 
     fn process_enum(
@@ -665,15 +669,18 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 }
             }
         }
-        self.visit_ty(&typ);
-        if let &Some(ref trait_ref) = trait_ref {
-            self.process_path(trait_ref.ref_id, &trait_ref.path);
-        }
-        self.process_generic_params(generics, "", item.id);
-        for impl_item in impl_items {
-            let map = &self.tcx.hir();
-            self.process_impl_item(impl_item, map.local_def_id_from_node_id(item.id));
-        }
+
+        let map = &self.tcx.hir();
+        self.nest_tables(item.id, |v| {
+            v.visit_ty(&typ);
+            if let &Some(ref trait_ref) = trait_ref {
+                v.process_path(trait_ref.ref_id, &trait_ref.path);
+            }
+            v.process_generic_params(generics, "", item.id);
+            for impl_item in impl_items {
+                v.process_impl_item(impl_item, map.local_def_id_from_node_id(item.id));
+            }
+        });
     }
 
     fn process_trait(
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 70b508d4786..1cfb84bb511 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -48,6 +48,9 @@ use log::{debug, error, info};
 pub struct SaveContext<'l, 'tcx> {
     tcx: TyCtxt<'tcx>,
     tables: &'l ty::TypeckTables<'tcx>,
+    /// Used as a fallback when nesting the typeck tables during item processing
+    /// (if these are not available for that item, e.g. don't own a body)
+    empty_tables: &'l ty::TypeckTables<'tcx>,
     access_levels: &'l AccessLevels,
     span_utils: SpanUtils<'tcx>,
     config: Config,
@@ -1114,6 +1117,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
         let save_ctxt = SaveContext {
             tcx,
             tables: &ty::TypeckTables::empty(None),
+            empty_tables: &ty::TypeckTables::empty(None),
             access_levels: &access_levels,
             span_utils: SpanUtils::new(&tcx.sess),
             config: find_config(config),
diff --git a/src/librustc_target/abi/call/asmjs.rs b/src/librustc_target/abi/call/asmjs.rs
deleted file mode 100644
index 92c86372a86..00000000000
--- a/src/librustc_target/abi/call/asmjs.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use crate::abi::call::{FnType, ArgType, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
-
-// Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128
-
-// See the https://github.com/kripken/emscripten-fastcomp-clang repository.
-// The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
-
-fn classify_ret_ty<'a, Ty, C>(cx: &C, ret: &mut ArgType<'a, Ty>)
-    where Ty: TyLayoutMethods<'a, C> + Copy,
-          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
-{
-    if ret.layout.is_aggregate() {
-        if let Some(unit) = ret.layout.homogeneous_aggregate(cx).unit() {
-            let size = ret.layout.size;
-            if unit.size == size {
-                ret.cast_to(Uniform {
-                    unit,
-                    total: size
-                });
-                return;
-            }
-        }
-
-        ret.make_indirect();
-    }
-}
-
-fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>) {
-    if arg.layout.is_aggregate() {
-        arg.make_indirect_byval();
-    }
-}
-
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>)
-    where Ty: TyLayoutMethods<'a, C> + Copy,
-          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
-{
-    if !fty.ret.is_ignore() {
-        classify_ret_ty(cx, &mut fty.ret);
-    }
-
-    for arg in &mut fty.args {
-        if arg.is_ignore() { continue; }
-        classify_arg_ty(arg);
-    }
-}
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs
index bc21113527e..17bad189bcf 100644
--- a/src/librustc_target/abi/call/mod.rs
+++ b/src/librustc_target/abi/call/mod.rs
@@ -5,7 +5,6 @@ use crate::spec::{self, HasTargetSpec};
 mod aarch64;
 mod amdgpu;
 mod arm;
-mod asmjs;
 mod hexagon;
 mod mips;
 mod mips64;
@@ -22,6 +21,7 @@ mod x86;
 mod x86_64;
 mod x86_win64;
 mod wasm32;
+mod wasm32_bindgen_compat;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum PassMode {
@@ -557,14 +557,6 @@ impl<'a, Ty> FnType<'a, Ty> {
             "powerpc" => powerpc::compute_abi_info(cx, self),
             "powerpc64" => powerpc64::compute_abi_info(cx, self),
             "s390x" => s390x::compute_abi_info(cx, self),
-            "asmjs" => asmjs::compute_abi_info(cx, self),
-            "wasm32" => {
-                if cx.target_spec().llvm_target.contains("emscripten") {
-                    asmjs::compute_abi_info(cx, self)
-                } else {
-                    wasm32::compute_abi_info(self)
-                }
-            }
             "msp430" => msp430::compute_abi_info(self),
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
@@ -573,6 +565,9 @@ impl<'a, Ty> FnType<'a, Ty> {
             "hexagon" => hexagon::compute_abi_info(self),
             "riscv32" => riscv::compute_abi_info(self, 32),
             "riscv64" => riscv::compute_abi_info(self, 64),
+            "wasm32" if cx.target_spec().target_os != "emscripten"
+                => wasm32_bindgen_compat::compute_abi_info(self),
+            "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
             a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
         }
 
diff --git a/src/librustc_target/abi/call/wasm32.rs b/src/librustc_target/abi/call/wasm32.rs
index 1fdcbb8e39b..27799edab91 100644
--- a/src/librustc_target/abi/call/wasm32.rs
+++ b/src/librustc_target/abi/call/wasm32.rs
@@ -1,20 +1,60 @@
-use crate::abi::call::{FnType, ArgType};
+use crate::abi::call::{FnType, ArgType, Uniform};
+use crate::abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods};
 
-fn classify_ret_ty<Ty>(ret: &mut ArgType<'_, Ty>) {
+fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgType<'a, Ty>) -> bool
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
+    if val.layout.is_aggregate() {
+        if let Some(unit) = val.layout.homogeneous_aggregate(cx).unit() {
+            let size = val.layout.size;
+            if unit.size == size {
+                val.cast_to(Uniform {
+                    unit,
+                    total: size
+                });
+                return true;
+            }
+        }
+    }
+    false
+}
+
+
+fn classify_ret_ty<'a, Ty, C>(cx: &C, ret: &mut ArgType<'a, Ty>)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
     ret.extend_integer_width_to(32);
+    if ret.layout.is_aggregate() {
+        if !unwrap_trivial_aggregate(cx, ret) {
+            ret.make_indirect();
+        }
+    }
 }
 
-fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>) {
+fn classify_arg_ty<'a, Ty, C>(cx: &C, arg: &mut ArgType<'a, Ty>)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
     arg.extend_integer_width_to(32);
+    if arg.layout.is_aggregate() {
+        if !unwrap_trivial_aggregate(cx, arg) {
+            arg.make_indirect_byval();
+        }
+    }
 }
 
-pub fn compute_abi_info<Ty>(fty: &mut FnType<'_, Ty>) {
+pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>)
+    where Ty: TyLayoutMethods<'a, C> + Copy,
+          C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout
+{
     if !fty.ret.is_ignore() {
-        classify_ret_ty(&mut fty.ret);
+        classify_ret_ty(cx, &mut fty.ret);
     }
 
     for arg in &mut fty.args {
         if arg.is_ignore() { continue; }
-        classify_arg_ty(arg);
+        classify_arg_ty(cx, arg);
     }
 }
diff --git a/src/librustc_target/abi/call/wasm32_bindgen_compat.rs b/src/librustc_target/abi/call/wasm32_bindgen_compat.rs
new file mode 100644
index 00000000000..2645e30594c
--- /dev/null
+++ b/src/librustc_target/abi/call/wasm32_bindgen_compat.rs
@@ -0,0 +1,27 @@
+// This is not and has never been a correct C ABI for WebAssembly, but
+// for a long time this was the C ABI that Rust used. wasm-bindgen
+// depends on ABI details for this ABI and is incompatible with the
+// correct C ABI, so this ABI is being kept around until wasm-bindgen
+// can be fixed to work with the correct ABI. See #63649 for further
+// discussion.
+
+use crate::abi::call::{FnType, ArgType};
+
+fn classify_ret_ty<Ty>(ret: &mut ArgType<'_, Ty>) {
+    ret.extend_integer_width_to(32);
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<'_, Ty>) {
+    arg.extend_integer_width_to(32);
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<'_, Ty>) {
+    if !fty.ret.is_ignore() {
+        classify_ret_ty(&mut fty.ret);
+    }
+
+    for arg in &mut fty.args {
+        if arg.is_ignore() { continue; }
+        classify_arg_ty(arg);
+    }
+}
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 26d37f196be..fde5c5bed4d 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -738,7 +738,11 @@ impl FieldPlacement {
 
     pub fn offset(&self, i: usize) -> Size {
         match *self {
-            FieldPlacement::Union(_) => Size::ZERO,
+            FieldPlacement::Union(count) => {
+                assert!(i < count,
+                        "Tried to access field {} of union with {} fields", i, count);
+                Size::ZERO
+            },
             FieldPlacement::Array { stride, count } => {
                 let i = i as u64;
                 assert!(i < count);
diff --git a/src/librustc_target/spec/asmjs_unknown_emscripten.rs b/src/librustc_target/spec/asmjs_unknown_emscripten.rs
index 6dc140cf160..e8f9c1f3d61 100644
--- a/src/librustc_target/spec/asmjs_unknown_emscripten.rs
+++ b/src/librustc_target/spec/asmjs_unknown_emscripten.rs
@@ -1,40 +1,10 @@
-use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
+use super::{LinkerFlavor, Target, wasm32_unknown_emscripten};
 
 pub fn target() -> Result<Target, String> {
-    let mut args = LinkArgs::new();
-    args.insert(LinkerFlavor::Em,
-                vec!["-s".to_string(),
-                     "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
-                     "-s".to_string(),
-                     "ABORTING_MALLOC=0".to_string(),
-                     "-s".to_string(),
-                     "WASM=0".to_string()]);
-
-    let opts = TargetOptions {
-        dynamic_linking: false,
-        executables: true,
-        exe_suffix: ".js".to_string(),
-        linker_is_gnu: true,
-        allow_asm: false,
-        obj_is_bitcode: true,
-        is_like_emscripten: true,
-        max_atomic_width: Some(32),
-        post_link_args: args,
-        target_family: Some("unix".to_string()),
-        codegen_backend: "emscripten".to_string(),
-        .. Default::default()
-    };
-    Ok(Target {
-        llvm_target: "asmjs-unknown-emscripten".to_string(),
-        target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
-        target_c_int_width: "32".to_string(),
-        target_os: "emscripten".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
-        arch: "asmjs".to_string(),
-        linker_flavor: LinkerFlavor::Em,
-        options: opts,
-    })
+    let mut target = wasm32_unknown_emscripten::target()?;
+    target.options.post_link_args
+        .entry(LinkerFlavor::Em)
+        .or_default()
+        .extend(vec!["-s".to_string(), "WASM=0".to_string()]);
+    Ok(target)
 }
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 25add0cc6a4..d91588db183 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -71,8 +71,7 @@ mod riscv_base;
 mod wasm32_base;
 mod vxworks_base;
 
-#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
-         RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
 pub enum LinkerFlavor {
     Em,
     Gcc,
@@ -82,8 +81,7 @@ pub enum LinkerFlavor {
     PtxLinker,
 }
 
-#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
-         RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
 pub enum LldFlavor {
     Wasm,
     Ld64,
@@ -462,7 +460,6 @@ supported_targets! {
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-unknown-unknown", wasm32_unknown_unknown),
     ("wasm32-wasi", wasm32_wasi),
-    ("wasm32-experimental-emscripten", wasm32_experimental_emscripten),
 
     ("thumbv6m-none-eabi", thumbv6m_none_eabi),
     ("thumbv7m-none-eabi", thumbv7m_none_eabi),
@@ -692,6 +689,9 @@ pub struct TargetOptions {
     /// defined in libgcc. If this option is enabled, the target must provide
     /// `eh_unwind_resume` lang item.
     pub custom_unwind_resume: bool,
+    /// Whether the runtime startup code requires the `main` function be passed
+    /// `argc` and `argv` values.
+    pub main_needs_argc_argv: bool,
 
     /// Flag indicating whether ELF TLS (e.g., #[thread_local]) is available for
     /// this target.
@@ -850,6 +850,7 @@ impl Default for TargetOptions {
             link_env_remove: Vec::new(),
             archive_format: "gnu".to_string(),
             custom_unwind_resume: false,
+            main_needs_argc_argv: true,
             allow_asm: true,
             has_elf_tls: false,
             obj_is_bitcode: false,
@@ -1160,6 +1161,7 @@ impl Target {
         key!(archive_format);
         key!(allow_asm, bool);
         key!(custom_unwind_resume, bool);
+        key!(main_needs_argc_argv, bool);
         key!(has_elf_tls, bool);
         key!(obj_is_bitcode, bool);
         key!(no_integrated_as, bool);
@@ -1377,6 +1379,7 @@ impl ToJson for Target {
         target_option_val!(archive_format);
         target_option_val!(allow_asm);
         target_option_val!(custom_unwind_resume);
+        target_option_val!(main_needs_argc_argv);
         target_option_val!(has_elf_tls);
         target_option_val!(obj_is_bitcode);
         target_option_val!(no_integrated_as);
diff --git a/src/librustc_target/spec/wasm32_experimental_emscripten.rs b/src/librustc_target/spec/wasm32_experimental_emscripten.rs
deleted file mode 100644
index b802bee25ae..00000000000
--- a/src/librustc_target/spec/wasm32_experimental_emscripten.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
-
-pub fn target() -> Result<Target, String> {
-    let mut post_link_args = LinkArgs::new();
-    post_link_args.insert(LinkerFlavor::Em,
-                          vec!["-s".to_string(),
-                               "WASM=1".to_string(),
-                               "-s".to_string(),
-                               "ASSERTIONS=1".to_string(),
-                               "-s".to_string(),
-                               "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
-                               "-g3".to_string()]);
-
-    let opts = TargetOptions {
-        dynamic_linking: false,
-        executables: true,
-        // Today emcc emits two files - a .js file to bootstrap and
-        // possibly interpret the wasm, and a .wasm file
-        exe_suffix: ".js".to_string(),
-        linker_is_gnu: true,
-        link_env: vec![("EMCC_WASM_BACKEND".to_string(), "1".to_string())],
-        allow_asm: false,
-        obj_is_bitcode: true,
-        is_like_emscripten: true,
-        max_atomic_width: Some(32),
-        post_link_args,
-        limit_rdylib_exports: false,
-        target_family: Some("unix".to_string()),
-        .. Default::default()
-    };
-    Ok(Target {
-        llvm_target: "wasm32-unknown-unknown".to_string(),
-        target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
-        target_c_int_width: "32".to_string(),
-        target_os: "emscripten".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
-        arch: "wasm32".to_string(),
-        linker_flavor: LinkerFlavor::Em,
-        options: opts,
-    })
-}
diff --git a/src/librustc_target/spec/wasm32_unknown_emscripten.rs b/src/librustc_target/spec/wasm32_unknown_emscripten.rs
index e0df36884bf..6a2c8c49537 100644
--- a/src/librustc_target/spec/wasm32_unknown_emscripten.rs
+++ b/src/librustc_target/spec/wasm32_unknown_emscripten.rs
@@ -1,45 +1,46 @@
-use super::{LinkArgs, LinkerFlavor, Target, TargetOptions};
+use super::wasm32_base;
+use super::{LinkArgs, LinkerFlavor, Target, TargetOptions, PanicStrategy};
 
 pub fn target() -> Result<Target, String> {
-    // FIXME(nikic) BINARYEN_TRAP_MODE=clamp is needed to avoid trapping in our
-    // -Zsaturating-float-casts implementation. This can be dropped if/when
-    // we have native fpto[su]i.sat intrinsics, or the implementation otherwise
-    // stops relying on non-trapping fpto[su]i.
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(LinkerFlavor::Em,
                           vec!["-s".to_string(),
-                               "BINARYEN=1".to_string(),
-                               "-s".to_string(),
                                "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string(),
                                "-s".to_string(),
-                               "BINARYEN_TRAP_MODE='clamp'".to_string()]);
+                               "ASSERTIONS=1".to_string(),
+                               "-s".to_string(),
+                               "DISABLE_EXCEPTION_CATCHING=1".to_string(),
+                               "-s".to_string(),
+                               "ABORTING_MALLOC=0".to_string(),
+                               // FIXME(tlively): Enable this linker option once libc type errors
+                               // are resolved. See https://github.com/rust-lang/libc/pull/1478.
+                               // "-Wl,--fatal-warnings".to_string(),
+                               ]);
 
     let opts = TargetOptions {
-        dynamic_linking: false,
-        executables: true,
-        // Today emcc emits two files - a .js file to bootstrap and
-        // possibly interpret the wasm, and a .wasm file
+        // emcc emits two files - a .js file to instantiate the wasm and supply platform
+        // functionality, and a .wasm file.
         exe_suffix: ".js".to_string(),
+        linker: None,
         linker_is_gnu: true,
-        allow_asm: false,
-        obj_is_bitcode: true,
         is_like_emscripten: true,
-        max_atomic_width: Some(32),
+        // FIXME(tlively): Emscripten supports unwinding, but we would have to pass
+        // -enable-emscripten-cxx-exceptions to LLVM at codegen time and merge
+        // https://reviews.llvm.org/rG5c3cdef84b82464756bb571c13c31cf7773860c3to use it.
+        panic_strategy: PanicStrategy::Abort,
         post_link_args,
-        limit_rdylib_exports: false,
         target_family: Some("unix".to_string()),
-        codegen_backend: "emscripten".to_string(),
-        .. Default::default()
+        .. wasm32_base::options()
     };
     Ok(Target {
-        llvm_target: "asmjs-unknown-emscripten".to_string(),
+        llvm_target: "wasm32-unknown-emscripten".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
         target_os: "emscripten".to_string(),
         target_env: String::new(),
         target_vendor: "unknown".to_string(),
-        data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Em,
         options: opts,
diff --git a/src/librustc_target/spec/wasm32_wasi.rs b/src/librustc_target/spec/wasm32_wasi.rs
index 86978c05b15..d5ef230dcf7 100644
--- a/src/librustc_target/spec/wasm32_wasi.rs
+++ b/src/librustc_target/spec/wasm32_wasi.rs
@@ -101,6 +101,10 @@ pub fn target() -> Result<Target, String> {
     // without a main function.
     options.crt_static_allows_dylibs = true;
 
+    // WASI's `sys::args::init` function ignores its arguments; instead,
+    // `args::args()` makes the WASI API calls itself.
+    options.main_needs_argc_argv = false;
+
     Ok(Target {
         llvm_target: "wasm32-wasi".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs
index 54d580ec05d..8d136a1b65c 100644
--- a/src/librustc_traits/chalk_context/mod.rs
+++ b/src/librustc_traits/chalk_context/mod.rs
@@ -33,7 +33,7 @@ use rustc::traits::{
     InEnvironment,
     ChalkCanonicalGoal,
 };
-use rustc::ty::{self, TyCtxt, InferConst};
+use rustc::ty::{self, TyCtxt};
 use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::{GenericArg, GenericArgKind};
@@ -286,7 +286,7 @@ impl context::ContextOps<ChalkArenas<'tcx>> for ChalkContext<'tcx> {
                     _ => false,
                 },
                 GenericArgKind::Const(ct) => match ct.val {
-                    ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)) => {
+                    ConstValue::Bound(debruijn, bound_ct) => {
                         debug_assert_eq!(debruijn, ty::INNERMOST);
                         cvar == bound_ct
                     }
diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs
index 8facec1e9e3..49d76681196 100644
--- a/src/librustc_traits/chalk_context/resolvent_ops.rs
+++ b/src/librustc_traits/chalk_context/resolvent_ops.rs
@@ -16,7 +16,7 @@ use rustc::traits::{
     Environment,
     InEnvironment,
 };
-use rustc::ty::{self, Ty, TyCtxt, InferConst};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::GenericArg;
 use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc::mir::interpret::ConstValue;
@@ -287,10 +287,7 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> {
         a: &'tcx ty::Const<'tcx>,
         b: &'tcx ty::Const<'tcx>,
     ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        if let ty::Const {
-            val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)),
-            ..
-        } = a {
+        if let ty::Const { val: ConstValue::Bound(debruijn, bound_ct), .. } = a {
             if *debruijn == self.binder_index {
                 self.unify_free_answer_var(*bound_ct, b.into())?;
                 return Ok(b);
@@ -299,14 +296,8 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> {
 
         match (a, b) {
             (
-                ty::Const {
-                    val: ConstValue::Infer(InferConst::Canonical(a_debruijn, a_bound)),
-                    ..
-                },
-                ty::Const {
-                    val: ConstValue::Infer(InferConst::Canonical(b_debruijn, b_bound)),
-                    ..
-                },
+                ty::Const { val: ConstValue::Bound(a_debruijn, a_bound), .. },
+                ty::Const { val: ConstValue::Bound(b_debruijn, b_bound), .. },
             ) => {
                 assert_eq!(a_debruijn, b_debruijn);
                 assert_eq!(a_bound, b_bound);
diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs
index 88e62db9a10..c1316f415a5 100644
--- a/src/librustc_traits/dropck_outlives.rs
+++ b/src/librustc_traits/dropck_outlives.rs
@@ -80,22 +80,30 @@ fn dropck_outlives<'tcx>(
             let mut fulfill_cx = TraitEngine::new(infcx.tcx);
 
             let cause = ObligationCause::dummy();
+            let mut constraints = DtorckConstraint::empty();
             while let Some((ty, depth)) = ty_stack.pop() {
-                let DtorckConstraint {
-                    dtorck_types,
-                    outlives,
-                    overflows,
-                } = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?;
+                info!("{} kinds, {} overflows, {} ty_stack",
+                    result.kinds.len(), result.overflows.len(), ty_stack.len());
+                dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?;
 
                 // "outlives" represent types/regions that may be touched
                 // by a destructor.
-                result.kinds.extend(outlives);
-                result.overflows.extend(overflows);
+                result.kinds.extend(constraints.outlives.drain(..));
+                result.overflows.extend(constraints.overflows.drain(..));
+
+                // If we have even one overflow, we should stop trying to evaluate further --
+                // chances are, the subsequent overflows for this evaluation won't provide useful
+                // information and will just decrease the speed at which we can emit these errors
+                // (since we'll be printing for just that much longer for the often enormous types
+                // that result here).
+                if result.overflows.len() >= 1 {
+                    break;
+                }
 
                 // dtorck types are "types that will get dropped but which
                 // do not themselves define a destructor", more or less. We have
                 // to push them onto the stack to be expanded.
-                for ty in dtorck_types {
+                for ty in constraints.dtorck_types.drain(..) {
                     match infcx.at(&cause, param_env).normalize(&ty) {
                         Ok(Normalized {
                             value: ty,
@@ -152,21 +160,23 @@ fn dtorck_constraint_for_ty<'tcx>(
     for_ty: Ty<'tcx>,
     depth: usize,
     ty: Ty<'tcx>,
-) -> Result<DtorckConstraint<'tcx>, NoSolution> {
+    constraints: &mut DtorckConstraint<'tcx>,
+) -> Result<(), NoSolution> {
     debug!(
         "dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
         span, for_ty, depth, ty
     );
 
     if depth >= *tcx.sess.recursion_limit.get() {
-        return Ok(DtorckConstraint {
-            outlives: vec![],
-            dtorck_types: vec![],
-            overflows: vec![ty],
-        });
+        constraints.overflows.push(ty);
+        return Ok(());
     }
 
-    let result = match ty.kind {
+    if tcx.trivial_dropck_outlives(ty) {
+        return Ok(());
+    }
+
+    match ty.kind {
         ty::Bool
         | ty::Char
         | ty::Int(_)
@@ -181,22 +191,20 @@ fn dtorck_constraint_for_ty<'tcx>(
         | ty::FnPtr(_)
         | ty::GeneratorWitness(..) => {
             // these types never have a destructor
-            Ok(DtorckConstraint::empty())
         }
 
         ty::Array(ety, _) | ty::Slice(ety) => {
             // single-element containers, behave like their element
-            dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
+            dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)?;
         }
 
-        ty::Tuple(tys) => tys.iter()
-            .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty.expect_ty()))
-            .collect(),
+        ty::Tuple(tys) => for ty in tys.iter() {
+            dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty.expect_ty(), constraints)?;
+        },
 
-        ty::Closure(def_id, substs) => substs.as_closure()
-            .upvar_tys(def_id, tcx)
-            .map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
-            .collect(),
+        ty::Closure(def_id, substs) => for ty in substs.as_closure().upvar_tys(def_id, tcx) {
+            dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+        }
 
         ty::Generator(def_id, substs, _movability) => {
             // rust-lang/rust#49918: types can be constructed, stored
@@ -222,17 +230,8 @@ fn dtorck_constraint_for_ty<'tcx>(
             // derived from lifetimes attached to the upvars, and we
             // *do* incorporate the upvars here.
 
-            let constraint = DtorckConstraint {
-                outlives: substs.as_generator().upvar_tys(def_id, tcx).map(|t| t.into()).collect(),
-                dtorck_types: vec![],
-                overflows: vec![],
-            };
-            debug!(
-                "dtorck_constraint: generator {:?} => {:?}",
-                def_id, constraint
-            );
-
-            Ok(constraint)
+            constraints.outlives.extend(substs.as_generator().upvar_tys(def_id, tcx)
+                .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }));
         }
 
         ty::Adt(def, substs) => {
@@ -241,41 +240,34 @@ fn dtorck_constraint_for_ty<'tcx>(
                 outlives,
                 overflows,
             } = tcx.at(span).adt_dtorck_constraint(def.did)?;
-            Ok(DtorckConstraint {
-                // FIXME: we can try to recursively `dtorck_constraint_on_ty`
-                // there, but that needs some way to handle cycles.
-                dtorck_types: dtorck_types.subst(tcx, substs),
-                outlives: outlives.subst(tcx, substs),
-                overflows: overflows.subst(tcx, substs),
-            })
+            // FIXME: we can try to recursively `dtorck_constraint_on_ty`
+            // there, but that needs some way to handle cycles.
+            constraints.dtorck_types.extend(dtorck_types.subst(tcx, substs));
+            constraints.outlives.extend(outlives.subst(tcx, substs));
+            constraints.overflows.extend(overflows.subst(tcx, substs));
         }
 
         // Objects must be alive in order for their destructor
         // to be called.
-        ty::Dynamic(..) => Ok(DtorckConstraint {
-            outlives: vec![ty.into()],
-            dtorck_types: vec![],
-            overflows: vec![],
-        }),
+        ty::Dynamic(..) => {
+            constraints.outlives.push(ty.into());
+        },
 
         // Types that can't be resolved. Pass them forward.
-        ty::Projection(..) | ty::Opaque(..) | ty::Param(..) => Ok(DtorckConstraint {
-            outlives: vec![],
-            dtorck_types: vec![ty],
-            overflows: vec![],
-        }),
+        ty::Projection(..) | ty::Opaque(..) | ty::Param(..) => {
+            constraints.dtorck_types.push(ty);
+        },
 
         ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
 
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => {
             // By the time this code runs, all type variables ought to
             // be fully resolved.
-            Err(NoSolution)
+            return Err(NoSolution)
         }
-    };
+    }
 
-    debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
-    result
+    Ok(())
 }
 
 /// Calculates the dtorck constraint for a type.
@@ -301,10 +293,11 @@ crate fn adt_dtorck_constraint(
         return Ok(result);
     }
 
-    let mut result = def.all_fields()
-        .map(|field| tcx.type_of(field.did))
-        .map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty))
-        .collect::<Result<DtorckConstraint<'_>, NoSolution>>()?;
+    let mut result = DtorckConstraint::empty();
+    for field in def.all_fields() {
+        let fty = tcx.type_of(field.did);
+        dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?;
+    }
     result.outlives.extend(tcx.destructor_constraints(def));
     dedup_dtorck_constraint(&mut result);
 
diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs
index 4c30227150f..0df367fcca8 100644
--- a/src/librustc_traits/lowering/mod.rs
+++ b/src/librustc_traits/lowering/mod.rs
@@ -218,7 +218,7 @@ fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
 
     let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
 
-    let predicates = &tcx.predicates_defined_on(def_id).predicates;
+    let predicates = tcx.predicates_defined_on(def_id).predicates;
 
     // Warning: these where clauses are not substituted for bound vars yet,
     // so that we don't need to adjust binders in the `FromEnv` rules below
@@ -319,7 +319,7 @@ fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> {
     let trait_pred = ty::TraitPredicate { trait_ref }.lower();
 
     // `WC`
-    let predicates = &tcx.predicates_of(def_id).predicates;
+    let predicates = tcx.predicates_of(def_id).predicates;
     let where_clauses = predicates
         .iter()
         .map(|(wc, _)| wc.lower())
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 2ee5ecfbcdc..a052ad95ed5 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -54,8 +54,7 @@ pub trait AstConv<'tcx> {
     /// but this can lead to cycle errors. The problem is that we have
     /// to do this resolution *in order to create the predicates in
     /// the first place*. Hence, we have this "special pass".
-    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-                                 -> &'tcx ty::GenericPredicates<'tcx>;
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>;
 
     /// Returns the lifetime to use when a lifetime is omitted (and not elided).
     fn re_infer(
@@ -233,8 +232,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 tcx.sess,
                 span,
                 E0632,
-                "cannot provide explicit type parameters when `impl Trait` is \
-                 used in argument position."
+                "cannot provide explicit generic arguments when `impl Trait` is \
+                 used in argument position"
             };
 
             err.emit();
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 8b97bf643e9..4f4133954cf 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -611,6 +611,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => {
                     debug!("supplied_sig_of_closure: closure is async fn body");
                     self.deduce_future_output_from_obligations(expr_def_id)
+                        .unwrap_or_else(|| {
+                            // AFAIK, deducing the future output
+                            // always succeeds *except* in error cases
+                            // like #65159. I'd like to return Error
+                            // here, but I can't because I can't
+                            // easily (and locally) prove that we
+                            // *have* reported an
+                            // error. --nikomatsakis
+                            astconv.ty_infer(None, decl.output.span())
+                        })
                 }
 
                 _ => astconv.ty_infer(None, decl.output.span()),
@@ -645,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn deduce_future_output_from_obligations(
         &self,
         expr_def_id: DefId,
-    ) -> Ty<'tcx> {
+    ) -> Option<Ty<'tcx>> {
         debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
 
         let ret_coercion =
@@ -688,8 +698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     None
                 }
-            })
-            .unwrap();
+            });
 
         debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty);
         output_ty
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 5c4c66bb64e..f79351dc903 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -824,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         target: Ty<'tcx>,
         allow_two_phase: AllowTwoPhase,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
-        let source = self.resolve_type_vars_with_obligations(expr_ty);
+        let source = self.resolve_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
@@ -842,7 +842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     /// Same as `try_coerce()`, but without side-effects.
     pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
-        let source = self.resolve_type_vars_with_obligations(expr_ty);
+        let source = self.resolve_vars_with_obligations(expr_ty);
         debug!("coercion::can({:?} -> {:?})", source, target);
 
         let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable);
@@ -866,8 +866,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 -> RelateResult<'tcx, Ty<'tcx>>
         where E: AsCoercionSite
     {
-        let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
-        let new_ty = self.resolve_type_vars_with_obligations(new_ty);
+        let prev_ty = self.resolve_vars_with_obligations(prev_ty);
+        let new_ty = self.resolve_vars_with_obligations(new_ty);
         debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
 
         // Special-case that coercion alone cannot handle:
@@ -1346,7 +1346,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             err.span_label(return_sp, "expected because this return type...");
             err.span_label( *sp, format!(
                 "...is found to be `{}` here",
-                fcx.resolve_type_vars_with_obligations(expected),
+                fcx.resolve_vars_with_obligations(expected),
             ));
         }
         err
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index d92ea7fd49a..3509d6566ec 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -108,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                               expected: Ty<'tcx>,
                               allow_two_phase: AllowTwoPhase)
                               -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
-        let expected = self.resolve_type_vars_with_obligations(expected);
+        let expected = self.resolve_vars_with_obligations(expected);
 
         let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase) {
             Ok(ty) => return (ty, None),
@@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
-        let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
+        let expr_ty = self.resolve_vars_with_obligations(checked_ty);
         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
 
         if self.is_assign_to_bool(expr, expected) {
@@ -350,11 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // If the span is from a macro, then it's hard to extract the text
         // and make a good suggestion, so don't bother.
-        let is_desugaring = match sp.desugaring_kind() {
-            Some(k) => sp.is_desugaring(k),
-            None => false
-        };
-        let is_macro = sp.from_expansion() && !is_desugaring;
+        let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none();
 
         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
         let expr = expr.peel_drop_temps();
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index d46ac4a39a3..0c8df9bad44 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -44,7 +44,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
             ensure_drop_predicates_are_implied_by_item_defn(
                 tcx,
                 drop_impl_did,
-                &dtor_predicates,
+                dtor_predicates,
                 adt_def.did,
                 self_to_impl_substs,
             )
@@ -140,7 +140,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
 fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     tcx: TyCtxt<'tcx>,
     drop_impl_did: DefId,
-    dtor_predicates: &ty::GenericPredicates<'tcx>,
+    dtor_predicates: ty::GenericPredicates<'tcx>,
     self_type_did: DefId,
     self_to_impl_substs: SubstsRef<'tcx>,
 ) -> Result<(), ErrorReported> {
@@ -199,7 +199,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     // just to look for all the predicates directly.
 
     assert_eq!(dtor_predicates.parent, None);
-    for (predicate, _) in &dtor_predicates.predicates {
+    for (predicate, _) in dtor_predicates.predicates {
         // (We do not need to worry about deep analysis of type
         // expressions etc because the Drop impls are already forced
         // to take on a structure that is roughly an alpha-renaming of
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index ad46a443b8f..f5f85bbcb10 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1010,7 +1010,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr,
     ) -> Ty<'tcx> {
         let flds = expected.only_has_type(self).and_then(|ty| {
-            let ty = self.resolve_type_vars_with_obligations(ty);
+            let ty = self.resolve_vars_with_obligations(ty);
             match ty.kind {
                 ty::Tuple(ref flds) => Some(&flds[..]),
                 _ => None
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 96cc5aa1dc2..d90ed2a790b 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -777,7 +777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 "items from traits can only be used if the trait is implemented and in scope"
             });
-            let mut msg = format!(
+            let message = |action| format!(
                 "the following {traits_define} an item `{name}`, perhaps you need to {action} \
                  {one_of_them}:",
                 traits_define = if candidates.len() == 1 {
@@ -785,11 +785,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     "traits define"
                 },
-                action = if let Some(param) = param_type {
-                    format!("restrict type parameter `{}` with", param)
-                } else {
-                    "implement".to_string()
-                },
+                action = action,
                 one_of_them = if candidates.len() == 1 {
                     "it"
                 } else {
@@ -809,50 +805,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // Get the `hir::Param` to verify whether it already has any bounds.
                         // We do this to avoid suggesting code that ends up as `T: FooBar`,
                         // instead we suggest `T: Foo + Bar` in that case.
-                        let mut has_bounds = None;
-                        let mut impl_trait = false;
-                        if let Node::GenericParam(ref param) = hir.get(id) {
-                            let kind = &param.kind;
-                            if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = kind {
-                                // We've found `fn foo(x: impl Trait)` instead of
-                                // `fn foo<T>(x: T)`. We want to suggest the correct
-                                // `fn foo(x: impl Trait + TraitBound)` instead of
-                                // `fn foo<T: TraitBound>(x: T)`. (See #63706.)
-                                impl_trait = true;
-                                has_bounds = param.bounds.get(1);
-                            } else {
-                                has_bounds = param.bounds.get(0);
+                        match hir.get(id) {
+                            Node::GenericParam(ref param) => {
+                                let mut impl_trait = false;
+                                let has_bounds = if let hir::GenericParamKind::Type {
+                                    synthetic: Some(_), ..
+                                } = &param.kind {
+                                    // We've found `fn foo(x: impl Trait)` instead of
+                                    // `fn foo<T>(x: T)`. We want to suggest the correct
+                                    // `fn foo(x: impl Trait + TraitBound)` instead of
+                                    // `fn foo<T: TraitBound>(x: T)`. (#63706)
+                                    impl_trait = true;
+                                    param.bounds.get(1)
+                                } else {
+                                    param.bounds.get(0)
+                                };
+                                let sp = hir.span(id);
+                                let sp = if let Some(first_bound) = has_bounds {
+                                    // `sp` only covers `T`, change it so that it covers
+                                    // `T:` when appropriate
+                                    sp.until(first_bound.span())
+                                } else {
+                                    sp
+                                };
+                                // FIXME: contrast `t.def_id` against `param.bounds` to not suggest
+                                // traits already there. That can happen when the cause is that
+                                // we're in a const scope or associated function used as a method.
+                                err.span_suggestions(
+                                    sp,
+                                    &message(format!(
+                                        "restrict type parameter `{}` with",
+                                        param.name.ident().as_str(),
+                                    )),
+                                    candidates.iter().map(|t| format!(
+                                        "{}{} {}{}",
+                                        param.name.ident().as_str(),
+                                        if impl_trait { " +" } else { ":" },
+                                        self.tcx.def_path_str(t.def_id),
+                                        if has_bounds.is_some() { " + "} else { "" },
+                                    )),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                suggested = true;
+                            }
+                            Node::Item(hir::Item {
+                                kind: hir::ItemKind::Trait(.., bounds, _), ident, ..
+                            }) => {
+                                let (sp, sep, article) = if bounds.is_empty() {
+                                    (ident.span.shrink_to_hi(), ":", "a")
+                                } else {
+                                    (bounds.last().unwrap().span().shrink_to_hi(), " +", "another")
+                                };
+                                err.span_suggestions(
+                                    sp,
+                                    &message(format!("add {} supertrait for", article)),
+                                    candidates.iter().map(|t| format!(
+                                        "{} {}",
+                                        sep,
+                                        self.tcx.def_path_str(t.def_id),
+                                    )),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                suggested = true;
                             }
+                            _ => {}
                         }
-                        let sp = hir.span(id);
-                        // `sp` only covers `T`, change it so that it covers `T:` when appropriate.
-                        let sp = if let Some(first_bound) = has_bounds {
-                            sp.until(first_bound.span())
-                        } else {
-                            sp
-                        };
-
-                        // FIXME: contrast `t.def_id` against `param.bounds` to not suggest traits
-                        // already there. That can happen when the cause is that we're in a const
-                        // scope or associated function used as a method.
-                        err.span_suggestions(
-                            sp,
-                            &msg[..],
-                            candidates.iter().map(|t| format!(
-                                "{}{} {}{}",
-                                param,
-                                if impl_trait { " +" } else { ":" },
-                                self.tcx.def_path_str(t.def_id),
-                                if has_bounds.is_some() { " + " } else { "" },
-                            )),
-                            Applicability::MaybeIncorrect,
-                        );
-                        suggested = true;
                     }
                 };
             }
 
             if !suggested {
+                let mut msg = message(if let Some(param) = param_type {
+                    format!("restrict type parameter `{}` with", param)
+                } else {
+                    "implement".to_string()
+                });
                 for (i, trait_info) in candidates.iter().enumerate() {
                     msg.push_str(&format!(
                         "\ncandidate #{}: `{}`",
@@ -892,7 +919,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // This occurs for UFCS desugaring of `T::method`, where there is no
         // receiver expression for the method call, and thus no autoderef.
         if let SelfSource::QPath(_) = source {
-            return is_local(self.resolve_type_vars_with_obligations(rcvr_ty));
+            return is_local(self.resolve_vars_with_obligations(rcvr_ty));
         }
 
         self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7475b9cc3b3..73a025182a7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1387,9 +1387,37 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
     check_transparent(tcx, span, def_id);
+    check_union_fields(tcx, span, def_id);
     check_packed(tcx, span, def_id);
 }
 
+/// When the `#![feature(untagged_unions)]` gate is active,
+/// check that the fields of the `union` does not contain fields that need dropping.
+fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: DefId) -> bool {
+    let item_type = tcx.type_of(item_def_id);
+    if let ty::Adt(def, substs) = item_type.kind {
+        assert!(def.is_union());
+        let fields = &def.non_enum_variant().fields;
+        for field in fields {
+            let field_ty = field.ty(tcx, substs);
+            // We are currently checking the type this field came from, so it must be local.
+            let field_span = tcx.hir().span_if_local(field.did).unwrap();
+            let param_env = tcx.param_env(field.did);
+            if field_ty.needs_drop(tcx, param_env) {
+                struct_span_err!(tcx.sess, field_span, E0740,
+                                    "unions may not contain fields that need dropping")
+                            .span_note(field_span,
+                                        "`std::mem::ManuallyDrop` can be used to wrap the type")
+                            .emit();
+                return false;
+            }
+        }
+    } else {
+        span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind);
+    }
+    return true;
+}
+
 /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
 /// projections that would result in "inheriting lifetimes".
 fn check_opaque<'tcx>(
@@ -2245,19 +2273,17 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         self.tcx
     }
 
-    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-                                 -> &'tcx ty::GenericPredicates<'tcx>
-    {
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
         let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
         let item_id = tcx.hir().ty_param_owner(hir_id);
         let item_def_id = tcx.hir().local_def_id(item_id);
         let generics = tcx.generics_of(item_def_id);
         let index = generics.param_def_id_to_index[&def_id];
-        tcx.arena.alloc(ty::GenericPredicates {
+        ty::GenericPredicates {
             parent: None,
-            predicates: self.param_env.caller_bounds.iter().filter_map(|&predicate| {
-                match predicate {
+            predicates: tcx.arena.alloc_from_iter(
+                self.param_env.caller_bounds.iter().filter_map(|&predicate| match predicate {
                     ty::Predicate::Trait(ref data)
                     if data.skip_binder().self_ty().is_param(index) => {
                         // HACK(eddyb) should get the original `Span`.
@@ -2265,9 +2291,9 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
                         Some((predicate, span))
                     }
                     _ => None
-                }
-            }).collect()
-        })
+                }),
+            ),
+        }
     }
 
     fn re_infer(
@@ -2442,23 +2468,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.cause(span, ObligationCauseCode::MiscObligation)
     }
 
-    /// Resolves type variables in `ty` if possible. Unlike the infcx
+    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
     /// version (resolve_vars_if_possible), this version will
     /// also select obligations if it seems useful, in an effort
     /// to get more type information.
-    fn resolve_type_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_type_vars_with_obligations(ty={:?})", ty);
+    fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        debug!("resolve_vars_with_obligations(ty={:?})", ty);
 
         // No Infer()? Nothing needs doing.
-        if !ty.has_infer_types() {
-            debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
+        if !ty.has_infer_types() && !ty.has_infer_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
             return ty;
         }
 
         // If `ty` is a type variable, see whether we already know what it is.
         ty = self.resolve_vars_if_possible(&ty);
-        if !ty.has_infer_types() {
-            debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
+        if !ty.has_infer_types() && !ty.has_infer_consts()  {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
             return ty;
         }
 
@@ -2469,7 +2495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.select_obligations_where_possible(false, |_| {});
         ty = self.resolve_vars_if_possible(&ty);
 
-        debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
+        debug!("resolve_vars_with_obligations: ty={:?}", ty);
         ty
     }
 
@@ -3670,7 +3696,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                            formal_ret: Ty<'tcx>,
                                            formal_args: &[Ty<'tcx>])
                                            -> Vec<Ty<'tcx>> {
-        let formal_ret = self.resolve_type_vars_with_obligations(formal_ret);
+        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
         let ret_ty = match expected_ret.only_has_type(self) {
             Some(ret) => ret,
             None => return Vec::new()
@@ -4519,7 +4545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 err.span_suggestion(
                     span,
                     "try adding a return type",
-                    format!("-> {} ", self.resolve_type_vars_with_obligations(found)),
+                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
                     Applicability::MachineApplicable);
                 true
             }
@@ -4995,7 +5021,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // If no resolution is possible, then an error is reported.
     // Numeric inference variables may be left unresolved.
     pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let ty = self.resolve_type_vars_with_obligations(ty);
+        let ty = self.resolve_vars_with_obligations(ty);
         if !ty.is_ty_var() {
             ty
         } else {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index f9df2d1d848..819c347d3ae 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_expr_with_needs(lhs_expr, Needs::MutPlace)
             }
         };
-        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
+        let lhs_ty = self.resolve_vars_with_obligations(lhs_ty);
 
         // N.B., as we have not yet type-checked the RHS, we don't have the
         // type at hand. Make a variable to represent it. The whole reason
@@ -196,7 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // see `NB` above
         let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
-        let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
+        let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
 
         let return_ty = match result {
             Ok(method) => {
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 53ee0777c7c..97c30f208f5 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -251,7 +251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         mut def_bm: BindingMode,
     ) -> (Ty<'tcx>, BindingMode) {
-        let mut expected = self.resolve_type_vars_with_obligations(&expected);
+        let mut expected = self.resolve_vars_with_obligations(&expected);
 
         // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
         // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index fa283904fe4..18b103960c7 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -791,7 +791,7 @@ fn check_opaque_types<'fcx, 'tcx>(
                         "check_opaque_types: may define, predicates={:#?}",
                         predicates,
                     );
-                    for &(pred, _) in predicates.predicates.iter() {
+                    for &(pred, _) in predicates.predicates {
                         let substituted_pred = pred.subst(fcx.tcx, substs);
                         // Avoid duplication of predicates that contain no parameters, for example.
                         if !predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
@@ -1011,7 +1011,7 @@ fn check_variances_for_type_defn<'tcx>(
 
     identify_constrained_generic_params(
         tcx,
-        &ty_predicates,
+        ty_predicates,
         None,
         &mut constrained_parameters,
     );
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 5b2081bef78..1749fd1075e 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -182,8 +182,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
         self.tcx
     }
 
-    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-                                 -> &'tcx ty::GenericPredicates<'tcx> {
+    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         self.tcx
             .at(span)
             .type_param_predicates((self.item_def_id, def_id))
@@ -254,7 +253,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
 fn type_param_predicates(
     tcx: TyCtxt<'_>,
     (item_def_id, def_id): (DefId, DefId),
-) -> &ty::GenericPredicates<'_> {
+) -> ty::GenericPredicates<'_> {
     use rustc::hir::*;
 
     // In the AST, bounds can derive from two places. Either
@@ -275,10 +274,10 @@ fn type_param_predicates(
         tcx.generics_of(item_def_id).parent
     };
 
-    let result = parent.map_or(&tcx.common.empty_predicates, |parent| {
+    let mut result = parent.map(|parent| {
         let icx = ItemCtxt::new(tcx, parent);
         icx.get_type_parameter_bounds(DUMMY_SP, def_id)
-    });
+    }).unwrap_or_default();
     let mut extend = None;
 
     let item_hir_id = tcx.hir().as_local_hir_id(item_def_id).unwrap();
@@ -321,9 +320,7 @@ fn type_param_predicates(
     };
 
     let icx = ItemCtxt::new(tcx, item_def_id);
-    let mut result = (*result).clone();
-    result.predicates.extend(extend.into_iter());
-    result.predicates.extend(
+    let extra_predicates = extend.into_iter().chain(
         icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
             .into_iter()
             .filter(|(predicate, _)| {
@@ -331,9 +328,12 @@ fn type_param_predicates(
                     ty::Predicate::Trait(ref data) => data.skip_binder().self_ty().is_param(index),
                     _ => false,
                 }
-            })
+            }),
+    );
+    result.predicates = tcx.arena.alloc_from_iter(
+        result.predicates.iter().copied().chain(extra_predicates),
     );
-    tcx.arena.alloc(result)
+    result
 }
 
 impl ItemCtxt<'tcx> {
@@ -698,7 +698,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef {
 fn super_predicates_of(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
-) -> &ty::GenericPredicates<'_> {
+) -> ty::GenericPredicates<'_> {
     debug!("super_predicates(trait_def_id={:?})", trait_def_id);
     let trait_hir_id = tcx.hir().as_local_hir_id(trait_def_id).unwrap();
 
@@ -732,21 +732,23 @@ fn super_predicates_of(
         generics, item.hir_id, self_param_ty, OnlySelfBounds(!is_trait_alias));
 
     // Combine the two lists to form the complete set of superbounds:
-    let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
+    let superbounds = &*tcx.arena.alloc_from_iter(
+        superbounds1.into_iter().chain(superbounds2)
+    );
 
     // Now require that immediate supertraits are converted,
     // which will, in turn, reach indirect supertraits.
-    for &(pred, span) in &superbounds {
+    for &(pred, span) in superbounds {
         debug!("superbound: {:?}", pred);
         if let ty::Predicate::Trait(bound) = pred {
             tcx.at(span).super_predicates_of(bound.def_id());
         }
     }
 
-    tcx.arena.alloc(ty::GenericPredicates {
+    ty::GenericPredicates {
         parent: None,
         predicates: superbounds,
-    })
+    }
 }
 
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef {
@@ -1958,7 +1960,7 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
 fn predicates_defined_on(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> &ty::GenericPredicates<'_> {
+) -> ty::GenericPredicates<'_> {
     debug!("predicates_defined_on({:?})", def_id);
     let mut result = tcx.explicit_predicates_of(def_id);
     debug!(
@@ -1974,9 +1976,13 @@ fn predicates_defined_on(
             def_id,
             inferred_outlives,
         );
-        let mut predicates = (*result).clone();
-        predicates.predicates.extend(inferred_outlives.iter().map(|&p| (p, span)));
-        result = tcx.arena.alloc(predicates);
+        result.predicates = tcx.arena.alloc_from_iter(
+            result.predicates.iter().copied().chain(
+                // FIXME(eddyb) use better spans - maybe add `Span`s
+                // to `inferred_outlives_of` predicates as well?
+                inferred_outlives.iter().map(|&p| (p, span)),
+            ),
+        );
     }
     debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
     result
@@ -1985,7 +1991,7 @@ fn predicates_defined_on(
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
 /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
 /// `Self: Trait` predicates for traits.
-fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::GenericPredicates<'_> {
+fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
     let mut result = tcx.predicates_defined_on(def_id);
 
     if tcx.is_trait(def_id) {
@@ -2002,9 +2008,11 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::GenericPredicates<'_> {
         // used, and adding the predicate into this list ensures
         // that this is done.
         let span = tcx.def_span(def_id);
-        let mut predicates = (*result).clone();
-        predicates.predicates.push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span));
-        result = tcx.arena.alloc(predicates);
+        result.predicates = tcx.arena.alloc_from_iter(
+            result.predicates.iter().copied().chain(
+                std::iter::once((ty::TraitRef::identity(tcx, def_id).to_predicate(), span))
+            ),
+        );
     }
     debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
@@ -2015,7 +2023,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::GenericPredicates<'_> {
 fn explicit_predicates_of(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> &ty::GenericPredicates<'_> {
+) -> ty::GenericPredicates<'_> {
     use rustc::hir::*;
     use rustc_data_structures::fx::FxHashSet;
 
@@ -2024,6 +2032,7 @@ fn explicit_predicates_of(
     /// A data structure with unique elements, which preserves order of insertion.
     /// Preserving the order of insertion is important here so as not to break
     /// compile-fail UI tests.
+    // FIXME(eddyb) just use `IndexSet` from `indexmap`.
     struct UniquePredicates<'tcx> {
         predicates: Vec<(ty::Predicate<'tcx>, Span)>,
         uniques: FxHashSet<(ty::Predicate<'tcx>, Span)>,
@@ -2133,10 +2142,10 @@ fn explicit_predicates_of(
                     let bounds_predicates = bounds.predicates(tcx, opaque_ty);
                     if impl_trait_fn.is_some() {
                         // opaque types
-                        return tcx.arena.alloc(ty::GenericPredicates {
+                        return ty::GenericPredicates {
                             parent: None,
-                            predicates: bounds_predicates,
-                        });
+                            predicates: tcx.arena.alloc_from_iter(bounds_predicates),
+                        };
                     } else {
                         // named opaque types
                         predicates.extend(bounds_predicates);
@@ -2339,10 +2348,10 @@ fn explicit_predicates_of(
         );
     }
 
-    let result = tcx.arena.alloc(ty::GenericPredicates {
+    let result = ty::GenericPredicates {
         parent: generics.parent,
-        predicates,
-    });
+        predicates: tcx.arena.alloc_from_iter(predicates),
+    };
     debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
 }
diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs
index 31476eb7317..1fdf49fde55 100644
--- a/src/librustc_typeck/constrained_generic_params.rs
+++ b/src/librustc_typeck/constrained_generic_params.rs
@@ -86,11 +86,11 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
 
 pub fn identify_constrained_generic_params<'tcx>(
     tcx: TyCtxt<'tcx>,
-    predicates: &ty::GenericPredicates<'tcx>,
+    predicates: ty::GenericPredicates<'tcx>,
     impl_trait_ref: Option<ty::TraitRef<'tcx>>,
     input_parameters: &mut FxHashSet<Parameter>,
 ) {
-    let mut predicates = predicates.predicates.clone();
+    let mut predicates = predicates.predicates.to_vec();
     setup_constraining_predicates(tcx, &mut predicates, impl_trait_ref, input_parameters);
 }
 
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index ef08e8d4f0b..3d41c6e09c6 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -194,7 +194,7 @@ a guard.
 ```compile_fail,E0029
 let string = "salutations !";
 
-// The ordering relation for strings can't be evaluated at compile time,
+// The ordering relation for strings cannot be evaluated at compile time,
 // so this doesn't work:
 match string {
     "hello" ..= "world" => {}
@@ -348,7 +348,7 @@ fn main() {
 "##,
 
 E0044: r##"
-You can't use type or const parameters on foreign items.
+You cannot use type or const parameters on foreign items.
 Example of erroneous code:
 
 ```compile_fail,E0044
@@ -788,7 +788,7 @@ fn some_other_func() {}
 fn some_function() {
     SOME_CONST = 14; // error : a constant value cannot be changed!
     1 = 3; // error : 1 isn't a valid place!
-    some_other_func() = 4; // error : we can't assign value to a function!
+    some_other_func() = 4; // error : we cannot assign value to a function!
     SomeStruct.x = 12; // error : SomeStruct a structure name but it is used
                        // like a variable!
 }
@@ -3891,6 +3891,33 @@ details.
 [issue #33685]: https://github.com/rust-lang/rust/issues/33685
 "##,
 
+E0588: r##"
+A type with `packed` representation hint has a field with `align`
+representation hint.
+
+Erroneous code example:
+
+```compile_fail,E0588
+#[repr(align(16))]
+struct Aligned(i32);
+
+#[repr(packed)] // error!
+struct Packed(Aligned);
+```
+
+Just like you cannot have both `align` and `packed` representation hints on a
+same type, a `packed` type cannot contain another type with the `align`
+representation hint. However, you can do the opposite:
+
+```
+#[repr(packed)]
+struct Packed(i32);
+
+#[repr(align(16))] // ok!
+struct Aligned(Packed);
+```
+"##,
+
 E0592: r##"
 This error occurs when you defined methods or associated functions with same
 name.
@@ -4299,7 +4326,7 @@ extern {
 
 unsafe {
     printf(::std::ptr::null(), 0f32);
-    // error: can't pass an `f32` to variadic function, cast to `c_double`
+    // error: cannot pass an `f32` to variadic function, cast to `c_double`
 }
 ```
 
@@ -4863,6 +4890,10 @@ assert_eq!(1, discriminant(&Enum::Struct{a: 7, b: 11}));
 ```
 "##,
 
+E0740: r##"
+A `union` cannot have fields with destructors.
+"##,
+
 E0733: r##"
 Recursion in an `async fn` requires boxing. For example, this will not compile:
 
@@ -4996,7 +5027,7 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
 //  E0174,
 //  E0182, // merged into E0229
     E0183,
-//  E0187, // can't infer the kind of the closure
+//  E0187, // cannot infer the kind of the closure
 //  E0188, // can not cast an immutable reference to a mutable pointer
 //  E0189, // deprecated: can only cast a boxed pointer to a boxed object
 //  E0190, // deprecated: can only cast a &-pointer to an &-object
@@ -5043,13 +5074,12 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
 //  E0564, // only named lifetimes are allowed in `impl Trait`,
            // but `{}` was found in the type `{}`
     E0587, // type has conflicting packed and align representation hints
-    E0588, // packed type cannot transitively contain a `[repr(align)]` type
 //  E0611, // merged into E0616
 //  E0612, // merged into E0609
 //  E0613, // Removed (merged with E0609)
     E0627, // yield statement outside of generator literal
-    E0632, // cannot provide explicit type parameters when `impl Trait` is used
-           // in argument position.
+    E0632, // cannot provide explicit generic arguments when `impl Trait` is
+           // used in argument position
     E0634, // type has conflicting packed representaton hints
     E0640, // infer outlives requirements
     E0641, // cannot cast to/from a pointer with an unknown kind
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index ab660caa222..2d188007712 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -114,7 +114,7 @@ fn enforce_impl_params_are_constrained(
 
     let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     cgp::identify_constrained_generic_params(
-        tcx, &impl_predicates, impl_trait_ref, &mut input_parameters);
+        tcx, impl_predicates, impl_trait_ref, &mut input_parameters);
 
     // Disallow unconstrained lifetimes, but only if they appear in assoc types.
     let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
index 40a57788c07..83194144216 100644
--- a/src/librustc_typeck/outlives/explicit.rs
+++ b/src/librustc_typeck/outlives/explicit.rs
@@ -30,7 +30,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
             let mut required_predicates = RequiredPredicates::default();
 
             // process predicates and convert to `RequiredPredicates` entry, see below
-            for (pred, _) in predicates.predicates.iter() {
+            for (pred, _) in predicates.predicates {
                 match pred {
                     ty::Predicate::TypeOutlives(predicate) => {
                         let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 18a84cd0eeb..b7f5ed9d004 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -104,7 +104,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     // regardless of the choice of `T`.
                     let params = (
                         self.cx.tcx.generics_of(param_env_def_id),
-                        &&self.cx.tcx.common.empty_predicates,
+                        ty::GenericPredicates::default(),
                     ).clean(self.cx).params;
 
                     Generics {
@@ -489,7 +489,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
 
         let mut generic_params = (
             tcx.generics_of(param_env_def_id),
-            &tcx.explicit_predicates_of(param_env_def_id),
+            tcx.explicit_predicates_of(param_env_def_id),
         ).clean(self.cx).params;
 
         let mut has_sized = FxHashSet::default();
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index afed11e7fab..ff59dcab672 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                         unsafety: hir::Unsafety::Normal,
                         generics: (
                             self.cx.tcx.generics_of(impl_def_id),
-                            &self.cx.tcx.explicit_predicates_of(impl_def_id),
+                            self.cx.tcx.explicit_predicates_of(impl_def_id),
                         ).clean(self.cx),
                         provided_trait_methods,
                         // FIXME(eddyb) compute both `trait_` and `for_` from
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index da3b52afadf..d5ce9456f7f 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -9,7 +9,7 @@ use std::ops;
 
 use syntax::symbol::{Symbol, sym};
 use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind};
-use syntax::parse::ParseSess;
+use syntax::sess::ParseSess;
 use syntax::feature_gate::Features;
 
 use syntax_pos::Span;
@@ -360,7 +360,7 @@ impl<'a> fmt::Display for Html<'a> {
                     ("target_arch", Some(arch)) => match &*arch.as_str() {
                         "aarch64" => "AArch64",
                         "arm" => "ARM",
-                        "asmjs" => "asm.js",
+                        "asmjs" => "JavaScript",
                         "mips" => "MIPS",
                         "mips64" => "MIPS-64",
                         "msp430" => "MSP430",
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 532c5f67bf3..e7cc8b76e48 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -3,7 +3,7 @@
 use std::iter::once;
 
 use syntax::ast;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::symbol::sym;
 use syntax_pos::Span;
 
@@ -193,7 +193,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
     let auto_trait = cx.tcx.trait_def(did).has_auto_impl;
     let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect();
     let predicates = cx.tcx.predicates_of(did);
-    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
+    let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
     let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight);
@@ -220,7 +220,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     let asyncness =  cx.tcx.asyncness(did);
     let predicates = cx.tcx.predicates_of(did);
     let (generics, decl) = clean::enter_impl_trait(cx, || {
-        ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx))
+        ((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
     });
     let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx);
     clean::Function {
@@ -241,7 +241,7 @@ fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum {
     let predicates = cx.tcx.explicit_predicates_of(did);
 
     clean::Enum {
-        generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
+        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
         variants_stripped: false,
         variants: cx.tcx.adt_def(did).variants.clean(cx),
     }
@@ -257,7 +257,7 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
             CtorKind::Fn => doctree::Tuple,
             CtorKind::Const => doctree::Unit,
         },
-        generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
+        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
@@ -269,7 +269,7 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
 
     clean::Union {
         struct_type: doctree::Plain,
-        generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
+        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
@@ -280,7 +280,7 @@ fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef {
 
     clean::Typedef {
         type_: cx.tcx.type_of(did).clean(cx),
-        generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
+        generics: (cx.tcx.generics_of(did), predicates).clean(cx),
     }
 }
 
@@ -376,7 +376,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>,
                 }
             }).collect::<Vec<_>>(),
             clean::enter_impl_trait(cx, || {
-                (tcx.generics_of(did), &predicates).clean(cx)
+                (tcx.generics_of(did), predicates).clean(cx)
             }),
         )
     };
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 212a09ee6e6..09c9757dc4d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -28,7 +28,7 @@ use rustc::ty::layout::VariantIdx;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use syntax::ast::{self, AttrStyle, Ident};
 use syntax::attr;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::source_map::DUMMY_SP;
 use syntax::symbol::{Symbol, kw, sym};
 use syntax::symbol::InternedString;
@@ -1307,7 +1307,7 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Debug)]
 pub enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
@@ -1589,7 +1589,7 @@ impl Clean<GenericParamDef> for hir::GenericParam {
 }
 
 // maybe use a Generic enum and use Vec<Generic>?
-#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
+#[derive(Clone, Debug, Default)]
 pub struct Generics {
     pub params: Vec<GenericParamDef>,
     pub where_predicates: Vec<WherePredicate>,
@@ -1664,8 +1664,7 @@ impl Clean<Generics> for hir::Generics {
     }
 }
 
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
-                                    &'a &'tcx ty::GenericPredicates<'tcx>) {
+impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
     fn clean(&self, cx: &DocContext<'_>) -> Generics {
         use self::WherePredicate as WP;
         use std::collections::BTreeMap;
@@ -2369,7 +2368,7 @@ impl Clean<Item> for ty::AssocItem {
             }
             ty::AssocKind::Method => {
                 let generics = (cx.tcx.generics_of(self.def_id),
-                                &cx.tcx.explicit_predicates_of(self.def_id)).clean(cx);
+                                cx.tcx.explicit_predicates_of(self.def_id)).clean(cx);
                 let sig = cx.tcx.fn_sig(self.def_id);
                 let mut decl = (self.def_id, sig).clean(cx);
 
@@ -2448,7 +2447,7 @@ impl Clean<Item> for ty::AssocItem {
                     // all of the generics from there and then look for bounds that are
                     // applied to this associated type in question.
                     let predicates = cx.tcx.explicit_predicates_of(did);
-                    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
+                    let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
                     let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
                         let (name, self_type, trait_, bounds) = match *pred {
                             WherePredicate::BoundPredicate {
@@ -3848,7 +3847,7 @@ impl Clean<Mutability> for hir::Mutability {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Copy, Debug, Hash)]
+#[derive(Clone, PartialEq, Debug)]
 pub enum ImplPolarity {
     Positive,
     Negative,
@@ -4507,7 +4506,6 @@ struct RegionDeps<'tcx> {
     smaller: FxHashSet<RegionTarget<'tcx>>
 }
 
-#[derive(Eq, PartialEq, Hash, Debug)]
 enum SimpleBound {
     TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
     Outlives(Lifetime),
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 1c0d1b32737..0b8d4d6c302 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -53,6 +53,8 @@ pub struct Options {
     pub codegen_options_strs: Vec<String>,
     /// Debugging (`-Z`) options to pass to the compiler.
     pub debugging_options: DebuggingOptions,
+    /// Debugging (`-Z`) options strings to pass to the compiler.
+    pub debugging_options_strs: Vec<String>,
     /// The target used to compile the crate against.
     pub target: TargetTriple,
     /// Edition used when reading the crate. Defaults to "2015". Also used by default when
@@ -478,6 +480,7 @@ impl Options {
         let generate_redirect_pages = matches.opt_present("generate-redirect-pages");
         let test_builder = matches.opt_str("test-builder").map(PathBuf::from);
         let codegen_options_strs = matches.opt_strs("C");
+        let debugging_options_strs = matches.opt_strs("Z");
         let lib_strs = matches.opt_strs("L");
         let extern_strs = matches.opt_strs("extern");
         let runtool = matches.opt_str("runtool");
@@ -499,6 +502,7 @@ impl Options {
             codegen_options,
             codegen_options_strs,
             debugging_options,
+            debugging_options_strs,
             target,
             edition,
             maybe_sysroot,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 00265caa965..2337ec5a52c 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -329,7 +329,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
     let config = interface::Config {
         opts: sessopts,
-        crate_cfg: config::parse_cfgspecs(cfgs),
+        crate_cfg: interface::parse_cfgspecs(cfgs),
         input,
         input_path: cpath,
         output_file: None,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 6e453561f6d..bbc00147ee1 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -4,7 +4,7 @@ pub use self::StructType::*;
 
 use syntax::ast;
 use syntax::ast::Name;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax_pos::{self, Span};
 
 use rustc::hir;
@@ -59,7 +59,7 @@ impl Module<'hir> {
             fns        :   Vec::new(),
             mods       :   Vec::new(),
             typedefs   :   Vec::new(),
-            opaque_tys :  Vec::new(),
+            opaque_tys :   Vec::new(),
             statics    :   Vec::new(),
             constants  :   Vec::new(),
             traits     :   Vec::new(),
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 5d86ee9721b..30c9453a643 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -14,7 +14,7 @@ use std::io::prelude::*;
 use syntax::source_map::{SourceMap, FilePathMapping};
 use syntax::parse::lexer;
 use syntax::parse::token::{self, Token};
-use syntax::parse;
+use syntax::sess::ParseSess;
 use syntax::symbol::{kw, sym};
 use syntax_pos::{Span, FileName};
 
@@ -33,7 +33,7 @@ pub fn render_with_highlighting(
                class, tooltip).unwrap();
     }
 
-    let sess = parse::ParseSess::new(FilePathMapping::empty());
+    let sess = ParseSess::new(FilePathMapping::empty());
     let fm = sess.source_map().new_source_file(
         FileName::Custom(String::from("rustdoc-highlighting")),
         src.to_owned(),
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index 5fb9afd6c49..e015739b03c 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -1,7 +1,7 @@
 //! Item types.
 
 use std::fmt;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use crate::clean;
 
 /// Item type. Corresponds to `clean::ItemEnum` variants.
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 1ff71a0024b..414c3137376 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -45,10 +45,11 @@ use errors;
 use serialize::json::{ToJson, Json, as_json};
 use syntax::ast;
 use syntax::edition::Edition;
-use syntax::ext::base::MacroKind;
-use syntax::source_map::FileName;
 use syntax::feature_gate::UnstableFeatures;
+use syntax::print::pprust;
+use syntax::source_map::FileName;
 use syntax::symbol::{Symbol, sym};
+use syntax_expand::base::MacroKind;
 use rustc::hir::def_id::DefId;
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
@@ -1240,6 +1241,7 @@ fn settings(root_path: &str, suffix: &str) -> String {
         ("go-to-only-result", "Directly go to item in search if there is only one result",
             false),
         ("line-numbers", "Show line numbers on code examples", false),
+        ("disable-shortcuts", "Disable keyboard shortcuts", false),
     ];
     format!(
 "<h1 class='fqn'>\
@@ -2957,7 +2959,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
 }
 
 fn render_attribute(attr: &ast::MetaItem) -> Option<String> {
-    let path = attr.path.to_string();
+    let path = pprust::path_to_string(&attr.path);
 
     if attr.is_word() {
         Some(path)
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 17a940cc4c9..f0104c9156d 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -79,6 +79,7 @@ function getSearchElement() {
                      "derive",
                      "traitalias"];
 
+    var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") !== "true";
     var search_input = getSearchInput();
 
     // On the search screen, so you remain on the last tab you opened.
@@ -294,7 +295,7 @@ function getSearchElement() {
 
     function handleShortcut(ev) {
         // Don't interfere with browser shortcuts
-        if (ev.ctrlKey || ev.altKey || ev.metaKey) {
+        if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts === true) {
             return;
         }
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 6bcb4a817d7..8cd32a3d1b5 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -34,6 +34,7 @@ extern crate rustc_typeck;
 extern crate rustc_lexer;
 extern crate serialize;
 extern crate syntax;
+extern crate syntax_expand;
 extern crate syntax_pos;
 extern crate test as testing;
 #[macro_use] extern crate log;
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 32044e48b6f..10e15ab8881 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,6 +1,7 @@
 use errors::Applicability;
 use syntax::parse::lexer::{StringReader as Lexer};
-use syntax::parse::{ParseSess, token};
+use syntax::parse::token;
+use syntax::sess::ParseSess;
 use syntax::source_map::FilePathMapping;
 use syntax_pos::{InnerSpan, FileName};
 
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 9186ed51420..4270b162baf 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -7,7 +7,7 @@ use rustc::ty;
 use rustc_resolve::ParentScope;
 use syntax;
 use syntax::ast::{self, Ident};
-use syntax::ext::base::SyntaxExtensionKind;
+use syntax_expand::base::SyntaxExtensionKind;
 use syntax::feature_gate::UnstableFeatures;
 use syntax::symbol::Symbol;
 use syntax_pos::DUMMY_SP;
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 05e6f36c958..8afc50f83bf 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -67,7 +67,7 @@ pub fn run(options: Options) -> i32 {
     cfgs.push("doctest".to_owned());
     let config = interface::Config {
         opts: sessopts,
-        crate_cfg: config::parse_cfgspecs(cfgs),
+        crate_cfg: interface::parse_cfgspecs(cfgs),
         input,
         input_path: None,
         output_file: None,
@@ -280,6 +280,9 @@ fn run_test(
     for codegen_options_str in &options.codegen_options_strs {
         compiler.arg("-C").arg(&codegen_options_str);
     }
+    for debugging_option_str in &options.debugging_options_strs {
+        compiler.arg("-Z").arg(&debugging_option_str);
+    }
     if no_run {
         compiler.arg("--emit=metadata");
     }
@@ -394,7 +397,7 @@ pub fn make_test(s: &str,
     // Uses libsyntax to parse the doctest and find if there's a main fn and the extern
     // crate already is included.
     let (already_has_main, already_has_extern_crate, found_macro) = with_globals(edition, || {
-        use crate::syntax::{parse::{self, ParseSess}, source_map::FilePathMapping};
+        use crate::syntax::{parse, sess::ParseSess, source_map::FilePathMapping};
         use errors::emitter::EmitterWriter;
         use errors::Handler;
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b6a90e1fb98..70c30687dab 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -8,7 +8,7 @@ use rustc::middle::privacy::AccessLevel;
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::ty::TyCtxt;
 use syntax::ast;
-use syntax::ext::base::MacroKind;
+use syntax_expand::base::MacroKind;
 use syntax::source_map::Spanned;
 use syntax::symbol::sym;
 use syntax_pos::{self, Span};
diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs
index d981740780e..f2e9be14c8d 100644
--- a/src/libserialize/collection_impls.rs
+++ b/src/libserialize/collection_impls.rs
@@ -143,7 +143,7 @@ impl<T> Decodable for BTreeSet<T>
 }
 
 impl<K, V, S> Encodable for HashMap<K, V, S>
-    where K: Encodable + Hash + Eq,
+    where K: Encodable + Eq,
           V: Encodable,
           S: BuildHasher,
 {
@@ -180,7 +180,7 @@ impl<K, V, S> Decodable for HashMap<K, V, S>
 }
 
 impl<T, S> Encodable for HashSet<T, S>
-    where T: Encodable + Hash + Eq,
+    where T: Encodable + Eq,
           S: BuildHasher,
 {
     fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 483f2ba52ec..6dcda986310 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -327,7 +327,31 @@ impl CString {
     /// [`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())
+        trait SpecIntoVec {
+            fn into_vec(self) -> Vec<u8>;
+        }
+        impl<T: Into<Vec<u8>>> SpecIntoVec for T {
+            default fn into_vec(self) -> Vec<u8> {
+                self.into()
+            }
+        }
+        // Specialization for avoiding reallocation.
+        impl SpecIntoVec for &'_ [u8] {
+            fn into_vec(self) -> Vec<u8> {
+                let mut v = Vec::with_capacity(self.len() + 1);
+                v.extend(self);
+                v
+            }
+        }
+        impl SpecIntoVec for &'_ str {
+            fn into_vec(self) -> Vec<u8> {
+                let mut v = Vec::with_capacity(self.len() + 1);
+                v.extend(self.as_bytes());
+                v
+            }
+        }
+
+        Self::_new(SpecIntoVec::into_vec(t))
     }
 
     fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index fc26dcb3211..6595f54162f 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1090,13 +1090,14 @@ impl Metadata {
 
     /// Returns the creation time listed in this metadata.
     ///
-    /// The returned value corresponds to the `birthtime` field of `stat` on
-    /// Unix platforms and the `ftCreationTime` field on Windows platforms.
+    /// The returned value corresponds to the `btime` field of `statx` on
+    /// Linux kernel starting from to 4.11, the `birthtime` field of `stat` on other
+    /// Unix platforms, and the `ftCreationTime` field on Windows platforms.
     ///
     /// # Errors
     ///
     /// This field may not be available on all platforms, and will return an
-    /// `Err` on platforms where it is not available.
+    /// `Err` on platforms or filesystems where it is not available.
     ///
     /// # Examples
     ///
@@ -1109,7 +1110,7 @@ impl Metadata {
     ///     if let Ok(time) = metadata.created() {
     ///         println!("{:?}", time);
     ///     } else {
-    ///         println!("Not supported on this platform");
+    ///         println!("Not supported on this platform or filesystem");
     ///     }
     ///     Ok(())
     /// }
@@ -3443,5 +3444,18 @@ mod tests {
             check!(a.created());
             check!(b.created());
         }
+
+        if cfg!(target_os = "linux") {
+            // Not always available
+            match (a.created(), b.created()) {
+                (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
+                (Err(e1), Err(e2)) if e1.kind() == ErrorKind::Other &&
+                                      e2.kind() == ErrorKind::Other => {}
+                (a, b) => panic!(
+                    "creation time must be always supported or not supported: {:?} {:?}",
+                    a, b,
+                ),
+            }
+        }
     }
 }
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index c798ee0e220..6574ef13db9 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -762,7 +762,7 @@ pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write +
 /// otherwise. `label` identifies the stream in a panic message.
 ///
 /// This function is used to print error messages, so it takes extra
-/// care to avoid causing a panic when `local_stream` is unusable.
+/// care to avoid causing a panic when `local_s` is unusable.
 /// For instance, if the TLS key for the local stream is
 /// already destroyed, or if the local stream is locked by another
 /// thread, it will just fall back to the global stream.
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index a8dfe924fdf..ab8a55660cb 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -33,9 +33,72 @@ mod as_keyword { }
 //
 /// Exit early from a loop.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// When `break` is encountered, execution of the associated loop body is
+/// immediately terminated.
+///
+/// ```rust
+/// let mut last = 0;
+///
+/// for x in 1..100 {
+///     if x > 12 {
+///         break;
+///     }
+///     last = x;
+/// }
+///
+/// assert_eq!(last, 12);
+/// println!("{}", last);
+/// ```
+///
+/// A break expression is normally associated with the innermost loop enclosing the
+/// `break` but a label can be used to specify which enclosing loop is affected.
+///
+///```rust
+/// 'outer: for i in 1..=5 {
+///     println!("outer iteration (i): {}", i);
+///
+///     'inner: for j in 1..=200 {
+///         println!("    inner iteration (j): {}", j);
+///         if j >= 3 {
+///             // breaks from inner loop, let's outer loop continue.
+///             break;
+///         }
+///         if i >= 2 {
+///             // breaks from outer loop, and directly to "Bye".
+///             break 'outer;
+///         }
+///     }
+/// }
+/// println!("Bye.");
+///```
+///
+/// When associated with `loop`, a break expression may be used to return a value from that loop.
+/// This is only valid with `loop` and not with any other type of loop.
+/// If no value is specified, `break;` returns `()`.
+/// Every `break` within a loop must return the same type.
+///
+/// ```rust
+/// let (mut a, mut b) = (1, 1);
+/// let result = loop {
+///     if b > 10 {
+///         break b;
+///     }
+///     let c = a + b;
+///     a = b;
+///     b = c;
+/// };
+/// // first number in Fibonacci sequence over 10:
+/// assert_eq!(result, 13);
+/// println!("{}", result);
+/// ```
+///
+/// For more details consult the [Reference on "break expression"] and the [Reference on "break and
+/// loop values"].
+///
+/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions
+/// [Reference on "break and loop values"]:
+/// ../reference/expressions/loop-expr.html#break-and-loop-values
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
 mod break_keyword { }
 
 #[doc(keyword = "const")]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index af6cb656444..93d3e4ea3df 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -275,6 +275,7 @@
 #![feature(link_args)]
 #![feature(linkage)]
 #![feature(log_syntax)]
+#![feature(manually_drop_take)]
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(needs_panic_runtime)]
@@ -297,6 +298,7 @@
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
 #![feature(slice_patterns)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stdsimd)]
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index 46bbd8855de..a9e4457f423 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -202,7 +202,7 @@ impl UdpSocket {
     ///
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
     /// assert_eq!(socket.peer_addr().unwrap_err().kind(),
-    ///            ::std::io::ErrorKind::NotConnected);
+    ///            std::io::ErrorKind::NotConnected);
     /// ```
     #[stable(feature = "udp_peer_addr", since = "1.40.0")]
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index 24c693790e8..577673b7e40 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -264,7 +264,7 @@ impl RefUnwindSafe for atomic::AtomicI128 {}
 #[cfg(target_has_atomic_load_store = "ptr")]
 #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 impl RefUnwindSafe for atomic::AtomicUsize {}
-#[cfg(target_hastarget_has_atomic_load_store_atomic = "8")]
+#[cfg(target_has_atomic_load_store = "8")]
 #[unstable(feature = "integer_atomics", issue = "32976")]
 impl RefUnwindSafe for atomic::AtomicU8 {}
 #[cfg(target_has_atomic_load_store = "16")]
diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs
index 638ce1679b8..2dde81bb0ec 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -12,8 +12,7 @@ use core::panic::{BoxMeUp, PanicInfo, Location};
 use crate::any::Any;
 use crate::fmt;
 use crate::intrinsics;
-use crate::mem;
-use crate::ptr;
+use crate::mem::{self, ManuallyDrop};
 use crate::raw;
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::stdio::panic_output;
@@ -227,10 +226,9 @@ pub use realstd::rt::update_panic_count;
 
 /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
 pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
-    #[allow(unions_with_drop_fields)]
     union Data<F, R> {
-        f: F,
-        r: R,
+        f: ManuallyDrop<F>,
+        r: ManuallyDrop<R>,
     }
 
     // We do some sketchy operations with ownership here for the sake of
@@ -261,7 +259,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     let mut any_data = 0;
     let mut any_vtable = 0;
     let mut data = Data {
-        f,
+        f: ManuallyDrop::new(f)
     };
 
     let r = __rust_maybe_catch_panic(do_call::<F, R>,
@@ -271,7 +269,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
 
     return if r == 0 {
         debug_assert!(update_panic_count(0) == 0);
-        Ok(data.r)
+        Ok(ManuallyDrop::into_inner(data.r))
     } else {
         update_panic_count(-1);
         debug_assert!(update_panic_count(0) == 0);
@@ -284,8 +282,9 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
     fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
         unsafe {
             let data = data as *mut Data<F, R>;
-            let f = ptr::read(&mut (*data).f);
-            ptr::write(&mut (*data).r, f());
+            let data = &mut (*data);
+            let f = ManuallyDrop::take(&mut data.f);
+            data.r = ManuallyDrop::new(f());
         }
     }
 }
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index da136ca6bf6..4b0cf8312f1 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1488,12 +1488,12 @@ impl Child {
 /// }
 ///
 /// fn main() {
-///     ::std::process::exit(match run_app() {
-///        Ok(_) => 0,
-///        Err(err) => {
-///            eprintln!("error: {:?}", err);
-///            1
-///        }
+///     std::process::exit(match run_app() {
+///         Ok(_) => 0,
+///         Err(err) => {
+///             eprintln!("error: {:?}", err);
+///             1
+///         }
 ///     });
 /// }
 /// ```
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index e529b8c4227..e28fbca7fa1 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -60,10 +60,9 @@ use crate::thread::{self, Thread};
 
 /// A synchronization primitive which can be used to run a one-time global
 /// initialization. Useful for one-time initialization for FFI or related
-/// functionality. This type can only be constructed with the [`ONCE_INIT`]
-/// value or the equivalent [`Once::new`] constructor.
+/// functionality. This type can only be constructed with the [`Once::new`]
+/// constructor.
 ///
-/// [`ONCE_INIT`]: constant.ONCE_INIT.html
 /// [`Once::new`]: struct.Once.html#method.new
 ///
 /// # Examples
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
index 952ba40ee87..d7e733b7fa0 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -10,7 +10,8 @@
 // fallback implementation to use as well.
 //
 // Due to rust-lang/rust#18804, make sure this is not generic!
-#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit", target_os = "redox"))]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit", target_os = "redox",
+          target_os = "emscripten"))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
     use crate::mem;
     use crate::sys_common::thread_local::register_dtor_fallback;
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index ac43526b50f..ba611a6b7e7 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -71,22 +71,7 @@ impl FileDesc {
         #[cfg(target_os = "android")]
         use super::android::cvt_pread64;
 
-        #[cfg(target_os = "emscripten")]
-        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
-            -> io::Result<isize>
-        {
-            use crate::convert::TryInto;
-            use libc::pread64;
-            // pread64 on emscripten actually takes a 32 bit offset
-            if let Ok(o) = offset.try_into() {
-                cvt(pread64(fd, buf, count, o))
-            } else {
-                Err(io::Error::new(io::ErrorKind::InvalidInput,
-                                   "cannot pread >2GB"))
-            }
-        }
-
-        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
+        #[cfg(not(target_os = "android"))]
         unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
@@ -128,22 +113,7 @@ impl FileDesc {
         #[cfg(target_os = "android")]
         use super::android::cvt_pwrite64;
 
-        #[cfg(target_os = "emscripten")]
-        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
-            -> io::Result<isize>
-        {
-            use crate::convert::TryInto;
-            use libc::pwrite64;
-            // pwrite64 on emscripten actually takes a 32 bit offset
-            if let Ok(o) = offset.try_into() {
-                cvt(pwrite64(fd, buf, count, o))
-            } else {
-                Err(io::Error::new(io::ErrorKind::InvalidInput,
-                                   "cannot pwrite >2GB"))
-            }
-        }
-
-        #[cfg(not(any(target_os = "android", target_os = "emscripten")))]
+        #[cfg(not(target_os = "android"))]
         unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
             -> io::Result<isize>
         {
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 3b1eb86b84f..39cc120594a 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -41,11 +41,138 @@ pub use crate::sys_common::fs::remove_dir_all;
 
 pub struct File(FileDesc);
 
-#[derive(Clone)]
-pub struct FileAttr {
-    stat: stat64,
+// FIXME: This should be available on Linux with all `target_arch` and `target_env`.
+// https://github.com/rust-lang/libc/issues/1545
+macro_rules! cfg_has_statx {
+    ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => {
+        cfg_if::cfg_if! {
+            if #[cfg(all(target_os = "linux", target_env = "gnu", any(
+                target_arch = "x86",
+                target_arch = "arm",
+                // target_arch = "mips",
+                target_arch = "powerpc",
+                target_arch = "x86_64",
+                // target_arch = "aarch64",
+                target_arch = "powerpc64",
+                // target_arch = "mips64",
+                // target_arch = "s390x",
+                target_arch = "sparc64",
+            )))] {
+                $($then_tt)*
+            } else {
+                $($else_tt)*
+            }
+        }
+    };
+    ($($block_inner:tt)*) => {
+        #[cfg(all(target_os = "linux", target_env = "gnu", any(
+            target_arch = "x86",
+            target_arch = "arm",
+            // target_arch = "mips",
+            target_arch = "powerpc",
+            target_arch = "x86_64",
+            // target_arch = "aarch64",
+            target_arch = "powerpc64",
+            // target_arch = "mips64",
+            // target_arch = "s390x",
+            target_arch = "sparc64",
+        )))]
+        {
+            $($block_inner)*
+        }
+    };
 }
 
+cfg_has_statx! {{
+    #[derive(Clone)]
+    pub struct FileAttr {
+        stat: stat64,
+        statx_extra_fields: Option<StatxExtraFields>,
+    }
+
+    #[derive(Clone)]
+    struct StatxExtraFields {
+        // This is needed to check if btime is supported by the filesystem.
+        stx_mask: u32,
+        stx_btime: libc::statx_timestamp,
+    }
+
+    // We prefer `statx` on Linux if available, which contains file creation time.
+    // Default `stat64` contains no creation time.
+    unsafe fn try_statx(
+        fd: c_int,
+        path: *const libc::c_char,
+        flags: i32,
+        mask: u32,
+    ) -> Option<io::Result<FileAttr>> {
+        use crate::sync::atomic::{AtomicBool, Ordering};
+
+        // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`
+        // We store the availability in a global to avoid unnecessary syscalls
+        static HAS_STATX: AtomicBool = AtomicBool::new(true);
+        syscall! {
+            fn statx(
+                fd: c_int,
+                pathname: *const libc::c_char,
+                flags: c_int,
+                mask: libc::c_uint,
+                statxbuf: *mut libc::statx
+            ) -> c_int
+        }
+
+        if !HAS_STATX.load(Ordering::Relaxed) {
+            return None;
+        }
+
+        let mut buf: libc::statx = mem::zeroed();
+        let ret = cvt(statx(fd, path, flags, mask, &mut buf));
+        match ret {
+            Err(err) => match err.raw_os_error() {
+                Some(libc::ENOSYS) => {
+                    HAS_STATX.store(false, Ordering::Relaxed);
+                    return None;
+                }
+                _ => return Some(Err(err)),
+            }
+            Ok(_) => {
+                // We cannot fill `stat64` exhaustively because of private padding fields.
+                let mut stat: stat64 = mem::zeroed();
+                // `c_ulong` on gnu-mips, `dev_t` otherwise
+                stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _;
+                stat.st_ino = buf.stx_ino as libc::ino64_t;
+                stat.st_nlink = buf.stx_nlink as libc::nlink_t;
+                stat.st_mode = buf.stx_mode as libc::mode_t;
+                stat.st_uid = buf.stx_uid as libc::uid_t;
+                stat.st_gid = buf.stx_gid as libc::gid_t;
+                stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _;
+                stat.st_size = buf.stx_size as off64_t;
+                stat.st_blksize = buf.stx_blksize as libc::blksize_t;
+                stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t;
+                stat.st_atime = buf.stx_atime.tv_sec as libc::time_t;
+                // `i64` on gnu-x86_64-x32, `c_ulong` otherwise.
+                stat.st_atime_nsec = buf.stx_atime.tv_nsec as _;
+                stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t;
+                stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _;
+                stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t;
+                stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _;
+
+                let extra = StatxExtraFields {
+                    stx_mask: buf.stx_mask,
+                    stx_btime: buf.stx_btime,
+                };
+
+                Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
+            }
+        }
+    }
+
+} else {
+    #[derive(Clone)]
+    pub struct FileAttr {
+        stat: stat64,
+    }
+}}
+
 // all DirEntry's will have a reference to this struct
 struct InnerReadDir {
     dirp: Dir,
@@ -97,6 +224,20 @@ pub struct FileType { mode: mode_t }
 #[derive(Debug)]
 pub struct DirBuilder { mode: mode_t }
 
+cfg_has_statx! {{
+    impl FileAttr {
+        fn from_stat64(stat: stat64) -> Self {
+            Self { stat, statx_extra_fields: None }
+        }
+    }
+} else {
+    impl FileAttr {
+        fn from_stat64(stat: stat64) -> Self {
+            Self { stat }
+        }
+    }
+}}
+
 impl FileAttr {
     pub fn size(&self) -> u64 { self.stat.st_size as u64 }
     pub fn perm(&self) -> FilePermissions {
@@ -164,6 +305,22 @@ impl FileAttr {
                   target_os = "macos",
                   target_os = "ios")))]
     pub fn created(&self) -> io::Result<SystemTime> {
+        cfg_has_statx! {
+            if let Some(ext) = &self.statx_extra_fields {
+                return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
+                    Ok(SystemTime::from(libc::timespec {
+                        tv_sec: ext.stx_btime.tv_sec as libc::time_t,
+                        tv_nsec: ext.stx_btime.tv_nsec as _,
+                    }))
+                } else {
+                    Err(io::Error::new(
+                        io::ErrorKind::Other,
+                        "creation time is not available for the filesystem",
+                    ))
+                };
+            }
+        }
+
         Err(io::Error::new(io::ErrorKind::Other,
                            "creation time is not available on this platform \
                             currently"))
@@ -306,12 +463,25 @@ impl DirEntry {
 
     #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
-        let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?;
+        let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?;
+        let name = self.entry.d_name.as_ptr();
+
+        cfg_has_statx! {
+            if let Some(ret) = unsafe { try_statx(
+                fd,
+                name,
+                libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT,
+                libc::STATX_ALL,
+            ) } {
+                return ret;
+            }
+        }
+
         let mut stat: stat64 = unsafe { mem::zeroed() };
         cvt(unsafe {
-            fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW)
+            fstatat64(fd, name, &mut stat, libc::AT_SYMLINK_NOFOLLOW)
         })?;
-        Ok(FileAttr { stat })
+        Ok(FileAttr::from_stat64(stat))
     }
 
     #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))]
@@ -517,11 +687,24 @@ impl File {
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
+        let fd = self.0.raw();
+
+        cfg_has_statx! {
+            if let Some(ret) = unsafe { try_statx(
+                fd,
+                b"\0" as *const _ as *const libc::c_char,
+                libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT,
+                libc::STATX_ALL,
+            ) } {
+                return ret;
+            }
+        }
+
         let mut stat: stat64 = unsafe { mem::zeroed() };
         cvt(unsafe {
-            fstat64(self.0.raw(), &mut stat)
+            fstat64(fd, &mut stat)
         })?;
-        Ok(FileAttr { stat })
+        Ok(FileAttr::from_stat64(stat))
     }
 
     pub fn fsync(&self) -> io::Result<()> {
@@ -602,8 +785,6 @@ impl File {
             SeekFrom::End(off) => (libc::SEEK_END, off),
             SeekFrom::Current(off) => (libc::SEEK_CUR, off),
         };
-        #[cfg(target_os = "emscripten")]
-        let pos = pos as i32;
         let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
         Ok(n as u64)
     }
@@ -798,20 +979,44 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
     let p = cstr(p)?;
+
+    cfg_has_statx! {
+        if let Some(ret) = unsafe { try_statx(
+            libc::AT_FDCWD,
+            p.as_ptr(),
+            libc::AT_STATX_SYNC_AS_STAT,
+            libc::STATX_ALL,
+        ) } {
+            return ret;
+        }
+    }
+
     let mut stat: stat64 = unsafe { mem::zeroed() };
     cvt(unsafe {
         stat64(p.as_ptr(), &mut stat)
     })?;
-    Ok(FileAttr { stat })
+    Ok(FileAttr::from_stat64(stat))
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
     let p = cstr(p)?;
+
+    cfg_has_statx! {
+        if let Some(ret) = unsafe { try_statx(
+            libc::AT_FDCWD,
+            p.as_ptr(),
+            libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT,
+            libc::STATX_ALL,
+        ) } {
+            return ret;
+        }
+    }
+
     let mut stat: stat64 = unsafe { mem::zeroed() };
     cvt(unsafe {
         lstat64(p.as_ptr(), &mut stat)
     })?;
-    Ok(FileAttr { stat })
+    Ok(FileAttr::from_stat64(stat))
 }
 
 pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs
index 28a504f1979..6ce41420284 100644
--- a/src/libstd/sys/wasi/thread.rs
+++ b/src/libstd/sys/wasi/thread.rs
@@ -31,10 +31,10 @@ impl Thread {
         let nanos = dur.as_nanos();
         assert!(nanos <= u64::max_value() as u128);
 
-        const CLOCK_ID: wasi::Userdata = 0x0123_45678;
+        const USERDATA: wasi::Userdata = 0x0123_45678;
 
         let clock = wasi::raw::__wasi_subscription_u_clock_t {
-            identifier: CLOCK_ID,
+            identifier: 0,
             clock_id: wasi::CLOCK_MONOTONIC,
             timeout: nanos as u64,
             precision: 0,
@@ -42,7 +42,7 @@ impl Thread {
         };
 
         let in_ = [wasi::Subscription {
-            userdata: 0,
+            userdata: USERDATA,
             type_: wasi::EVENTTYPE_CLOCK,
             u: wasi::raw::__wasi_subscription_u { clock: clock },
         }];
@@ -53,7 +53,7 @@ impl Thread {
         };
         match (res, event) {
             (Ok(1), wasi::Event {
-                userdata: CLOCK_ID,
+                userdata: USERDATA,
                 error: 0,
                 type_: wasi::EVENTTYPE_CLOCK,
                 ..
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 204f6af5fc1..4160123c9a2 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -412,7 +412,7 @@ impl File {
 
     pub fn duplicate(&self) -> io::Result<File> {
         Ok(File {
-            handle: self.handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?,
+            handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?,
         })
     }
 
diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs
index d734f412bf8..3753269adfe 100644
--- a/src/libstd/sys_common/os_str_bytes.rs
+++ b/src/libstd/sys_common/os_str_bytes.rs
@@ -193,7 +193,7 @@ impl Slice {
 pub trait OsStringExt {
     /// Creates an [`OsString`] from a byte vector.
     ///
-    /// See the module docmentation for an example.
+    /// See the module documentation for an example.
     ///
     /// [`OsString`]: ../../../ffi/struct.OsString.html
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -201,7 +201,7 @@ pub trait OsStringExt {
 
     /// Yields the underlying byte vector of this [`OsString`].
     ///
-    /// See the module docmentation for an example.
+    /// See the module documentation for an example.
     ///
     /// [`OsString`]: ../../../ffi/struct.OsString.html
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -226,14 +226,14 @@ pub trait OsStrExt {
     #[stable(feature = "rust1", since = "1.0.0")]
     /// Creates an [`OsStr`] from a byte slice.
     ///
-    /// See the module docmentation for an example.
+    /// See the module documentation for an example.
     ///
     /// [`OsStr`]: ../../../ffi/struct.OsStr.html
     fn from_bytes(slice: &[u8]) -> &Self;
 
     /// Gets the underlying byte view of the [`OsStr`] slice.
     ///
-    /// See the module docmentation for an example.
+    /// See the module documentation for an example.
     ///
     /// [`OsStr`]: ../../../ffi/struct.OsStr.html
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 023952042e6..51a62cd0658 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2,31 +2,29 @@
 
 pub use GenericArgs::*;
 pub use UnsafeSource::*;
-pub use crate::symbol::{Ident, Symbol as Name};
 pub use crate::util::parser::ExprPrecedence;
 
-use crate::ext::hygiene::ExpnId;
 use crate::parse::token::{self, DelimToken};
-use crate::print::pprust;
 use crate::ptr::P;
 use crate::source_map::{dummy_spanned, respan, Spanned};
-use crate::symbol::{kw, sym, Symbol};
 use crate::tokenstream::TokenStream;
-use crate::ThinVec;
+
+use rustc_target::spec::abi::Abi;
+pub use rustc_target::abi::FloatTy;
+
+use syntax_pos::{Span, DUMMY_SP, ExpnId};
+use syntax_pos::symbol::{kw, sym, Symbol};
+pub use syntax_pos::symbol::{Ident, Symbol as Name};
 
 use rustc_index::vec::Idx;
 #[cfg(target_arch = "x86_64")]
 use rustc_data_structures::static_assert_size;
-use rustc_target::spec::abi::Abi;
-use syntax_pos::{Span, DUMMY_SP};
-
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_serialize::{self, Decoder, Encoder};
 use std::fmt;
 
-pub use rustc_target::abi::FloatTy;
-
 #[cfg(test)]
 mod tests;
 
@@ -70,7 +68,7 @@ impl fmt::Display for Lifetime {
 /// along with a bunch of supporting information.
 ///
 /// E.g., `std::cmp::PartialEq`.
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Path {
     pub span: Span,
     /// The segments in the path: the things separated by `::`.
@@ -86,18 +84,6 @@ impl PartialEq<Symbol> for Path {
     }
 }
 
-impl fmt::Debug for Path {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "path({})", pprust::path_to_string(self))
-    }
-}
-
-impl fmt::Display for Path {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", pprust::path_to_string(self))
-    }
-}
-
 impl Path {
     // Convert a span and an identifier to the corresponding
     // one-segment path.
@@ -507,19 +493,13 @@ pub struct Block {
     pub span: Span,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Pat {
     pub id: NodeId,
     pub kind: PatKind,
     pub span: Span,
 }
 
-impl fmt::Debug for Pat {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "pat({}: {})", self.id, pprust::pat_to_string(self))
-    }
-}
-
 impl Pat {
     /// Attempt reparsing the pattern as a type.
     /// This is intended for use by diagnostics.
@@ -831,7 +811,7 @@ impl UnOp {
 }
 
 /// A statement
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Stmt {
     pub id: NodeId,
     pub kind: StmtKind,
@@ -865,18 +845,7 @@ impl Stmt {
     }
 }
 
-impl fmt::Debug for Stmt {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "stmt({}: {})",
-            self.id.to_string(),
-            pprust::stmt_to_string(self)
-        )
-    }
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum StmtKind {
     /// A local (let) binding.
     Local(P<Local>),
@@ -973,7 +942,7 @@ pub struct AnonConst {
 }
 
 /// An expression.
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Expr {
     pub id: NodeId,
     pub kind: ExprKind,
@@ -1100,12 +1069,6 @@ impl Expr {
     }
 }
 
-impl fmt::Debug for Expr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "expr({}: {})", self.id, pprust::expr_to_string(self))
-    }
-}
-
 /// Limit types of a range (inclusive or exclusive)
 #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)]
 pub enum RangeLimits {
@@ -1342,6 +1305,7 @@ impl MacroDef {
     }
 }
 
+// Clippy uses Hash and PartialEq
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)]
 pub enum StrStyle {
     /// A regular string, like `"foo"`.
@@ -1364,6 +1328,7 @@ pub struct Lit {
     pub span: Span,
 }
 
+// Clippy uses Hash and PartialEq
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)]
 pub enum LitIntType {
     Signed(IntTy),
@@ -1374,6 +1339,7 @@ pub enum LitIntType {
 /// Literal kind.
 ///
 /// E.g., `"foo"`, `42`, `12.34`, or `bool`.
+// Clippy uses Hash and PartialEq
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)]
 pub enum LitKind {
     /// A string literal (`"foo"`).
@@ -1660,19 +1626,13 @@ pub enum AssocTyConstraintKind {
     },
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Ty {
     pub id: NodeId,
     pub kind: TyKind,
     pub span: Span,
 }
 
-impl fmt::Debug for Ty {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "type({})", pprust::ty_to_string(self))
-    }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct BareFnTy {
     pub unsafety: Unsafety,
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 2a8e6b2cc95..84c86c9651f 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -2,9 +2,9 @@
 
 use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
 use crate::early_buffered_lints::BufferedEarlyLintId;
-use crate::ext::base::ExtCtxt;
 use crate::feature_gate::{Features, GatedCfg};
-use crate::parse::ParseSess;
+use crate::print::pprust;
+use crate::sess::ParseSess;
 
 use errors::{Applicability, Handler};
 use syntax_pos::hygiene::Transparency;
@@ -31,6 +31,10 @@ pub struct AttributeTemplate {
 }
 
 impl AttributeTemplate {
+    pub fn only_word() -> Self {
+        Self { word: true, list: None, name_value_str: None }
+    }
+
     /// Checks that the given meta-item is compatible with this template.
     fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
         match meta_item_kind {
@@ -80,7 +84,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
     }
 }
 
-#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum InlineAttr {
     None,
     Hint,
@@ -88,7 +92,7 @@ pub enum InlineAttr {
     Never,
 }
 
-#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -243,7 +247,11 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
             let meta = meta.as_ref().unwrap();
             let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                 if item.is_some() {
-                    handle_errors(sess, meta.span, AttrError::MultipleItem(meta.path.to_string()));
+                    handle_errors(
+                        sess,
+                        meta.span,
+                        AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
+                    );
                     return false
                 }
                 if let Some(v) = meta.value_str() {
@@ -271,7 +279,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                                     handle_errors(
                                         sess,
                                         mi.span,
-                                        AttrError::UnknownMetaItem(mi.path.to_string(), expected),
+                                        AttrError::UnknownMetaItem(
+                                            pprust::path_to_string(&mi.path),
+                                            expected,
+                                        ),
                                     );
                                     continue 'outer
                                 }
@@ -362,7 +373,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                                         sess,
                                         meta.span(),
                                         AttrError::UnknownMetaItem(
-                                            mi.path.to_string(),
+                                            pprust::path_to_string(&mi.path),
                                             &["feature", "reason", "issue", "soft"]
                                         ),
                                     );
@@ -434,7 +445,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                                             sess,
                                             meta.span(),
                                             AttrError::UnknownMetaItem(
-                                                mi.path.to_string(), &["since", "note"],
+                                                pprust::path_to_string(&mi.path),
+                                                &["since", "note"],
                                             ),
                                         );
                                         continue 'outer
@@ -597,8 +609,11 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
                     !eval_condition(mis[0].meta_item().unwrap(), sess, eval)
                 },
                 _ => {
-                    span_err!(sess.span_diagnostic, cfg.span, E0537,
-                              "invalid predicate `{}`", cfg.path);
+                    span_err!(
+                        sess.span_diagnostic, cfg.span, E0537,
+                        "invalid predicate `{}`",
+                        pprust::path_to_string(&cfg.path)
+                    );
                     false
                 }
             }
@@ -609,8 +624,7 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
     }
 }
 
-
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, Clone)]
 pub struct Deprecation {
     pub since: Option<Symbol>,
     pub note: Option<Symbol>,
@@ -653,7 +667,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
                 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                     if item.is_some() {
                         handle_errors(
-                            sess, meta.span, AttrError::MultipleItem(meta.path.to_string())
+                            sess,
+                            meta.span,
+                            AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
                         );
                         return false
                     }
@@ -691,8 +707,10 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
                                     handle_errors(
                                         sess,
                                         meta.span(),
-                                        AttrError::UnknownMetaItem(mi.path.to_string(),
-                                                                   &["since", "note"]),
+                                        AttrError::UnknownMetaItem(
+                                            pprust::path_to_string(&mi.path),
+                                            &["since", "note"],
+                                        ),
                                     );
                                     continue 'outer
                                 }
@@ -730,7 +748,7 @@ pub enum ReprAttr {
     ReprAlign(u32),
 }
 
-#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
+#[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
 pub enum IntType {
     SignedInt(ast::IntTy),
     UnsignedInt(ast::UintTy)
@@ -921,14 +939,7 @@ pub fn find_transparency(
     (transparency.map_or(fallback, |t| t.0), error)
 }
 
-pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
-    // All the built-in macro attributes are "words" at the moment.
-    let template = AttributeTemplate { word: true, list: None, name_value_str: None };
-    let attr = ecx.attribute(meta_item.clone());
-    check_builtin_attribute(ecx.parse_sess, &attr, name, template);
-}
-
-crate fn check_builtin_attribute(
+pub fn check_builtin_attribute(
     sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate
 ) {
     // Some special attributes like `cfg` must be checked
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 7bef693a5be..4aec5040881 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -16,12 +16,13 @@ use crate::mut_visit::visit_clobber;
 use crate::source_map::{BytePos, Spanned, DUMMY_SP};
 use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use crate::parse::parser::Parser;
-use crate::parse::{ParseSess, PResult};
+use crate::parse::PResult;
 use crate::parse::token::{self, Token};
 use crate::ptr::P;
+use crate::sess::ParseSess;
 use crate::symbol::{sym, Symbol};
 use crate::ThinVec;
-use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
+use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 use crate::GLOBALS;
 
 use log::debug;
@@ -279,7 +280,7 @@ impl Attribute {
         self.item.meta(self.span)
     }
 
-    pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
+    crate fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     {
         let mut parser = Parser::new(
@@ -297,24 +298,11 @@ impl Attribute {
         Ok(result)
     }
 
-    pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec<T>>
-        where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    {
+    pub fn parse_derive_paths<'a>(&self, sess: &'a ParseSess) -> PResult<'a, Vec<Path>> {
         if self.tokens.is_empty() {
             return Ok(Vec::new());
         }
-        self.parse(sess, |parser| {
-            parser.expect(&token::OpenDelim(token::Paren))?;
-            let mut list = Vec::new();
-            while !parser.eat(&token::CloseDelim(token::Paren)) {
-                list.push(f(parser)?);
-                if !parser.eat(&token::Comma) {
-                   parser.expect(&token::CloseDelim(token::Paren))?;
-                    break
-                }
-            }
-            Ok(list)
-        })
+        self.parse(sess, |p| p.parse_derive_paths())
     }
 
     pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
@@ -475,7 +463,7 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option
 }
 
 impl MetaItem {
-    fn tokens(&self) -> TokenStream {
+    fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
         let mut idents = vec![];
         let mut last_pos = BytePos(0 as u32);
         for (i, segment) in self.path.segments.iter().enumerate() {
@@ -489,8 +477,8 @@ impl MetaItem {
             idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
             last_pos = segment.ident.span.hi();
         }
-        self.kind.tokens(self.span).append_to_tree_and_joint_vec(&mut idents);
-        TokenStream::new(idents)
+        idents.extend(self.kind.token_trees_and_joints(self.span));
+        idents
     }
 
     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
@@ -549,13 +537,14 @@ impl MetaItem {
 }
 
 impl MetaItemKind {
-    pub fn tokens(&self, span: Span) -> TokenStream {
+    pub fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> {
         match *self {
-            MetaItemKind::Word => TokenStream::empty(),
+            MetaItemKind::Word => vec![],
             MetaItemKind::NameValue(ref lit) => {
-                let mut vec = vec![TokenTree::token(token::Eq, span).into()];
-                lit.tokens().append_to_tree_and_joint_vec(&mut vec);
-                TokenStream::new(vec)
+                vec![
+                    TokenTree::token(token::Eq, span).into(),
+                    lit.token_tree().into(),
+                ]
             }
             MetaItemKind::List(ref list) => {
                 let mut tokens = Vec::new();
@@ -563,17 +552,26 @@ impl MetaItemKind {
                     if i > 0 {
                         tokens.push(TokenTree::token(token::Comma, span).into());
                     }
-                    item.tokens().append_to_tree_and_joint_vec(&mut tokens);
+                    tokens.extend(item.token_trees_and_joints())
                 }
-                TokenTree::Delimited(
-                    DelimSpan::from_single(span),
-                    token::Paren,
-                    TokenStream::new(tokens).into(),
-                ).into()
+                vec![
+                    TokenTree::Delimited(
+                        DelimSpan::from_single(span),
+                        token::Paren,
+                        TokenStream::new(tokens).into(),
+                    ).into()
+                ]
             }
         }
     }
 
+    // Premature conversions of `TokenTree`s to `TokenStream`s can hurt
+    // performance. Do not use this function if `token_trees_and_joints()` can
+    // be used instead.
+    pub fn tokens(&self, span: Span) -> TokenStream {
+        TokenStream::new(self.token_trees_and_joints(span))
+    }
+
     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind>
         where I: Iterator<Item = TokenTree>,
     {
@@ -615,10 +613,10 @@ impl NestedMetaItem {
         }
     }
 
-    fn tokens(&self) -> TokenStream {
+    fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
         match *self {
-            NestedMetaItem::MetaItem(ref item) => item.tokens(),
-            NestedMetaItem::Literal(ref lit) => lit.tokens(),
+            NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(),
+            NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()],
         }
     }
 
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 2923cc86ba0..54dc95291d6 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -10,8 +10,8 @@ use crate::attr;
 use crate::ast;
 use crate::edition::Edition;
 use crate::mut_visit::*;
-use crate::parse::{token, ParseSess};
 use crate::ptr::P;
+use crate::sess::ParseSess;
 use crate::symbol::sym;
 use crate::util::map_in_place::MapInPlace;
 
@@ -56,6 +56,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition,
     (krate, features)
 }
 
+#[macro_export]
 macro_rules! configure {
     ($this:ident, $node:ident) => {
         match $this.configure($node) {
@@ -111,25 +112,7 @@ impl<'a> StripUnconfigured<'a> {
             return vec![];
         }
 
-        let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
-            parser.expect(&token::OpenDelim(token::Paren))?;
-
-            let cfg_predicate = parser.parse_meta_item()?;
-            parser.expect(&token::Comma)?;
-
-            // Presumably, the majority of the time there will only be one attr.
-            let mut expanded_attrs = Vec::with_capacity(1);
-
-            while !parser.check(&token::CloseDelim(token::Paren)) {
-                let lo = parser.token.span.lo();
-                let item = parser.parse_attr_item()?;
-                expanded_attrs.push((item, parser.prev_span.with_lo(lo)));
-                parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
-            }
-
-            parser.expect(&token::CloseDelim(token::Paren))?;
-            Ok((cfg_predicate, expanded_attrs))
-        }) {
+        let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |p| p.parse_cfg_attr()) {
             Ok(result) => result,
             Err(mut e) => {
                 e.emit();
diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs
index fc3f095856a..17ea4767520 100644
--- a/src/libsyntax/error_codes.rs
+++ b/src/libsyntax/error_codes.rs
@@ -295,6 +295,33 @@ named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the
 same directory.
 "##,
 
+E0584: r##"
+A doc comment that is not attached to anything has been encountered.
+
+Erroneous code example:
+
+```compile_fail,E0584
+trait Island {
+    fn lost();
+
+    /// I'm lost!
+}
+```
+
+A little reminder: a doc comment has to be placed before the item it's supposed
+to document. So if you want to document the `Island` trait, you need to put a
+doc comment before it, not inside it. Same goes for the `lost` method: the doc
+comment needs to be before it:
+
+```
+/// I'm THE island!
+trait Island {
+    /// I'm lost!
+    fn lost();
+}
+```
+"##,
+
 E0585: r##"
 A documentation comment that doesn't document anything was found.
 
@@ -494,7 +521,6 @@ features in the `-Z allow_features` flag.
     E0549,
     E0553, // multiple rustc_const_unstable attributes
 //  E0555, // replaced with a generic attribute input check
-    E0584, // file for module `..` found at both .. and ..
     E0629, // missing 'feature' (rustc_const_unstable)
     // rustc_const_unstable attribute must be paired with stable/unstable
     // attribute
diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs
index ab1620b9524..7dd6ae90d9a 100644
--- a/src/libsyntax/feature_gate/builtin_attrs.rs
+++ b/src/libsyntax/feature_gate/builtin_attrs.rs
@@ -9,8 +9,8 @@ use super::active::Features;
 
 use crate::ast;
 use crate::attr::AttributeTemplate;
+use crate::sess::ParseSess;
 use crate::symbol::{Symbol, sym};
-use crate::parse::ParseSess;
 
 use syntax_pos::Span;
 use rustc_data_structures::fx::FxHashMap;
@@ -286,7 +286,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     (
         sym::plugin_registrar, Normal, template!(Word),
         Gated(
-            Stability::Deprecated("https://github.com/rust-lang/rust/issues/29597", None),
+            Stability::Deprecated(
+                "https://github.com/rust-lang/rust/pull/64675",
+                Some("may be removed in a future compiler version"),
+            ),
             sym::plugin_registrar,
             "compiler plugins are deprecated",
             cfg_fn!(plugin_registrar)
@@ -295,7 +298,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     (
         sym::plugin, CrateLevel, template!(List: "name|name(args)"),
         Gated(
-            Stability::Deprecated("https://github.com/rust-lang/rust/issues/29597", None),
+            Stability::Deprecated(
+                "https://github.com/rust-lang/rust/pull/64675",
+                Some("may be removed in a future compiler version"),
+            ),
             sym::plugin,
             "compiler plugins are deprecated",
             cfg_fn!(plugin)
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 6008f8f3005..172511f0f09 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -5,14 +5,14 @@ use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 
 use crate::ast::{
     self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
-    PatKind, RangeEnd,
+    PatKind, RangeEnd, VariantData,
 };
 use crate::attr::{self, check_builtin_attribute};
 use crate::source_map::Spanned;
 use crate::edition::{ALL_EDITIONS, Edition};
 use crate::visit::{self, FnKind, Visitor};
-use crate::parse::{token, ParseSess};
-use crate::parse::parser::Parser;
+use crate::parse::token;
+use crate::sess::ParseSess;
 use crate::symbol::{Symbol, sym};
 use crate::tokenstream::TokenTree;
 
@@ -56,7 +56,7 @@ macro_rules! gate_feature {
     };
 }
 
-crate fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
+pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
     PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
 }
 
@@ -246,6 +246,51 @@ impl<'a> PostExpansionVisitor<'a> {
             Abi::System => {}
         }
     }
+
+    fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
+        let has_fields = variants.iter().any(|variant| match variant.data {
+            VariantData::Tuple(..) | VariantData::Struct(..) => true,
+            VariantData::Unit(..) => false,
+        });
+
+        let discriminant_spans = variants.iter().filter(|variant| match variant.data {
+            VariantData::Tuple(..) | VariantData::Struct(..) => false,
+            VariantData::Unit(..) => true,
+        })
+        .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
+        .collect::<Vec<_>>();
+
+        if !discriminant_spans.is_empty() && has_fields {
+            let mut err = feature_err(
+                self.parse_sess,
+                sym::arbitrary_enum_discriminant,
+                discriminant_spans.clone(),
+                crate::feature_gate::GateIssue::Language,
+                "custom discriminant values are not allowed in enums with tuple or struct variants",
+            );
+            for sp in discriminant_spans {
+                err.span_label(sp, "disallowed custom discriminant");
+            }
+            for variant in variants.iter() {
+                match &variant.data {
+                    VariantData::Struct(..) => {
+                        err.span_label(
+                            variant.span,
+                            "struct variant defined here",
+                        );
+                    }
+                    VariantData::Tuple(..) => {
+                        err.span_label(
+                            variant.span,
+                            "tuple variant defined here",
+                        );
+                    }
+                    VariantData::Unit(..) => {}
+                }
+            }
+            err.emit();
+        }
+    }
 }
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@@ -353,7 +398,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
 
                 let has_feature = self.features.arbitrary_enum_discriminant;
                 if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
-                    Parser::maybe_report_invalid_custom_discriminants(self.parse_sess, &variants);
+                    self.maybe_report_invalid_custom_discriminants(&variants);
                 }
             }
 
@@ -769,7 +814,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
             }
 
             if let Some(allowed) = allow_features.as_ref() {
-                if allowed.iter().find(|f| *f == name.as_str()).is_none() {
+                if allowed.iter().find(|&f| f == &name.as_str() as &str).is_none() {
                     span_err!(span_handler, mi.span(), E0725,
                               "the feature `{}` is not in the list of allowed features",
                               name);
diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs
index ca13ab36205..ba970618c0e 100644
--- a/src/libsyntax/feature_gate/mod.rs
+++ b/src/libsyntax/feature_gate/mod.rs
@@ -58,8 +58,7 @@ pub use builtin_attrs::{
     deprecated_attributes, is_builtin_attr,  is_builtin_attr_name,
 };
 pub use check::{
-    check_crate, get_features, feature_err, emit_feature_err,
+    check_crate, check_attribute, get_features, feature_err, emit_feature_err,
     Stability, GateIssue, UnstableFeatures,
     EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION,
 };
-crate use check::check_attribute;
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index 2423e1070fc..e3296788d9f 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -12,7 +12,7 @@
 use crate::source_map::{SourceMap, FilePathMapping};
 
 use errors::registry::Registry;
-use errors::{SubDiagnostic, CodeSuggestion, SourceMapper};
+use errors::{SubDiagnostic, CodeSuggestion, SourceMapper, SourceMapperDyn};
 use errors::{DiagnosticId, Applicability};
 use errors::emitter::{Emitter, HumanReadableErrorType};
 
@@ -89,8 +89,8 @@ impl JsonEmitter {
 }
 
 impl Emitter for JsonEmitter {
-    fn emit_diagnostic(&mut self, db: &errors::Diagnostic) {
-        let data = Diagnostic::from_errors_diagnostic(db, self);
+    fn emit_diagnostic(&mut self, diag: &errors::Diagnostic) {
+        let data = Diagnostic::from_errors_diagnostic(diag, self);
         let result = if self.pretty {
             writeln!(&mut self.dst, "{}", as_pretty_json(&data))
         } else {
@@ -113,6 +113,10 @@ impl Emitter for JsonEmitter {
         }
     }
 
+    fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> {
+        Some(&self.sm)
+    }
+
     fn should_show_explain(&self) -> bool {
         match self.json_rendered {
             HumanReadableErrorType::Short(_) => false,
@@ -205,10 +209,10 @@ struct ArtifactNotification<'a> {
 }
 
 impl Diagnostic {
-    fn from_errors_diagnostic(db: &errors::Diagnostic,
+    fn from_errors_diagnostic(diag: &errors::Diagnostic,
                                je: &JsonEmitter)
                                -> Diagnostic {
-        let sugg = db.suggestions.iter().map(|sugg| {
+        let sugg = diag.suggestions.iter().map(|sugg| {
             Diagnostic {
                 message: sugg.msg.clone(),
                 code: None,
@@ -237,30 +241,30 @@ impl Diagnostic {
         let output = buf.clone();
         je.json_rendered.new_emitter(
             Box::new(buf), Some(je.sm.clone()), false, None, je.external_macro_backtrace
-        ).ui_testing(je.ui_testing).emit_diagnostic(db);
+        ).ui_testing(je.ui_testing).emit_diagnostic(diag);
         let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
         let output = String::from_utf8(output).unwrap();
 
         Diagnostic {
-            message: db.message(),
-            code: DiagnosticCode::map_opt_string(db.code.clone(), je),
-            level: db.level.to_str(),
-            spans: DiagnosticSpan::from_multispan(&db.span, je),
-            children: db.children.iter().map(|c| {
+            message: diag.message(),
+            code: DiagnosticCode::map_opt_string(diag.code.clone(), je),
+            level: diag.level.to_str(),
+            spans: DiagnosticSpan::from_multispan(&diag.span, je),
+            children: diag.children.iter().map(|c| {
                 Diagnostic::from_sub_diagnostic(c, je)
             }).chain(sugg).collect(),
             rendered: Some(output),
         }
     }
 
-    fn from_sub_diagnostic(db: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
+    fn from_sub_diagnostic(diag: &SubDiagnostic, je: &JsonEmitter) -> Diagnostic {
         Diagnostic {
-            message: db.message(),
+            message: diag.message(),
             code: None,
-            level: db.level.to_str(),
-            spans: db.render_span.as_ref()
+            level: diag.level.to_str(),
+            spans: diag.render_span.as_ref()
                      .map(|sp| DiagnosticSpan::from_multispan(sp, je))
-                     .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)),
+                     .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, je)),
             children: vec![],
             rendered: None,
         }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 09a47795a82..3fa13f08d3a 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -13,17 +13,12 @@
 #![feature(crate_visibility_modifier)]
 #![feature(label_break_value)]
 #![feature(nll)]
-#![feature(proc_macro_diagnostic)]
-#![feature(proc_macro_internals)]
-#![feature(proc_macro_span)]
 #![feature(try_trait)]
 #![feature(slice_patterns)]
 #![feature(unicode_internals)]
 
 #![recursion_limit="256"]
 
-extern crate proc_macro;
-
 pub use errors;
 use rustc_data_structures::sync::Lock;
 use rustc_index::bit_set::GrowableBitSet;
@@ -34,26 +29,7 @@ use syntax_pos::edition::Edition;
 #[cfg(test)]
 mod tests;
 
-const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
-
-// A variant of 'try!' that panics on an Err. This is used as a crutch on the
-// way towards a non-panic!-prone parser. It should be used for fatal parsing
-// errors; eventually we plan to convert all code using panictry to just use
-// normal try.
-#[macro_export]
-macro_rules! panictry {
-    ($e:expr) => ({
-        use std::result::Result::{Ok, Err};
-        use errors::FatalError;
-        match $e {
-            Ok(e) => e,
-            Err(mut e) => {
-                e.emit();
-                FatalError.raise()
-            }
-        }
-    })
-}
+pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
 
 // A variant of 'panictry!' that works on a Vec<Diagnostic> instead of a single DiagnosticBuilder.
 macro_rules! panictry_buffer {
@@ -91,7 +67,7 @@ pub struct Globals {
 impl Globals {
     fn new(edition: Edition) -> Globals {
         Globals {
-            // We have no idea how many attributes their will be, so just
+            // We have no idea how many attributes there will be, so just
             // initiate the vectors with 0 bits. We'll grow them as necessary.
             used_attrs: Lock::new(GrowableBitSet::new_empty()),
             known_attrs: Lock::new(GrowableBitSet::new_empty()),
@@ -147,6 +123,7 @@ pub mod ptr;
 pub mod show_span;
 pub use syntax_pos::edition;
 pub use syntax_pos::symbol;
+pub mod sess;
 pub mod tokenstream;
 pub mod visit;
 
@@ -156,19 +133,4 @@ pub mod print {
     mod helpers;
 }
 
-pub mod ext {
-    mod placeholders;
-    mod proc_macro_server;
-
-    pub use syntax_pos::hygiene;
-    pub use mbe::macro_rules::compile_declarative_macro;
-    pub mod allocator;
-    pub mod base;
-    pub mod build;
-    pub mod expand;
-    pub mod proc_macro;
-
-    crate mod mbe;
-}
-
 pub mod early_buffered_lints;
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 3923b9f297b..60ee17d09b7 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -610,10 +610,8 @@ pub fn noop_visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
 }
 
 pub fn noop_visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
-    visit_opt(tts, |tts| {
-        let tts = Lrc::make_mut(tts);
-        visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree));
-    })
+    let tts = Lrc::make_mut(tts);
+    visit_vec(tts, |(tree, _is_joint)| vis.visit_tt(tree));
 }
 
 // Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index ac3feadce3a..e6dc9a4c134 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -1,5 +1,5 @@
-use crate::parse::ParseSess;
 use crate::parse::token::{self, Token, TokenKind};
+use crate::sess::ParseSess;
 use crate::symbol::{sym, Symbol};
 use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char};
 
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index e5ba7e45309..b4dd23c9f9b 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxHashMap;
 use syntax_pos::Span;
 
 use crate::print::pprust::token_to_string;
@@ -16,6 +17,7 @@ impl<'a> StringReader<'a> {
             unmatched_braces: Vec::new(),
             matching_delim_spans: Vec::new(),
             last_unclosed_found_span: None,
+            last_delim_empty_block_spans: FxHashMap::default()
         };
         let res = tt_reader.parse_all_token_trees();
         (res, tt_reader.unmatched_braces)
@@ -34,6 +36,7 @@ struct TokenTreesReader<'a> {
     /// Used only for error recovery when arriving to EOF with mismatched braces.
     matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
     last_unclosed_found_span: Option<Span>,
+    last_delim_empty_block_spans: FxHashMap<token::DelimToken, Span>
 }
 
 impl<'a> TokenTreesReader<'a> {
@@ -121,13 +124,20 @@ impl<'a> TokenTreesReader<'a> {
                     // Correct delimiter.
                     token::CloseDelim(d) if d == delim => {
                         let (open_brace, open_brace_span) = self.open_braces.pop().unwrap();
+                        let close_brace_span = self.token.span;
+
+                        if tts.is_empty() {
+                            let empty_block_span = open_brace_span.to(close_brace_span);
+                            self.last_delim_empty_block_spans.insert(delim, empty_block_span);
+                        }
+
                         if self.open_braces.len() == 0 {
                             // Clear up these spans to avoid suggesting them as we've found
                             // properly matched delimiters so far for an entire block.
                             self.matching_delim_spans.clear();
                         } else {
                             self.matching_delim_spans.push(
-                                (open_brace, open_brace_span, self.token.span),
+                                (open_brace, open_brace_span, close_brace_span),
                             );
                         }
                         // Parse the close delimiter.
@@ -193,13 +203,20 @@ impl<'a> TokenTreesReader<'a> {
                     tts.into()
                 ).into())
             },
-            token::CloseDelim(_) => {
+            token::CloseDelim(delim) => {
                 // An unexpected closing delimiter (i.e., there is no
                 // matching opening delimiter).
                 let token_str = token_to_string(&self.token);
                 let msg = format!("unexpected close delimiter: `{}`", token_str);
                 let mut err = self.string_reader.sess.span_diagnostic
                     .struct_span_err(self.token.span, &msg);
+
+                if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
+                    err.span_label(
+                        span,
+                        "this block is empty, you might have not meant to close it"
+                    );
+                }
                 err.span_label(self.token.span, "unexpected close delimiter");
                 Err(err)
             },
diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs
index 56a79bfe5d5..7952e293a53 100644
--- a/src/libsyntax/parse/literal.rs
+++ b/src/libsyntax/parse/literal.rs
@@ -1,14 +1,10 @@
 //! Code related to parsing literals.
 
 use crate::ast::{self, Lit, LitKind};
-use crate::parse::parser::Parser;
-use crate::parse::PResult;
-use crate::parse::token::{self, Token, TokenKind};
-use crate::print::pprust;
+use crate::parse::token::{self, Token};
 use crate::symbol::{kw, sym, Symbol};
-use crate::tokenstream::{TokenStream, TokenTree};
+use crate::tokenstream::TokenTree;
 
-use errors::{Applicability, Handler};
 use log::debug;
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::Span;
@@ -28,72 +24,6 @@ crate enum LitError {
     IntTooLarge,
 }
 
-impl LitError {
-    fn report(&self, diag: &Handler, lit: token::Lit, span: Span) {
-        let token::Lit { kind, suffix, .. } = lit;
-        match *self {
-            // `NotLiteral` is not an error by itself, so we don't report
-            // it and give the parser opportunity to try something else.
-            LitError::NotLiteral => {}
-            // `LexerError` *is* an error, but it was already reported
-            // by lexer, so here we don't report it the second time.
-            LitError::LexerError => {}
-            LitError::InvalidSuffix => {
-                expect_no_suffix(
-                    diag, span, &format!("{} {} literal", kind.article(), kind.descr()), suffix
-                );
-            }
-            LitError::InvalidIntSuffix => {
-                let suf = suffix.expect("suffix error with no suffix").as_str();
-                if looks_like_width_suffix(&['i', 'u'], &suf) {
-                    // If it looks like a width, try to be helpful.
-                    let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
-                    diag.struct_span_err(span, &msg)
-                        .help("valid widths are 8, 16, 32, 64 and 128")
-                        .emit();
-                } else {
-                    let msg = format!("invalid suffix `{}` for integer literal", suf);
-                    diag.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{}`", suf))
-                        .help("the suffix must be one of the integral types (`u32`, `isize`, etc)")
-                        .emit();
-                }
-            }
-            LitError::InvalidFloatSuffix => {
-                let suf = suffix.expect("suffix error with no suffix").as_str();
-                if looks_like_width_suffix(&['f'], &suf) {
-                    // If it looks like a width, try to be helpful.
-                    let msg = format!("invalid width `{}` for float literal", &suf[1..]);
-                    diag.struct_span_err(span, &msg)
-                        .help("valid widths are 32 and 64")
-                        .emit();
-                } else {
-                    let msg = format!("invalid suffix `{}` for float literal", suf);
-                    diag.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{}`", suf))
-                        .help("valid suffixes are `f32` and `f64`")
-                        .emit();
-                }
-            }
-            LitError::NonDecimalFloat(base) => {
-                let descr = match base {
-                    16 => "hexadecimal",
-                    8 => "octal",
-                    2 => "binary",
-                    _ => unreachable!(),
-                };
-                diag.struct_span_err(span, &format!("{} float literal is not supported", descr))
-                    .span_label(span, "not supported")
-                    .emit();
-            }
-            LitError::IntTooLarge => {
-                diag.struct_span_err(span, "integer literal is too large")
-                    .emit();
-            }
-        }
-    }
-}
-
 impl LitKind {
     /// Converts literal token into a semantic literal.
     fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
@@ -204,7 +134,7 @@ impl LitKind {
         let (kind, symbol, suffix) = match *self {
             LitKind::Str(symbol, ast::StrStyle::Cooked) => {
                 // Don't re-intern unless the escaped string is different.
-                let s = &symbol.as_str();
+                let s: &str = &symbol.as_str();
                 let escaped = s.escape_default().to_string();
                 let symbol = if escaped == *s { symbol } else { Symbol::intern(&escaped) };
                 (token::Str, symbol, None)
@@ -254,7 +184,7 @@ impl LitKind {
 
 impl Lit {
     /// Converts literal token into an AST literal.
-    fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
+    crate fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
         Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
     }
 
@@ -286,109 +216,16 @@ impl Lit {
         Lit { token: kind.to_lit_token(), kind, span }
     }
 
-    /// Losslessly convert an AST literal into a token stream.
-    crate fn tokens(&self) -> TokenStream {
+    /// Losslessly convert an AST literal into a token tree.
+    crate fn token_tree(&self) -> TokenTree {
         let token = match self.token.kind {
             token::Bool => token::Ident(self.token.symbol, false),
             _ => token::Literal(self.token),
         };
-        TokenTree::token(token, self.span).into()
-    }
-}
-
-impl<'a> Parser<'a> {
-    /// Matches `lit = true | false | token_lit`.
-    crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
-        let mut recovered = None;
-        if self.token == token::Dot {
-            // Attempt to recover `.4` as `0.4`.
-            recovered = self.look_ahead(1, |next_token| {
-                if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
-                        = next_token.kind {
-                    if self.token.span.hi() == next_token.span.lo() {
-                        let s = String::from("0.") + &symbol.as_str();
-                        let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
-                        return Some(Token::new(kind, self.token.span.to(next_token.span)));
-                    }
-                }
-                None
-            });
-            if let Some(token) = &recovered {
-                self.bump();
-                self.diagnostic()
-                    .struct_span_err(token.span, "float literals must have an integer part")
-                    .span_suggestion(
-                        token.span,
-                        "must have an integer part",
-                        pprust::token_to_string(token),
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
-            }
-        }
-
-        let token = recovered.as_ref().unwrap_or(&self.token);
-        match Lit::from_token(token) {
-            Ok(lit) => {
-                self.bump();
-                Ok(lit)
-            }
-            Err(LitError::NotLiteral) => {
-                let msg = format!("unexpected token: {}", self.this_token_descr());
-                Err(self.span_fatal(token.span, &msg))
-            }
-            Err(err) => {
-                let (lit, span) = (token.expect_lit(), token.span);
-                self.bump();
-                err.report(&self.sess.span_diagnostic, lit, span);
-                // Pack possible quotes and prefixes from the original literal into
-                // the error literal's symbol so they can be pretty-printed faithfully.
-                let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
-                let symbol = Symbol::intern(&suffixless_lit.to_string());
-                let lit = token::Lit::new(token::Err, symbol, lit.suffix);
-                Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
-            }
-        }
-    }
-}
-
-crate fn expect_no_suffix(diag: &Handler, sp: Span, kind: &str, suffix: Option<Symbol>) {
-    if let Some(suf) = suffix {
-        let mut err = if kind == "a tuple index" &&
-                         [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) {
-            // #59553: warn instead of reject out of hand to allow the fix to percolate
-            // through the ecosystem when people fix their macros
-            let mut err = diag.struct_span_warn(
-                sp,
-                &format!("suffixes on {} are invalid", kind),
-            );
-            err.note(&format!(
-                "`{}` is *temporarily* accepted on tuple index fields as it was \
-                    incorrectly accepted on stable for a few releases",
-                suf,
-            ));
-            err.help(
-                "on proc macros, you'll want to use `syn::Index::from` or \
-                    `proc_macro::Literal::*_unsuffixed` for code that will desugar \
-                    to tuple field access",
-            );
-            err.note(
-                "for more context, see https://github.com/rust-lang/rust/issues/60210",
-            );
-            err
-        } else {
-            diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
-        };
-        err.span_label(sp, format!("invalid suffix `{}`", suf));
-        err.emit();
+        TokenTree::token(token, self.span)
     }
 }
 
-// Checks if `s` looks like i32 or u1234 etc.
-fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
-    s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
-}
-
 fn strip_underscores(symbol: Symbol) -> Symbol {
     // Do not allocate a new string unless necessary.
     let s = symbol.as_str();
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1518da23b09..e6b794a6a99 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -1,40 +1,33 @@
 //! The main parser interface.
 
-use crate::ast::{self, CrateConfig, NodeId};
-use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
-use crate::source_map::{SourceMap, FilePathMapping};
-use crate::feature_gate::UnstableFeatures;
-use crate::parse::parser::Parser;
-use crate::parse::parser::emit_unclosed_delims;
-use crate::parse::token::TokenKind;
-use crate::tokenstream::{TokenStream, TokenTree};
+use crate::ast;
+use crate::parse::parser::{Parser, emit_unclosed_delims};
+use crate::parse::token::Nonterminal;
+use crate::tokenstream::{self, TokenStream, TokenTree};
 use crate::print::pprust;
-use crate::symbol::Symbol;
+use crate::sess::ParseSess;
 
-use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
-use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use errors::{FatalError, Level, Diagnostic, DiagnosticBuilder};
 #[cfg(target_arch = "x86_64")]
 use rustc_data_structures::static_assert_size;
-use rustc_data_structures::sync::{Lrc, Lock, Once};
-use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
-use syntax_pos::edition::Edition;
-use syntax_pos::hygiene::ExpnId;
+use rustc_data_structures::sync::Lrc;
+use syntax_pos::{Span, SourceFile, FileName};
 
 use std::borrow::Cow;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::str;
 
+use log::info;
+
 #[cfg(test)]
 mod tests;
 
 #[macro_use]
 pub mod parser;
-pub mod attr;
 pub mod lexer;
 pub mod token;
 
 crate mod classify;
-crate mod diagnostics;
 crate mod literal;
 crate mod unescape_error_reporting;
 
@@ -45,112 +38,6 @@ pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(PResult<'_, bool>, 16);
 
-/// Collected spans during parsing for places where a certain feature was
-/// used and should be feature gated accordingly in `check_crate`.
-#[derive(Default)]
-pub struct GatedSpans {
-    /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`.
-    pub let_chains: Lock<Vec<Span>>,
-    /// Spans collected for gating `async_closure`, e.g. `async || ..`.
-    pub async_closure: Lock<Vec<Span>>,
-    /// Spans collected for gating `yield e?` expressions (`generators` gate).
-    pub yields: Lock<Vec<Span>>,
-    /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`.
-    pub or_patterns: Lock<Vec<Span>>,
-    /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`.
-    pub const_extern_fn: Lock<Vec<Span>>,
-}
-
-/// Info about a parsing session.
-pub struct ParseSess {
-    pub span_diagnostic: Handler,
-    pub unstable_features: UnstableFeatures,
-    pub config: CrateConfig,
-    pub edition: Edition,
-    pub missing_fragment_specifiers: Lock<FxHashSet<Span>>,
-    /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
-    pub raw_identifier_spans: Lock<Vec<Span>>,
-    /// Used to determine and report recursive module inclusions.
-    included_mod_stack: Lock<Vec<PathBuf>>,
-    source_map: Lrc<SourceMap>,
-    pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
-    /// Contains the spans of block expressions that could have been incomplete based on the
-    /// operation token that followed it, but that the parser cannot identify without further
-    /// analysis.
-    pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
-    pub injected_crate_name: Once<Symbol>,
-    pub gated_spans: GatedSpans,
-}
-
-impl ParseSess {
-    pub fn new(file_path_mapping: FilePathMapping) -> Self {
-        let cm = Lrc::new(SourceMap::new(file_path_mapping));
-        let handler = Handler::with_tty_emitter(
-            ColorConfig::Auto,
-            true,
-            None,
-            Some(cm.clone()),
-        );
-        ParseSess::with_span_handler(handler, cm)
-    }
-
-    pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
-        Self {
-            span_diagnostic: handler,
-            unstable_features: UnstableFeatures::from_environment(),
-            config: FxHashSet::default(),
-            edition: ExpnId::root().expn_data().edition,
-            missing_fragment_specifiers: Lock::new(FxHashSet::default()),
-            raw_identifier_spans: Lock::new(Vec::new()),
-            included_mod_stack: Lock::new(vec![]),
-            source_map,
-            buffered_lints: Lock::new(vec![]),
-            ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
-            injected_crate_name: Once::new(),
-            gated_spans: GatedSpans::default(),
-        }
-    }
-
-    #[inline]
-    pub fn source_map(&self) -> &SourceMap {
-        &self.source_map
-    }
-
-    pub fn buffer_lint<S: Into<MultiSpan>>(&self,
-        lint_id: BufferedEarlyLintId,
-        span: S,
-        id: NodeId,
-        msg: &str,
-    ) {
-        self.buffered_lints.with_lock(|buffered_lints| {
-            buffered_lints.push(BufferedEarlyLint{
-                span: span.into(),
-                id,
-                msg: msg.into(),
-                lint_id,
-            });
-        });
-    }
-
-    /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
-    /// parser to continue parsing the following operation as part of the same expression.
-    pub fn expr_parentheses_needed(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        span: Span,
-        alt_snippet: Option<String>,
-    ) {
-        if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) {
-            err.span_suggestion(
-                span,
-                "parentheses are required to parse this as an expression",
-                format!("({})", snippet),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-}
-
 #[derive(Clone)]
 pub struct Directory<'a> {
     pub path: Cow<'a, Path>,
@@ -384,26 +271,131 @@ pub fn stream_to_parser_with_base_dir<'a>(
     Parser::new(sess, stream, Some(base_dir), true, false, None)
 }
 
-/// A sequence separator.
-pub struct SeqSep {
-    /// The separator token.
-    pub sep: Option<TokenKind>,
-    /// `true` if a trailing separator is allowed.
-    pub trailing_sep_allowed: bool,
+// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
+// fact that architecturally, we are using parsing (read on below to understand why).
+
+pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> TokenStream {
+    // A `Nonterminal` is often a parsed AST item. At this point we now
+    // need to convert the parsed AST to an actual token stream, e.g.
+    // un-parse it basically.
+    //
+    // Unfortunately there's not really a great way to do that in a
+    // guaranteed lossless fashion right now. The fallback here is to just
+    // stringify the AST node and reparse it, but this loses all span
+    // information.
+    //
+    // As a result, some AST nodes are annotated with the token stream they
+    // came from. Here we attempt to extract these lossless token streams
+    // before we fall back to the stringification.
+    let tokens = match *nt {
+        Nonterminal::NtItem(ref item) => {
+            prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
+        }
+        Nonterminal::NtTraitItem(ref item) => {
+            prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
+        }
+        Nonterminal::NtImplItem(ref item) => {
+            prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
+        }
+        Nonterminal::NtIdent(ident, is_raw) => {
+            Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into())
+        }
+        Nonterminal::NtLifetime(ident) => {
+            Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into())
+        }
+        Nonterminal::NtTT(ref tt) => {
+            Some(tt.clone().into())
+        }
+        _ => None,
+    };
+
+    // FIXME(#43081): Avoid this pretty-print + reparse hack
+    let source = pprust::nonterminal_to_string(nt);
+    let filename = FileName::macro_expansion_source_code(&source);
+    let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span));
+
+    // During early phases of the compiler the AST could get modified
+    // directly (e.g., attributes added or removed) and the internal cache
+    // of tokens my not be invalidated or updated. Consequently if the
+    // "lossless" token stream disagrees with our actual stringification
+    // (which has historically been much more battle-tested) then we go
+    // with the lossy stream anyway (losing span information).
+    //
+    // Note that the comparison isn't `==` here to avoid comparing spans,
+    // but it *also* is a "probable" equality which is a pretty weird
+    // definition. We mostly want to catch actual changes to the AST
+    // like a `#[cfg]` being processed or some weird `macro_rules!`
+    // expansion.
+    //
+    // What we *don't* want to catch is the fact that a user-defined
+    // literal like `0xf` is stringified as `15`, causing the cached token
+    // stream to not be literal `==` token-wise (ignoring spans) to the
+    // token stream we got from stringification.
+    //
+    // Instead the "probably equal" check here is "does each token
+    // recursively have the same discriminant?" We basically don't look at
+    // the token values here and assume that such fine grained token stream
+    // modifications, including adding/removing typically non-semantic
+    // tokens such as extra braces and commas, don't happen.
+    if let Some(tokens) = tokens {
+        if tokens.probably_equal_for_proc_macro(&tokens_for_real) {
+            return tokens
+        }
+        info!("cached tokens found, but they're not \"probably equal\", \
+                going with stringified version");
+    }
+    return tokens_for_real
 }
 
-impl SeqSep {
-    pub fn trailing_allowed(t: TokenKind) -> SeqSep {
-        SeqSep {
-            sep: Some(t),
-            trailing_sep_allowed: true,
-        }
+fn prepend_attrs(
+    sess: &ParseSess,
+    attrs: &[ast::Attribute],
+    tokens: Option<&tokenstream::TokenStream>,
+    span: syntax_pos::Span
+) -> Option<tokenstream::TokenStream> {
+    let tokens = tokens?;
+    if attrs.len() == 0 {
+        return Some(tokens.clone())
     }
+    let mut builder = tokenstream::TokenStreamBuilder::new();
+    for attr in attrs {
+        assert_eq!(attr.style, ast::AttrStyle::Outer,
+                   "inner attributes should prevent cached tokens from existing");
+
+        let source = pprust::attribute_to_string(attr);
+        let macro_filename = FileName::macro_expansion_source_code(&source);
+        if attr.is_sugared_doc {
+            let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
+            builder.push(stream);
+            continue
+        }
 
-    pub fn none() -> SeqSep {
-        SeqSep {
-            sep: None,
-            trailing_sep_allowed: false,
+        // synthesize # [ $path $tokens ] manually here
+        let mut brackets = tokenstream::TokenStreamBuilder::new();
+
+        // For simple paths, push the identifier directly
+        if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() {
+            let ident = attr.path.segments[0].ident;
+            let token = token::Ident(ident.name, ident.as_str().starts_with("r#"));
+            brackets.push(tokenstream::TokenTree::token(token, ident.span));
+
+        // ... and for more complicated paths, fall back to a reparse hack that
+        // should eventually be removed.
+        } else {
+            let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
+            brackets.push(stream);
         }
+
+        brackets.push(attr.tokens.clone());
+
+        // The span we list here for `#` and for `[ ... ]` are both wrong in
+        // that it encompasses more than each token, but it hopefully is "good
+        // enough" for now at least.
+        builder.push(tokenstream::TokenTree::token(token::Pound, attr.span));
+        let delim_span = tokenstream::DelimSpan::from_single(attr.span);
+        builder.push(tokenstream::TokenTree::Delimited(
+            delim_span, token::DelimToken::Bracket, brackets.build().into()));
     }
+    builder.push(tokens.clone());
+    Some(builder.build())
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 4a457f5a43c..2ce0046ca27 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1,28 +1,28 @@
+pub mod attr;
 mod expr;
 mod pat;
 mod item;
-pub use item::AliasKind;
 mod module;
-pub use module::{ModulePath, ModulePathSuccess};
 mod ty;
 mod path;
 pub use path::PathStyle;
 mod stmt;
 mod generics;
+mod diagnostics;
+use diagnostics::Error;
 
 use crate::ast::{
-    self, DUMMY_NODE_ID, AttrStyle, Attribute, BindingMode, CrateSugar, Ident,
-    IsAsync, MacDelimiter, Mutability, Param, StrStyle, SelfKind, TyKind, Visibility,
-    VisibilityKind, Unsafety,
+    self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
+    IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
 };
-use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token};
-use crate::parse::diagnostics::{Error, dummy_arg};
+use crate::parse::{PResult, Directory, DirectoryOwnership};
 use crate::parse::lexer::UnmatchedBrace;
 use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
-use crate::parse::token::{Token, TokenKind, DelimToken};
+use crate::parse::token::{self, Token, TokenKind, DelimToken};
 use crate::print::pprust;
 use crate::ptr::P;
-use crate::source_map::{self, respan};
+use crate::sess::ParseSess;
+use crate::source_map::respan;
 use crate::symbol::{kw, sym, Symbol};
 use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
 use crate::ThinVec;
@@ -44,29 +44,18 @@ bitflags::bitflags! {
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
-crate enum SemiColonMode {
+enum SemiColonMode {
     Break,
     Ignore,
     Comma,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
-crate enum BlockMode {
+enum BlockMode {
     Break,
     Ignore,
 }
 
-/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
-struct ParamCfg {
-    /// Is `self` is allowed as the first parameter?
-    is_self_allowed: bool,
-    /// Is `...` allowed as the tail of the parameter list?
-    allow_c_variadic: bool,
-    /// `is_name_required` decides if, per-parameter,
-    /// the parameter must have a pattern or just a type.
-    is_name_required: fn(&token::Token) -> bool,
-}
-
 /// Like `maybe_whole_expr`, but for things other than expressions.
 #[macro_export]
 macro_rules! maybe_whole {
@@ -97,13 +86,6 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
     }
 }
 
-fn maybe_append(mut lhs: Vec<Attribute>, mut rhs: Option<Vec<Attribute>>) -> Vec<Attribute> {
-    if let Some(ref mut rhs) = rhs {
-        lhs.append(rhs);
-    }
-    lhs
-}
-
 #[derive(Debug, Clone, Copy, PartialEq)]
 enum PrevTokenKind {
     DocComment,
@@ -135,33 +117,33 @@ pub struct Parser<'a> {
     prev_token_kind: PrevTokenKind,
     restrictions: Restrictions,
     /// Used to determine the path to externally loaded source files.
-    crate directory: Directory<'a>,
+    pub(super) directory: Directory<'a>,
     /// `true` to parse sub-modules in other files.
-    pub recurse_into_file_modules: bool,
+    pub(super) recurse_into_file_modules: bool,
     /// Name of the root module this parser originated from. If `None`, then the
     /// name is not known. This does not change while the parser is descending
     /// into modules, and sub-parsers have new values for this name.
     pub root_module_name: Option<String>,
-    crate expected_tokens: Vec<TokenType>,
+    expected_tokens: Vec<TokenType>,
     token_cursor: TokenCursor,
     desugar_doc_comments: bool,
     /// `true` we should configure out of line modules as we parse.
-    pub cfg_mods: bool,
+    cfg_mods: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
     /// required in order to detect extra leading left angle brackets (`<` characters) and error
     /// appropriately.
     ///
     /// See the comments in the `parse_path_segment` function for more details.
-    crate unmatched_angle_bracket_count: u32,
-    crate max_angle_bracket_count: u32,
+    unmatched_angle_bracket_count: u32,
+    max_angle_bracket_count: u32,
     /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery
     /// it gets removed from here. Every entry left at the end gets emitted as an independent
     /// error.
-    crate unclosed_delims: Vec<UnmatchedBrace>,
-    crate last_unexpected_token_span: Option<Span>,
-    crate last_type_ascription: Option<(Span, bool /* likely path typo */)>,
+    pub(super) unclosed_delims: Vec<UnmatchedBrace>,
+    last_unexpected_token_span: Option<Span>,
+    pub last_type_ascription: Option<(Span, bool /* likely path typo */)>,
     /// If present, this `Parser` is not parsing Rust code but rather a macro call.
-    crate subparser_name: Option<&'static str>,
+    subparser_name: Option<&'static str>,
 }
 
 impl<'a> Drop for Parser<'a> {
@@ -205,7 +187,7 @@ struct TokenCursorFrame {
 /// You can find some more example usage of this in the `collect_tokens` method
 /// on the parser.
 #[derive(Clone)]
-crate enum LastToken {
+enum LastToken {
     Collecting(Vec<TreeAndJoint>),
     Was(Option<TreeAndJoint>),
 }
@@ -296,10 +278,10 @@ impl TokenCursor {
             token::NoDelim,
             &if doc_comment_style(&name.as_str()) == AttrStyle::Inner {
                 [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
-                    .iter().cloned().collect::<TokenStream>().into()
+                    .iter().cloned().collect::<TokenStream>()
             } else {
                 [TokenTree::token(token::Pound, sp), body]
-                    .iter().cloned().collect::<TokenStream>().into()
+                    .iter().cloned().collect::<TokenStream>()
             },
         )));
 
@@ -308,7 +290,7 @@ impl TokenCursor {
 }
 
 #[derive(Clone, PartialEq)]
-crate enum TokenType {
+enum TokenType {
     Token(TokenKind),
     Keyword(Symbol),
     Operator,
@@ -320,7 +302,7 @@ crate enum TokenType {
 }
 
 impl TokenType {
-    crate fn to_string(&self) -> String {
+    fn to_string(&self) -> String {
         match *self {
             TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)),
             TokenType::Keyword(kw) => format!("`{}`", kw),
@@ -335,11 +317,35 @@ impl TokenType {
 }
 
 #[derive(Copy, Clone, Debug)]
-crate enum TokenExpectType {
+enum TokenExpectType {
     Expect,
     NoExpect,
 }
 
+/// A sequence separator.
+struct SeqSep {
+    /// The separator token.
+    sep: Option<TokenKind>,
+    /// `true` if a trailing separator is allowed.
+    trailing_sep_allowed: bool,
+}
+
+impl SeqSep {
+    fn trailing_allowed(t: TokenKind) -> SeqSep {
+        SeqSep {
+            sep: Some(t),
+            trailing_sep_allowed: true,
+        }
+    }
+
+    fn none() -> SeqSep {
+        SeqSep {
+            sep: None,
+            trailing_sep_allowed: false,
+        }
+    }
+}
+
 impl<'a> Parser<'a> {
     pub fn new(
         sess: &'a ParseSess,
@@ -416,7 +422,7 @@ impl<'a> Parser<'a> {
         pprust::token_to_string(&self.token)
     }
 
-    crate fn token_descr(&self) -> Option<&'static str> {
+    fn token_descr(&self) -> Option<&'static str> {
         Some(match &self.token.kind {
             _ if self.token.is_special_ident() => "reserved identifier",
             _ if self.token.is_used_keyword() => "keyword",
@@ -426,7 +432,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    crate fn this_token_descr(&self) -> String {
+    pub(super) fn this_token_descr(&self) -> String {
         if let Some(prefix) = self.token_descr() {
             format!("{} `{}`", prefix, self.this_token_to_string())
         } else {
@@ -476,7 +482,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
+    fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
         self.parse_ident_common(true)
     }
 
@@ -509,7 +515,7 @@ impl<'a> Parser<'a> {
     ///
     /// This method will automatically add `tok` to `expected_tokens` if `tok` is not
     /// encountered.
-    crate fn check(&mut self, tok: &TokenKind) -> bool {
+    fn check(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.token == *tok;
         if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); }
         is_present
@@ -531,7 +537,7 @@ impl<'a> Parser<'a> {
 
     /// If the next token is the given keyword, eats it and returns `true`.
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
-    pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
+    fn eat_keyword(&mut self, kw: Symbol) -> bool {
         if self.check_keyword(kw) {
             self.bump();
             true
@@ -569,7 +575,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn check_ident(&mut self) -> bool {
+    fn check_ident(&mut self) -> bool {
         self.check_or_expected(self.token.is_ident(), TokenType::Ident)
     }
 
@@ -649,10 +655,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
-        literal::expect_no_suffix(&self.sess.span_diagnostic, sp, kind, suffix)
-    }
-
     /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single
     /// `<` and continue. If `<-` is seen, replaces it with a single `<`
     /// and continue. If a `<` is not seen, returns false.
@@ -738,7 +740,7 @@ impl<'a> Parser<'a> {
     /// Parses a sequence, including the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
-    pub fn parse_seq_to_end<T>(
+    fn parse_seq_to_end<T>(
         &mut self,
         ket: &TokenKind,
         sep: SeqSep,
@@ -754,7 +756,7 @@ impl<'a> Parser<'a> {
     /// Parses a sequence, not including the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
-    pub fn parse_seq_to_before_end<T>(
+    fn parse_seq_to_before_end<T>(
         &mut self,
         ket: &TokenKind,
         sep: SeqSep,
@@ -772,7 +774,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    crate fn parse_seq_to_before_tokens<T>(
+    fn parse_seq_to_before_tokens<T>(
         &mut self,
         kets: &[&TokenKind],
         sep: SeqSep,
@@ -1018,7 +1020,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn process_potential_macro_variable(&mut self) {
+    pub fn process_potential_macro_variable(&mut self) {
         self.token = match self.token.kind {
             token::Dollar if self.token.span.from_expansion() &&
                              self.look_ahead(1, |t| t.is_ident()) => {
@@ -1052,7 +1054,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a single token tree from the input.
-    crate fn parse_token_tree(&mut self) -> TokenTree {
+    pub fn parse_token_tree(&mut self) -> TokenTree {
         match self.token.kind {
             token::OpenDelim(..) => {
                 let frame = mem::replace(&mut self.token_cursor.frame,
@@ -1105,271 +1107,6 @@ impl<'a> Parser<'a> {
         res
     }
 
-    /// Parses the parameter list of a function, including the `(` and `)` delimiters.
-    fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
-        let sp = self.token.span;
-        let is_trait_item = cfg.is_self_allowed;
-        let mut c_variadic = false;
-        // Parse the arguments, starting out with `self` being possibly allowed...
-        let (params, _) = self.parse_paren_comma_seq(|p| {
-            let param = p.parse_param_general(&cfg, is_trait_item);
-            // ...now that we've parsed the first argument, `self` is no longer allowed.
-            cfg.is_self_allowed = false;
-
-            match param {
-                Ok(param) => Ok(
-                    if let TyKind::CVarArgs = param.ty.kind {
-                        c_variadic = true;
-                        if p.token != token::CloseDelim(token::Paren) {
-                            p.span_err(
-                                p.token.span,
-                                "`...` must be the last argument of a C-variadic function",
-                            );
-                            // FIXME(eddyb) this should probably still push `CVarArgs`.
-                            // Maybe AST validation/HIR lowering should emit the above error?
-                            None
-                        } else {
-                            Some(param)
-                        }
-                    } else {
-                        Some(param)
-                    }
-                ),
-                Err(mut e) => {
-                    e.emit();
-                    let lo = p.prev_span;
-                    // Skip every token until next possible arg or end.
-                    p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
-                    // Create a placeholder argument for proper arg count (issue #34264).
-                    let span = lo.to(p.prev_span);
-                    Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
-                }
-            }
-        })?;
-
-        let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
-
-        // Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
-        self.deduplicate_recovered_params_names(&mut params);
-
-        if c_variadic && params.len() <= 1 {
-            self.span_err(
-                sp,
-                "C-variadic function must be declared with at least one named argument",
-            );
-        }
-
-        Ok(params)
-    }
-
-    /// Skips unexpected attributes and doc comments in this position and emits an appropriate
-    /// error.
-    /// This version of parse param doesn't necessarily require identifier names.
-    fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
-        let lo = self.token.span;
-        let attrs = self.parse_outer_attributes()?;
-
-        // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
-        if let Some(mut param) = self.parse_self_param()? {
-            param.attrs = attrs.into();
-            return if cfg.is_self_allowed {
-                Ok(param)
-            } else {
-                self.recover_bad_self_param(param, is_trait_item)
-            };
-        }
-
-        let is_name_required = match self.token.kind {
-            token::DotDotDot => false,
-            _ => (cfg.is_name_required)(&self.token),
-        };
-        let (pat, ty) = if is_name_required || self.is_named_param() {
-            debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
-
-            let pat = self.parse_fn_param_pat()?;
-            if let Err(mut err) = self.expect(&token::Colon) {
-                return if let Some(ident) = self.parameter_without_type(
-                    &mut err,
-                    pat,
-                    is_name_required,
-                    cfg.is_self_allowed,
-                    is_trait_item,
-                ) {
-                    err.emit();
-                    Ok(dummy_arg(ident))
-                } else {
-                    Err(err)
-                };
-            }
-
-            self.eat_incorrect_doc_comment_for_param_type();
-            (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
-        } else {
-            debug!("parse_param_general ident_to_pat");
-            let parser_snapshot_before_ty = self.clone();
-            self.eat_incorrect_doc_comment_for_param_type();
-            let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
-            if ty.is_ok() && self.token != token::Comma &&
-               self.token != token::CloseDelim(token::Paren) {
-                // This wasn't actually a type, but a pattern looking like a type,
-                // so we are going to rollback and re-parse for recovery.
-                ty = self.unexpected();
-            }
-            match ty {
-                Ok(ty) => {
-                    let ident = Ident::new(kw::Invalid, self.prev_span);
-                    let bm = BindingMode::ByValue(Mutability::Immutable);
-                    let pat = self.mk_pat_ident(ty.span, bm, ident);
-                    (pat, ty)
-                }
-                // If this is a C-variadic argument and we hit an error, return the error.
-                Err(err) if self.token == token::DotDotDot => return Err(err),
-                // Recover from attempting to parse the argument as a type without pattern.
-                Err(mut err) => {
-                    err.cancel();
-                    mem::replace(self, parser_snapshot_before_ty);
-                    self.recover_arg_parse()?
-                }
-            }
-        };
-
-        let span = lo.to(self.token.span);
-
-        Ok(Param {
-            attrs: attrs.into(),
-            id: ast::DUMMY_NODE_ID,
-            is_placeholder: false,
-            pat,
-            span,
-            ty,
-        })
-    }
-
-    /// Returns the parsed optional self parameter and whether a self shortcut was used.
-    ///
-    /// See `parse_self_param_with_attrs` to collect attributes.
-    fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
-        // Extract an identifier *after* having confirmed that the token is one.
-        let expect_self_ident = |this: &mut Self| {
-            match this.token.kind {
-                // Preserve hygienic context.
-                token::Ident(name, _) => {
-                    let span = this.token.span;
-                    this.bump();
-                    Ident::new(name, span)
-                }
-                _ => unreachable!(),
-            }
-        };
-        // Is `self` `n` tokens ahead?
-        let is_isolated_self = |this: &Self, n| {
-            this.is_keyword_ahead(n, &[kw::SelfLower])
-            && this.look_ahead(n + 1, |t| t != &token::ModSep)
-        };
-        // Is `mut self` `n` tokens ahead?
-        let is_isolated_mut_self = |this: &Self, n| {
-            this.is_keyword_ahead(n, &[kw::Mut])
-            && is_isolated_self(this, n + 1)
-        };
-        // Parse `self` or `self: TYPE`. We already know the current token is `self`.
-        let parse_self_possibly_typed = |this: &mut Self, m| {
-            let eself_ident = expect_self_ident(this);
-            let eself_hi = this.prev_span;
-            let eself = if this.eat(&token::Colon) {
-                SelfKind::Explicit(this.parse_ty()?, m)
-            } else {
-                SelfKind::Value(m)
-            };
-            Ok((eself, eself_ident, eself_hi))
-        };
-        // Recover for the grammar `*self`, `*const self`, and `*mut self`.
-        let recover_self_ptr = |this: &mut Self| {
-            let msg = "cannot pass `self` by raw pointer";
-            let span = this.token.span;
-            this.struct_span_err(span, msg)
-                .span_label(span, msg)
-                .emit();
-
-            Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span))
-        };
-
-        // Parse optional `self` parameter of a method.
-        // Only a limited set of initial token sequences is considered `self` parameters; anything
-        // else is parsed as a normal function parameter list, so some lookahead is required.
-        let eself_lo = self.token.span;
-        let (eself, eself_ident, eself_hi) = match self.token.kind {
-            token::BinOp(token::And) => {
-                let eself = if is_isolated_self(self, 1) {
-                    // `&self`
-                    self.bump();
-                    SelfKind::Region(None, Mutability::Immutable)
-                } else if is_isolated_mut_self(self, 1) {
-                    // `&mut self`
-                    self.bump();
-                    self.bump();
-                    SelfKind::Region(None, Mutability::Mutable)
-                } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
-                    // `&'lt self`
-                    self.bump();
-                    let lt = self.expect_lifetime();
-                    SelfKind::Region(Some(lt), Mutability::Immutable)
-                } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) {
-                    // `&'lt mut self`
-                    self.bump();
-                    let lt = self.expect_lifetime();
-                    self.bump();
-                    SelfKind::Region(Some(lt), Mutability::Mutable)
-                } else {
-                    // `&not_self`
-                    return Ok(None);
-                };
-                (eself, expect_self_ident(self), self.prev_span)
-            }
-            // `*self`
-            token::BinOp(token::Star) if is_isolated_self(self, 1) => {
-                self.bump();
-                recover_self_ptr(self)?
-            }
-            // `*mut self` and `*const self`
-            token::BinOp(token::Star) if
-                self.look_ahead(1, |t| t.is_mutability())
-                && is_isolated_self(self, 2) =>
-            {
-                self.bump();
-                self.bump();
-                recover_self_ptr(self)?
-            }
-            // `self` and `self: TYPE`
-            token::Ident(..) if is_isolated_self(self, 0) => {
-                parse_self_possibly_typed(self, Mutability::Immutable)?
-            }
-            // `mut self` and `mut self: TYPE`
-            token::Ident(..) if is_isolated_mut_self(self, 0) => {
-                self.bump();
-                parse_self_possibly_typed(self, Mutability::Mutable)?
-            }
-            _ => return Ok(None),
-        };
-
-        let eself = source_map::respan(eself_lo.to(eself_hi), eself);
-        Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
-    }
-
-    fn is_named_param(&self) -> bool {
-        let offset = match self.token.kind {
-            token::Interpolated(ref nt) => match **nt {
-                token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
-                _ => 0,
-            }
-            token::BinOp(token::And) | token::AndAnd => 1,
-            _ if self.token.is_keyword(kw::Mut) => 1,
-            _ => 0,
-        };
-
-        self.look_ahead(offset, |t| t.is_ident()) &&
-        self.look_ahead(offset + 1, |t| t == &token::Colon)
-    }
-
     fn is_crate_vis(&self) -> bool {
         self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
     }
@@ -1454,12 +1191,14 @@ impl<'a> Parser<'a> {
 `pub(super)`: visible only in the current module's parent
 `pub(in path::to::module)`: visible only on the specified path"##;
 
+        let path_str = pprust::path_to_string(&path);
+
         struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg)
             .help(suggestion)
             .span_suggestion(
                 path.span,
-                &format!("make this visible only to module `{}` with `in`", path),
-                format!("in {}", path),
+                &format!("make this visible only to module `{}` with `in`", path_str),
+                format!("in {}", path_str),
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -1548,7 +1287,7 @@ impl<'a> Parser<'a> {
             // This can happen due to a bad interaction of two unrelated recovery mechanisms with
             // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(`
             // (#62881).
-            return Ok((ret?, TokenStream::new(vec![])));
+            return Ok((ret?, TokenStream::default()));
         } else {
             &mut self.token_cursor.stack[prev].last_token
         };
@@ -1563,7 +1302,7 @@ impl<'a> Parser<'a> {
                 // This can happen due to a bad interaction of two unrelated recovery mechanisms
                 // with mismatched delimiters *and* recovery lookahead on the likely typo
                 // `pub ident(` (#62895, different but similar to the case above).
-                return Ok((ret?, TokenStream::new(vec![])));
+                return Ok((ret?, TokenStream::default()));
             }
         };
 
@@ -1601,7 +1340,7 @@ impl<'a> Parser<'a> {
                                    *t == token::BinOp(token::Star))
     }
 
-    pub fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> {
+    fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option<ast::Name>)> {
         let ret = match self.token.kind {
             token::Literal(token::Lit { kind: token::Str, symbol, suffix }) =>
                 (symbol, ast::StrStyle::Cooked, suffix),
@@ -1641,7 +1380,7 @@ impl<'a> Parser<'a> {
             ],
             Applicability::MaybeIncorrect,
         ).span_suggestion(
-            self.sess.source_map.next_point(self.prev_span),
+            self.sess.source_map().next_point(self.prev_span),
             "add a semicolon",
             ';'.to_string(),
             Applicability::MaybeIncorrect,
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/parser/attr.rs
index e74f3045db8..188a144cac9 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/parser/attr.rs
@@ -1,13 +1,11 @@
+use super::{SeqSep, PResult, Parser, TokenType, PathStyle};
 use crate::attr;
 use crate::ast;
-use crate::parse::{SeqSep, PResult};
 use crate::parse::token::{self, Nonterminal, DelimToken};
-use crate::parse::parser::{Parser, TokenType, PathStyle};
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::source_map::Span;
 
 use log::debug;
-use smallvec::smallvec;
 
 #[derive(Debug)]
 enum InnerAttributeParsePolicy<'a> {
@@ -20,7 +18,7 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
 
 impl<'a> Parser<'a> {
     /// Parses attributes that appear before an item.
-    crate fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
+    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
         let mut attrs: Vec<ast::Attribute> = Vec::new();
         let mut just_parsed_doc_comment = false;
         loop {
@@ -84,9 +82,10 @@ impl<'a> Parser<'a> {
 
     /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
     /// that prescribes how to handle inner attributes.
-    fn parse_attribute_with_inner_parse_policy(&mut self,
-                                               inner_parse_policy: InnerAttributeParsePolicy<'_>)
-                                               -> PResult<'a, ast::Attribute> {
+    fn parse_attribute_with_inner_parse_policy(
+        &mut self,
+        inner_parse_policy: InnerAttributeParsePolicy<'_>
+    ) -> PResult<'a, ast::Attribute> {
         debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
                inner_parse_policy,
                self.token);
@@ -193,17 +192,17 @@ impl<'a> Parser<'a> {
                         is_interpolated_expr = true;
                     }
                 }
-                let tokens = if is_interpolated_expr {
+                let token_tree = if is_interpolated_expr {
                     // We need to accept arbitrary interpolated expressions to continue
                     // supporting things like `doc = $expr` that work on stable.
                     // Non-literal interpolated expressions are rejected after expansion.
-                    self.parse_token_tree().into()
+                    self.parse_token_tree()
                 } else {
-                    self.parse_unsuffixed_lit()?.tokens()
+                    self.parse_unsuffixed_lit()?.token_tree()
                 };
-                TokenStream::from_streams(smallvec![eq.into(), tokens])
+                TokenStream::new(vec![eq.into(), token_tree.into()])
             } else {
-                TokenStream::empty()
+                TokenStream::default()
             };
             ast::AttrItem { path, tokens }
         })
@@ -260,6 +259,27 @@ impl<'a> Parser<'a> {
         Ok(lit)
     }
 
+    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
+    crate fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> {
+        self.expect(&token::OpenDelim(token::Paren))?;
+
+        let cfg_predicate = self.parse_meta_item()?;
+        self.expect(&token::Comma)?;
+
+        // Presumably, the majority of the time there will only be one attr.
+        let mut expanded_attrs = Vec::with_capacity(1);
+
+        while !self.check(&token::CloseDelim(token::Paren)) {
+            let lo = self.token.span.lo();
+            let item = self.parse_attr_item()?;
+            expanded_attrs.push((item, self.prev_span.with_lo(lo)));
+            self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
+        }
+
+        self.expect(&token::CloseDelim(token::Paren))?;
+        Ok((cfg_predicate, expanded_attrs))
+    }
+
     /// Matches the following grammar (per RFC 1559).
     ///
     ///     meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs
index 42cbe28fc17..06982c789db 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/parser/diagnostics.rs
@@ -1,10 +1,11 @@
+use super::{
+    BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType,
+    SeqSep, PResult, Parser
+};
 use crate::ast::{
     self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
-    Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData,
+    Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
 };
-use crate::feature_gate::feature_err;
-use crate::parse::{SeqSep, PResult, Parser, ParseSess};
-use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
 use crate::parse::token::{self, TokenKind};
 use crate::print::pprust;
 use crate::ptr::P;
@@ -18,8 +19,9 @@ use log::{debug, trace};
 use std::mem;
 
 const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments";
+
 /// Creates a placeholder argument.
-crate fn dummy_arg(ident: Ident) -> Param {
+pub(super) fn dummy_arg(ident: Ident) -> Param {
     let pat = P(Pat {
         id: ast::DUMMY_NODE_ID,
         kind: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None),
@@ -122,7 +124,7 @@ impl Error {
     }
 }
 
-pub trait RecoverQPath: Sized + 'static {
+pub(super) trait RecoverQPath: Sized + 'static {
     const PATH_STYLE: PathStyle = PathStyle::Expr;
     fn to_ty(&self) -> Option<P<Ty>>;
     fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
@@ -174,39 +176,43 @@ impl<'a> Parser<'a> {
         self.span_fatal(self.token.span, m)
     }
 
-    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
+    crate fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
         self.sess.span_diagnostic.struct_span_fatal(sp, m)
     }
 
-    pub fn span_fatal_err<S: Into<MultiSpan>>(&self, sp: S, err: Error) -> DiagnosticBuilder<'a> {
+    pub(super) fn span_fatal_err<S: Into<MultiSpan>>(
+        &self,
+        sp: S,
+        err: Error,
+    ) -> DiagnosticBuilder<'a> {
         err.span_err(sp, self.diagnostic())
     }
 
-    pub fn bug(&self, m: &str) -> ! {
+    pub(super) fn bug(&self, m: &str) -> ! {
         self.sess.span_diagnostic.span_bug(self.token.span, m)
     }
 
-    pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
+    pub(super) fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
         self.sess.span_diagnostic.span_err(sp, m)
     }
 
-    crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
+    pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
         self.sess.span_diagnostic.struct_span_err(sp, m)
     }
 
-    crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
+    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
         self.sess.span_diagnostic.span_bug(sp, m)
     }
 
-    crate fn diagnostic(&self) -> &'a errors::Handler {
+    pub(super) fn diagnostic(&self) -> &'a errors::Handler {
         &self.sess.span_diagnostic
     }
 
-    crate fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
+    pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
         self.sess.source_map().span_to_snippet(span)
     }
 
-    crate fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
+    pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
         let mut err = self.struct_span_err(
             self.token.span,
             &format!("expected identifier, found {}", self.this_token_descr()),
@@ -237,7 +243,7 @@ impl<'a> Parser<'a> {
         err
     }
 
-    pub fn expected_one_of_not_found(
+    pub(super) fn expected_one_of_not_found(
         &mut self,
         edible: &[TokenKind],
         inedible: &[TokenKind],
@@ -424,7 +430,7 @@ impl<'a> Parser<'a> {
 
     /// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
     /// passes through any errors encountered. Used for error recovery.
-    crate fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
+    pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
         if let Err(ref mut err) = self.parse_seq_to_before_tokens(
             kets,
             SeqSep::none(),
@@ -442,7 +448,7 @@ impl<'a> Parser<'a> {
     /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
     ///                                                        ^^ help: remove extra angle brackets
     /// ```
-    crate fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) {
+    pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) {
         // This function is intended to be invoked after parsing a path segment where there are two
         // cases:
         //
@@ -561,7 +567,7 @@ impl<'a> Parser<'a> {
     ///     inner_op   r2
     ///        /  \
     ///     l1    r1
-    crate fn check_no_chained_comparison(
+    pub(super) fn check_no_chained_comparison(
         &mut self,
         lhs: &Expr,
         outer_op: &AssocOp,
@@ -696,7 +702,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn maybe_report_ambiguous_plus(
+    pub(super) fn maybe_report_ambiguous_plus(
         &mut self,
         allow_plus: bool,
         impl_dyn_multi: bool,
@@ -715,55 +721,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn maybe_report_invalid_custom_discriminants(
-        sess: &ParseSess,
-        variants: &[ast::Variant],
-    ) {
-        let has_fields = variants.iter().any(|variant| match variant.data {
-            VariantData::Tuple(..) | VariantData::Struct(..) => true,
-            VariantData::Unit(..) => false,
-        });
-
-        let discriminant_spans = variants.iter().filter(|variant| match variant.data {
-            VariantData::Tuple(..) | VariantData::Struct(..) => false,
-            VariantData::Unit(..) => true,
-        })
-        .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
-        .collect::<Vec<_>>();
-
-        if !discriminant_spans.is_empty() && has_fields {
-            let mut err = feature_err(
-                sess,
-                sym::arbitrary_enum_discriminant,
-                discriminant_spans.clone(),
-                crate::feature_gate::GateIssue::Language,
-                "custom discriminant values are not allowed in enums with tuple or struct variants",
-            );
-            for sp in discriminant_spans {
-                err.span_label(sp, "disallowed custom discriminant");
-            }
-            for variant in variants.iter() {
-                match &variant.data {
-                    VariantData::Struct(..) => {
-                        err.span_label(
-                            variant.span,
-                            "struct variant defined here",
-                        );
-                    }
-                    VariantData::Tuple(..) => {
-                        err.span_label(
-                            variant.span,
-                            "tuple variant defined here",
-                        );
-                    }
-                    VariantData::Unit(..) => {}
-                }
-            }
-            err.emit();
-        }
-    }
-
-    crate fn maybe_recover_from_bad_type_plus(
+    pub(super) fn maybe_recover_from_bad_type_plus(
         &mut self,
         allow_plus: bool,
         ty: &Ty,
@@ -817,7 +775,7 @@ impl<'a> Parser<'a> {
     /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`.
     /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem`
     /// tail, and combines them into a `<Ty>::AssocItem` expression/pattern/type.
-    crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
+    pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
         &mut self,
         base: P<T>,
         allow_recovery: bool,
@@ -833,7 +791,7 @@ impl<'a> Parser<'a> {
 
     /// Given an already parsed `Ty`, parses the `::AssocItem` tail and
     /// combines them into a `<Ty>::AssocItem` expression/pattern/type.
-    crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
+    pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
         &mut self,
         ty_span: Span,
         ty: P<Ty>,
@@ -856,7 +814,7 @@ impl<'a> Parser<'a> {
                 // This is a best-effort recovery.
                 path.span,
                 "try",
-                format!("<{}>::{}", ty_str, path),
+                format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
                 Applicability::MaybeIncorrect,
             )
             .emit();
@@ -872,7 +830,7 @@ impl<'a> Parser<'a> {
         )))
     }
 
-    crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
+    pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
         if self.eat(&token::Semi) {
             let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
             err.span_suggestion_short(
@@ -908,7 +866,7 @@ impl<'a> Parser<'a> {
 
     /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a
     /// closing delimiter.
-    pub fn unexpected_try_recover(
+    pub(super) fn unexpected_try_recover(
         &mut self,
         t: &TokenKind,
     ) -> PResult<'a, bool /* recovered */> {
@@ -958,7 +916,7 @@ impl<'a> Parser<'a> {
         Err(err)
     }
 
-    crate fn parse_semi_or_incorrect_foreign_fn_body(
+    pub(super) fn parse_semi_or_incorrect_foreign_fn_body(
         &mut self,
         ident: &Ident,
         extern_sp: Span,
@@ -996,7 +954,7 @@ impl<'a> Parser<'a> {
 
     /// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
     /// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
-    crate fn parse_incorrect_await_syntax(
+    pub(super) fn parse_incorrect_await_syntax(
         &mut self,
         lo: Span,
         await_sp: Span,
@@ -1048,7 +1006,7 @@ impl<'a> Parser<'a> {
     }
 
     /// If encountering `future.await()`, consumes and emits an error.
-    crate fn recover_from_await_method_call(&mut self) {
+    pub(super) fn recover_from_await_method_call(&mut self) {
         if self.token == token::OpenDelim(token::Paren) &&
             self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
         {
@@ -1071,7 +1029,7 @@ impl<'a> Parser<'a> {
     /// and suggest writing `for $pat in $expr` instead.
     ///
     /// This should be called before parsing the `$block`.
-    crate fn recover_parens_around_for_head(
+    pub(super) fn recover_parens_around_for_head(
         &mut self,
         pat: P<Pat>,
         expr: &Expr,
@@ -1109,7 +1067,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
+    pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
         self.token.is_ident() &&
             if let ast::ExprKind::Path(..) = node { true } else { false } &&
             !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
@@ -1123,7 +1081,7 @@ impl<'a> Parser<'a> {
              self.look_ahead(2, |t| t == &token::Lt))  // `foo:bar::<baz>`
     }
 
-    crate fn recover_seq_parse_error(
+    pub(super) fn recover_seq_parse_error(
         &mut self,
         delim: token::DelimToken,
         lo: Span,
@@ -1140,7 +1098,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn recover_closing_delimiter(
+    pub(super) fn recover_closing_delimiter(
         &mut self,
         tokens: &[TokenKind],
         mut err: DiagnosticBuilder<'a>,
@@ -1191,7 +1149,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
-    crate fn eat_bad_pub(&mut self) {
+    pub(super) fn eat_bad_pub(&mut self) {
         if self.token.is_keyword(kw::Pub) {
             match self.parse_visibility(false) {
                 Ok(vis) => {
@@ -1209,7 +1167,7 @@ impl<'a> Parser<'a> {
     /// statement. This is something of a best-effort heuristic.
     ///
     /// We terminate when we find an unmatched `}` (without consuming it).
-    crate fn recover_stmt(&mut self) {
+    pub(super) fn recover_stmt(&mut self) {
         self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
     }
 
@@ -1220,7 +1178,11 @@ impl<'a> Parser<'a> {
     ///
     /// If `break_on_block` is `Break`, then we will stop consuming tokens
     /// after finding (and consuming) a brace-delimited block.
-    crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
+    pub(super) fn recover_stmt_(
+        &mut self,
+        break_on_semi: SemiColonMode,
+        break_on_block: BlockMode,
+    ) {
         let mut brace_depth = 0;
         let mut bracket_depth = 0;
         let mut in_block = false;
@@ -1288,7 +1250,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn check_for_for_in_in_typo(&mut self, in_span: Span) {
+    pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
         if self.eat_keyword(kw::In) {
             // a common typo: `for _ in in bar {}`
             self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`")
@@ -1302,14 +1264,14 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
+    pub(super) fn expected_semi_or_open_brace<T>(&mut self) -> PResult<'a, T> {
         let token_str = self.this_token_descr();
         let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str));
         err.span_label(self.token.span, "expected `;` or `{`");
         Err(err)
     }
 
-    crate fn eat_incorrect_doc_comment_for_param_type(&mut self) {
+    pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
         if let token::DocComment(_) = self.token.kind {
             self.struct_span_err(
                 self.token.span,
@@ -1337,7 +1299,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn parameter_without_type(
+    pub(super) fn parameter_without_type(
         &mut self,
         err: &mut DiagnosticBuilder<'_>,
         pat: P<ast::Pat>,
@@ -1400,7 +1362,7 @@ impl<'a> Parser<'a> {
         None
     }
 
-    crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
+    pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
         let pat = self.parse_pat(Some("argument name"))?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
@@ -1428,7 +1390,7 @@ impl<'a> Parser<'a> {
         Ok((pat, ty))
     }
 
-    crate fn recover_bad_self_param(
+    pub(super) fn recover_bad_self_param(
         &mut self,
         mut param: ast::Param,
         is_trait_item: bool,
@@ -1446,7 +1408,7 @@ impl<'a> Parser<'a> {
         Ok(param)
     }
 
-    crate fn consume_block(&mut self, delim: token::DelimToken) {
+    pub(super) fn consume_block(&mut self, delim: token::DelimToken) {
         let mut brace_depth = 0;
         loop {
             if self.eat(&token::OpenDelim(delim)) {
@@ -1466,7 +1428,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
+    pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
         let (span, msg) = match (&self.token.kind, self.subparser_name) {
             (&token::Eof, Some(origin)) => {
                 let sp = self.sess.source_map().next_point(self.token.span);
@@ -1511,7 +1473,7 @@ impl<'a> Parser<'a> {
     /// the parameters are *names* (so we don't emit errors about not being able to find `b` in
     /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`,
     /// we deduplicate them to not complain about duplicated parameter names.
-    crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec<Param>) {
+    pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec<Param>) {
         let mut seen_inputs = FxHashSet::default();
         for input in fn_inputs.iter_mut() {
             let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = (
diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs
index b459782d237..67a530ec683 100644
--- a/src/libsyntax/parse/parser/expr.rs
+++ b/src/libsyntax/parse/parser/expr.rs
@@ -1,18 +1,18 @@
-use super::{
-    Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode, SemiColonMode,
-    SeqSep, TokenExpectType,
-};
+use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode};
+use super::{SemiColonMode, SeqSep, TokenExpectType};
 use super::pat::{GateOr, PARAM_EXPECTED};
+use super::diagnostics::Error;
+
+use crate::parse::literal::LitError;
 
 use crate::ast::{
     self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
     Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
-    FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field,
+    FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit,
 };
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use crate::parse::classify;
-use crate::parse::token::{self, Token};
-use crate::parse::diagnostics::Error;
+use crate::parse::token::{self, Token, TokenKind};
 use crate::print::pprust;
 use crate::ptr::P;
 use crate::source_map::{self, Span};
@@ -20,6 +20,7 @@ use crate::symbol::{kw, sym};
 use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
 
 use errors::Applicability;
+use syntax_pos::Symbol;
 use std::mem;
 use rustc_data_structures::thin_vec::ThinVec;
 
@@ -422,7 +423,7 @@ impl<'a> Parser<'a> {
                 self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator")
                     .span_suggestion_short(
                         span_of_tilde,
-                        "use `!` to perform bitwise negation",
+                        "use `!` to perform bitwise not",
                         "!".to_owned(),
                         Applicability::MachineApplicable
                     )
@@ -552,8 +553,11 @@ impl<'a> Parser<'a> {
 
                         // 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 {}", path, op_noun);
+                        let msg = format!(
+                            "`<` is interpreted as a start of generic arguments for `{}`, not a {}",
+                            pprust::path_to_string(&path),
+                            op_noun,
+                        );
                         let span_after_type = parser_snapshot_after_type.token.span;
                         let expr = mk_expr(self, P(Ty {
                             span: path.span,
@@ -1069,8 +1073,167 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    /// Matches `lit = true | false | token_lit`.
+    pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> {
+        let mut recovered = None;
+        if self.token == token::Dot {
+            // Attempt to recover `.4` as `0.4`.
+            recovered = self.look_ahead(1, |next_token| {
+                if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
+                        = next_token.kind {
+                    if self.token.span.hi() == next_token.span.lo() {
+                        let s = String::from("0.") + &symbol.as_str();
+                        let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
+                        return Some(Token::new(kind, self.token.span.to(next_token.span)));
+                    }
+                }
+                None
+            });
+            if let Some(token) = &recovered {
+                self.bump();
+                self.struct_span_err(token.span, "float literals must have an integer part")
+                    .span_suggestion(
+                        token.span,
+                        "must have an integer part",
+                        pprust::token_to_string(token),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            }
+        }
+
+        let token = recovered.as_ref().unwrap_or(&self.token);
+        match Lit::from_token(token) {
+            Ok(lit) => {
+                self.bump();
+                Ok(lit)
+            }
+            Err(LitError::NotLiteral) => {
+                let msg = format!("unexpected token: {}", self.this_token_descr());
+                Err(self.span_fatal(token.span, &msg))
+            }
+            Err(err) => {
+                let (lit, span) = (token.expect_lit(), token.span);
+                self.bump();
+                self.error_literal_from_token(err, lit, span);
+                // Pack possible quotes and prefixes from the original literal into
+                // the error literal's symbol so they can be pretty-printed faithfully.
+                let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None);
+                let symbol = Symbol::intern(&suffixless_lit.to_string());
+                let lit = token::Lit::new(token::Err, symbol, lit.suffix);
+                Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
+            }
+        }
+    }
+
+    fn error_literal_from_token(&self, err: LitError, lit: token::Lit, span: Span) {
+        // Checks if `s` looks like i32 or u1234 etc.
+        fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
+            s.len() > 1
+            && s.starts_with(first_chars)
+            && s[1..].chars().all(|c| c.is_ascii_digit())
+        }
+
+        let token::Lit { kind, suffix, .. } = lit;
+        match err {
+            // `NotLiteral` is not an error by itself, so we don't report
+            // it and give the parser opportunity to try something else.
+            LitError::NotLiteral => {}
+            // `LexerError` *is* an error, but it was already reported
+            // by lexer, so here we don't report it the second time.
+            LitError::LexerError => {}
+            LitError::InvalidSuffix => {
+                self.expect_no_suffix(
+                    span,
+                    &format!("{} {} literal", kind.article(), kind.descr()),
+                    suffix,
+                );
+            }
+            LitError::InvalidIntSuffix => {
+                let suf = suffix.expect("suffix error with no suffix").as_str();
+                if looks_like_width_suffix(&['i', 'u'], &suf) {
+                    // If it looks like a width, try to be helpful.
+                    let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
+                    self.struct_span_err(span, &msg)
+                        .help("valid widths are 8, 16, 32, 64 and 128")
+                        .emit();
+                } else {
+                    let msg = format!("invalid suffix `{}` for integer literal", suf);
+                    self.struct_span_err(span, &msg)
+                        .span_label(span, format!("invalid suffix `{}`", suf))
+                        .help("the suffix must be one of the integral types (`u32`, `isize`, etc)")
+                        .emit();
+                }
+            }
+            LitError::InvalidFloatSuffix => {
+                let suf = suffix.expect("suffix error with no suffix").as_str();
+                if looks_like_width_suffix(&['f'], &suf) {
+                    // If it looks like a width, try to be helpful.
+                    let msg = format!("invalid width `{}` for float literal", &suf[1..]);
+                    self.struct_span_err(span, &msg)
+                        .help("valid widths are 32 and 64")
+                        .emit();
+                } else {
+                    let msg = format!("invalid suffix `{}` for float literal", suf);
+                    self.struct_span_err(span, &msg)
+                        .span_label(span, format!("invalid suffix `{}`", suf))
+                        .help("valid suffixes are `f32` and `f64`")
+                        .emit();
+                }
+            }
+            LitError::NonDecimalFloat(base) => {
+                let descr = match base {
+                    16 => "hexadecimal",
+                    8 => "octal",
+                    2 => "binary",
+                    _ => unreachable!(),
+                };
+                self.struct_span_err(span, &format!("{} float literal is not supported", descr))
+                    .span_label(span, "not supported")
+                    .emit();
+            }
+            LitError::IntTooLarge => {
+                self.struct_span_err(span, "integer literal is too large")
+                    .emit();
+            }
+        }
+    }
+
+    pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbol>) {
+        if let Some(suf) = suffix {
+            let mut err = if kind == "a tuple index"
+                && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf)
+            {
+                // #59553: warn instead of reject out of hand to allow the fix to percolate
+                // through the ecosystem when people fix their macros
+                let mut err = self.sess.span_diagnostic.struct_span_warn(
+                    sp,
+                    &format!("suffixes on {} are invalid", kind),
+                );
+                err.note(&format!(
+                    "`{}` is *temporarily* accepted on tuple index fields as it was \
+                        incorrectly accepted on stable for a few releases",
+                    suf,
+                ));
+                err.help(
+                    "on proc macros, you'll want to use `syn::Index::from` or \
+                        `proc_macro::Literal::*_unsuffixed` for code that will desugar \
+                        to tuple field access",
+                );
+                err.note(
+                    "for more context, see https://github.com/rust-lang/rust/issues/60210",
+                );
+                err
+            } else {
+                self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
+            };
+            err.span_label(sp, format!("invalid suffix `{}`", suf));
+            err.emit();
+        }
+    }
+
     /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
-    crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
+    pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
         maybe_whole_expr!(self);
 
         let minus_lo = self.token.span;
@@ -1090,7 +1253,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block or unsafe block.
-    crate fn parse_block_expr(
+    pub(super) fn parse_block_expr(
         &mut self,
         opt_label: Option<Label>,
         lo: Span,
@@ -1395,7 +1558,7 @@ impl<'a> Parser<'a> {
         return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs));
     }
 
-    crate fn parse_arm(&mut self) -> PResult<'a, Arm> {
+    pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
         let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
         let pat = self.parse_top_pat(GateOr::No)?;
@@ -1503,7 +1666,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an `async move? {...}` expression.
-    pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
+    fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let span_lo = self.token.span;
         self.expect_keyword(kw::Async)?;
         let capture_clause = self.parse_capture_clause();
@@ -1783,4 +1946,8 @@ impl<'a> Parser<'a> {
     crate fn mk_expr(&self, span: Span, kind: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr { kind, span, attrs, id: DUMMY_NODE_ID })
     }
+
+    pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> {
+        self.mk_expr(span, ExprKind::Err, ThinVec::new())
+    }
 }
diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs
index 2ecd9cca3c6..bfcb0042a75 100644
--- a/src/libsyntax/parse/parser/generics.rs
+++ b/src/libsyntax/parse/parser/generics.rs
@@ -74,7 +74,7 @@ impl<'a> Parser<'a> {
 
     /// Parses a (possibly empty) list of lifetime and type parameters, possibly including
     /// a trailing comma and erroneous trailing attributes.
-    crate fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
+    pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
         let mut params = Vec::new();
         loop {
             let attrs = self.parse_outer_attributes()?;
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index 3c60c88e2aa..73bd80e2a21 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -1,34 +1,28 @@
-use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode, ParamCfg};
+use super::{Parser, PResult, PathStyle, SemiColonMode, BlockMode};
+use super::diagnostics::{Error, dummy_arg};
 
 use crate::maybe_whole;
 use crate::ptr::P;
-use crate::ast::{
-    self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle,
-    Item, ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind,
-    UseTree, UseTreeKind, PathSegment,
-    IsAuto, Constness, IsAsync, Unsafety, Defaultness,
-    Visibility, VisibilityKind, Mutability, FnDecl, FnHeader, MethodSig, Block,
-    ForeignItem, ForeignItemKind,
-    Ty, TyKind, Generics, GenericBounds, TraitRef,
-    EnumDef, VariantData, StructField, AnonConst,
-    Mac, MacDelimiter,
-};
-use crate::ext::base::DummyResult;
+use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind};
+use crate::ast::{ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
+use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness};
+use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
+use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField};
+use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param};
 use crate::parse::token;
-use crate::parse::parser::maybe_append;
-use crate::parse::diagnostics::Error;
 use crate::tokenstream::{TokenTree, TokenStream};
-use crate::source_map::{respan, Span};
 use crate::symbol::{kw, sym};
+use crate::source_map::{self, respan, Span};
+use crate::ThinVec;
 
-use std::mem;
 use log::debug;
+use std::mem;
 use rustc_target::spec::abi::Abi;
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey};
 
 /// Whether the type alias or associated type is a concrete type or an opaque type.
 #[derive(Debug)]
-pub enum AliasKind {
+pub(super) enum AliasKind {
     /// Just a new name for the same type.
     Weak(P<Ty>),
     /// Only trait impls of the type will be usable, not the actual type itself.
@@ -412,7 +406,7 @@ impl<'a> Parser<'a> {
         self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
     }
 
-    fn mk_item_with_info(
+    pub(super) fn mk_item_with_info(
         &self,
         attrs: Vec<Attribute>,
         lo: Span,
@@ -421,18 +415,15 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, Option<P<Item>>> {
         let (ident, item, extra_attrs) = info;
         let span = lo.to(self.prev_span);
-        let attrs = maybe_append(attrs, extra_attrs);
+        let attrs = Self::maybe_append(attrs, extra_attrs);
         Ok(Some(self.mk_item(span, ident, item, vis, attrs)))
     }
 
-    fn recover_first_param(&mut self) -> &'static str {
-        match self.parse_outer_attributes()
-            .and_then(|_| self.parse_self_param())
-            .map_err(|mut e| e.cancel())
-        {
-            Ok(Some(_)) => "method",
-            _ => "function",
+    fn maybe_append<T>(mut lhs: Vec<T>, mut rhs: Option<Vec<T>>) -> Vec<T> {
+        if let Some(ref mut rhs) = rhs {
+            lhs.append(rhs);
         }
+        lhs
     }
 
     /// This is the fall-through for parsing items.
@@ -620,7 +611,7 @@ impl<'a> Parser<'a> {
         let ty_second = if self.token == token::DotDot {
             // We need to report this error after `cfg` expansion for compatibility reasons
             self.bump(); // `..`, do not add it to expected tokens
-            Some(DummyResult::raw_ty(self.prev_span, true))
+            Some(self.mk_ty(self.prev_span, TyKind::Err))
         } else if has_for || self.token.can_begin_type() {
             Some(self.parse_ty()?)
         } else {
@@ -707,9 +698,11 @@ impl<'a> Parser<'a> {
         Ok(item)
     }
 
-    fn parse_impl_item_(&mut self,
-                        at_end: &mut bool,
-                        mut attrs: Vec<Attribute>) -> PResult<'a, ImplItem> {
+    fn parse_impl_item_(
+        &mut self,
+        at_end: &mut bool,
+        mut attrs: Vec<Attribute>,
+    ) -> PResult<'a, ImplItem> {
         let lo = self.token.span;
         let vis = self.parse_visibility(false)?;
         let defaultness = self.parse_defaultness();
@@ -722,8 +715,11 @@ impl<'a> Parser<'a> {
             (name, kind, generics)
         } else if self.is_const_item() {
             self.parse_impl_const()?
+        } else if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(&vis), at_end)? {
+            // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
+            (Ident::invalid(), ast::ImplItemKind::Macro(mac), Generics::default())
         } else {
-            let (name, inner_attrs, generics, kind) = self.parse_impl_method(&vis, at_end)?;
+            let (name, inner_attrs, generics, kind) = self.parse_impl_method(at_end)?;
             attrs.extend(inner_attrs);
             (name, kind, generics)
         };
@@ -783,71 +779,6 @@ impl<'a> Parser<'a> {
         Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
     }
 
-    /// Parses a method or a macro invocation in a trait impl.
-    fn parse_impl_method(
-        &mut self,
-        vis: &Visibility,
-        at_end: &mut bool
-    ) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
-        // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
-        if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(vis), at_end)? {
-            // method macro
-            Ok((Ident::invalid(), vec![], Generics::default(), ast::ImplItemKind::Macro(mac)))
-        } else {
-            let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
-            *at_end = true;
-            let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-            Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
-        }
-    }
-
-    /// Parse the "signature", including the identifier, parameters, and generics
-    /// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
-    fn parse_method_sig(
-        &mut self,
-        is_name_required: fn(&token::Token) -> bool,
-    ) -> PResult<'a, (Ident, MethodSig, Generics)> {
-        let header = self.parse_fn_front_matter()?;
-        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
-            is_self_allowed: true,
-            allow_c_variadic: false,
-            is_name_required,
-        })?;
-        Ok((ident, MethodSig { header, decl }, generics))
-    }
-
-    /// Parses all the "front matter" for a `fn` declaration, up to
-    /// and including the `fn` keyword:
-    ///
-    /// - `const fn`
-    /// - `unsafe fn`
-    /// - `const unsafe fn`
-    /// - `extern fn`
-    /// - etc.
-    fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
-        let is_const_fn = self.eat_keyword(kw::Const);
-        let const_span = self.prev_span;
-        let asyncness = self.parse_asyncness();
-        if let IsAsync::Async { .. } = asyncness {
-            self.ban_async_in_2015(self.prev_span);
-        }
-        let asyncness = respan(self.prev_span, asyncness);
-        let unsafety = self.parse_unsafety();
-        let (constness, unsafety, abi) = if is_const_fn {
-            (respan(const_span, Constness::Const), unsafety, Abi::Rust)
-        } else {
-            let abi = self.parse_extern_abi()?;
-            (respan(self.prev_span, Constness::NotConst), unsafety, abi)
-        };
-        if !self.eat_keyword(kw::Fn) {
-            // It is possible for `expect_one_of` to recover given the contents of
-            // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
-            // account for this.
-            if !self.expect_one_of(&[], &[])? { unreachable!() }
-        }
-        Ok(FnHeader { constness, unsafety, asyncness, abi })
-    }
-
     /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
         // Parse optional `auto` prefix.
@@ -957,13 +888,7 @@ impl<'a> Parser<'a> {
             // trait item macro.
             (Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
         } else {
-            // This is somewhat dubious; We don't want to allow
-            // argument names to be left off if there is a definition...
-            //
-            // We don't allow argument names to be left off in edition 2018.
-            let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
-            let body = self.parse_trait_method_body(at_end, &mut attrs)?;
-            (ident, TraitItemKind::Method(sig, body), generics)
+            self.parse_trait_item_method(at_end, &mut attrs)?
         };
 
         Ok(TraitItem {
@@ -991,43 +916,6 @@ impl<'a> Parser<'a> {
         Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
     }
 
-    /// Parse the "body" of a method in a trait item definition.
-    /// This can either be `;` when there's no body,
-    /// or e.g. a block when the method is a provided one.
-    fn parse_trait_method_body(
-        &mut self,
-        at_end: &mut bool,
-        attrs: &mut Vec<Attribute>,
-    ) -> PResult<'a, Option<P<Block>>> {
-        Ok(match self.token.kind {
-            token::Semi => {
-                debug!("parse_trait_method_body(): parsing required method");
-                self.bump();
-                *at_end = true;
-                None
-            }
-            token::OpenDelim(token::Brace) => {
-                debug!("parse_trait_method_body(): parsing provided method");
-                *at_end = true;
-                let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-                attrs.extend(inner_attrs.iter().cloned());
-                Some(body)
-            }
-            token::Interpolated(ref nt) => {
-                match **nt {
-                    token::NtBlock(..) => {
-                        *at_end = true;
-                        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-                        attrs.extend(inner_attrs.iter().cloned());
-                        Some(body)
-                    }
-                    _ => return self.expected_semi_or_open_brace(),
-                }
-            }
-            _ => return self.expected_semi_or_open_brace(),
-        })
-    }
-
     /// Parses the following grammar:
     ///
     ///     TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
@@ -1194,45 +1082,6 @@ impl<'a> Parser<'a> {
         Ok(ident)
     }
 
-    /// Parses an item-position function declaration.
-    fn parse_item_fn(
-        &mut self,
-        lo: Span,
-        vis: Visibility,
-        attrs: Vec<Attribute>,
-        header: FnHeader,
-    ) -> PResult<'a, Option<P<Item>>> {
-        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
-            is_self_allowed: false,
-            allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
-            is_name_required: |_| true,
-        })?;
-        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-        let kind = ItemKind::Fn(decl, header, generics, body);
-        self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
-    }
-
-    /// Parse the "signature", including the identifier, parameters, and generics of a function.
-    fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
-        let ident = self.parse_ident()?;
-        let mut generics = self.parse_generics()?;
-        let decl = self.parse_fn_decl(cfg, true)?;
-        generics.where_clause = self.parse_where_clause()?;
-        Ok((ident, decl, generics))
-    }
-
-    /// Parses the parameter list and result type of a function declaration.
-    pub(super) fn parse_fn_decl(
-        &mut self,
-        cfg: ParamCfg,
-        ret_allow_plus: bool,
-    ) -> PResult<'a, P<FnDecl>> {
-        Ok(P(FnDecl {
-            inputs: self.parse_fn_params(cfg)?,
-            output: self.parse_ret_ty(ret_allow_plus)?,
-        }))
-    }
-
     /// Parses `extern` for foreign ABIs modules.
     ///
     /// `extern` is expected to have been
@@ -1273,7 +1122,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a foreign item.
-    crate fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, ForeignItem> {
+    pub fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, ForeignItem> {
         maybe_whole!(self, NtForeignItem, |ni| ni);
 
         let attrs = self.parse_outer_attributes()?;
@@ -1344,32 +1193,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parses a function declaration from a foreign module.
-    fn parse_item_foreign_fn(
-        &mut self,
-        vis: ast::Visibility,
-        lo: Span,
-        attrs: Vec<Attribute>,
-        extern_sp: Span,
-    ) -> PResult<'a, ForeignItem> {
-        self.expect_keyword(kw::Fn)?;
-        let (ident, decl, generics) = self.parse_fn_sig(super::ParamCfg {
-            is_self_allowed: false,
-            allow_c_variadic: true,
-            is_name_required: |_| true,
-        })?;
-        let span = lo.to(self.token.span);
-        self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
-        Ok(ast::ForeignItem {
-            ident,
-            attrs,
-            kind: ForeignItemKind::Fn(decl, generics),
-            id: DUMMY_NODE_ID,
-            span,
-            vis,
-        })
-    }
-
     /// Parses a static item from a foreign module.
     /// Assumes that the `static` keyword is already parsed.
     fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
@@ -1910,3 +1733,466 @@ impl<'a> Parser<'a> {
         })
     }
 }
+
+/// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
+pub(super) struct ParamCfg {
+    /// Is `self` is allowed as the first parameter?
+    pub is_self_allowed: bool,
+    /// Is `...` allowed as the tail of the parameter list?
+    pub allow_c_variadic: bool,
+    /// `is_name_required` decides if, per-parameter,
+    /// the parameter must have a pattern or just a type.
+    pub is_name_required: fn(&token::Token) -> bool,
+}
+
+/// Parsing of functions and methods.
+impl<'a> Parser<'a> {
+    /// Parses an item-position function declaration.
+    fn parse_item_fn(
+        &mut self,
+        lo: Span,
+        vis: Visibility,
+        attrs: Vec<Attribute>,
+        header: FnHeader,
+    ) -> PResult<'a, Option<P<Item>>> {
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: false,
+            allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe,
+            is_name_required: |_| true,
+        })?;
+        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+        let kind = ItemKind::Fn(decl, header, generics, body);
+        self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
+    }
+
+    /// Parses a function declaration from a foreign module.
+    fn parse_item_foreign_fn(
+        &mut self,
+        vis: ast::Visibility,
+        lo: Span,
+        attrs: Vec<Attribute>,
+        extern_sp: Span,
+    ) -> PResult<'a, ForeignItem> {
+        self.expect_keyword(kw::Fn)?;
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: false,
+            allow_c_variadic: true,
+            is_name_required: |_| true,
+        })?;
+        let span = lo.to(self.token.span);
+        self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
+        Ok(ast::ForeignItem {
+            ident,
+            attrs,
+            kind: ForeignItemKind::Fn(decl, generics),
+            id: DUMMY_NODE_ID,
+            span,
+            vis,
+        })
+    }
+
+    /// Parses a method or a macro invocation in a trait impl.
+    fn parse_impl_method(
+        &mut self,
+        at_end: &mut bool,
+    ) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
+        let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
+        *at_end = true;
+        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+        Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
+    }
+
+    fn parse_trait_item_method(
+        &mut self,
+        at_end: &mut bool,
+        attrs: &mut Vec<Attribute>,
+    ) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+        // This is somewhat dubious; We don't want to allow
+        // argument names to be left off if there is a definition...
+        //
+        // We don't allow argument names to be left off in edition 2018.
+        let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
+        let body = self.parse_trait_method_body(at_end, attrs)?;
+        Ok((ident, TraitItemKind::Method(sig, body), generics))
+    }
+
+    /// Parse the "body" of a method in a trait item definition.
+    /// This can either be `;` when there's no body,
+    /// or e.g. a block when the method is a provided one.
+    fn parse_trait_method_body(
+        &mut self,
+        at_end: &mut bool,
+        attrs: &mut Vec<Attribute>,
+    ) -> PResult<'a, Option<P<Block>>> {
+        Ok(match self.token.kind {
+            token::Semi => {
+                debug!("parse_trait_method_body(): parsing required method");
+                self.bump();
+                *at_end = true;
+                None
+            }
+            token::OpenDelim(token::Brace) => {
+                debug!("parse_trait_method_body(): parsing provided method");
+                *at_end = true;
+                let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+                attrs.extend(inner_attrs.iter().cloned());
+                Some(body)
+            }
+            token::Interpolated(ref nt) => {
+                match **nt {
+                    token::NtBlock(..) => {
+                        *at_end = true;
+                        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+                        attrs.extend(inner_attrs.iter().cloned());
+                        Some(body)
+                    }
+                    _ => return self.expected_semi_or_open_brace(),
+                }
+            }
+            _ => return self.expected_semi_or_open_brace(),
+        })
+    }
+
+    /// Parse the "signature", including the identifier, parameters, and generics
+    /// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
+    fn parse_method_sig(
+        &mut self,
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, (Ident, MethodSig, Generics)> {
+        let header = self.parse_fn_front_matter()?;
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: true,
+            allow_c_variadic: false,
+            is_name_required,
+        })?;
+        Ok((ident, MethodSig { header, decl }, generics))
+    }
+
+    /// Parses all the "front matter" for a `fn` declaration, up to
+    /// and including the `fn` keyword:
+    ///
+    /// - `const fn`
+    /// - `unsafe fn`
+    /// - `const unsafe fn`
+    /// - `extern fn`
+    /// - etc.
+    fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
+        let is_const_fn = self.eat_keyword(kw::Const);
+        let const_span = self.prev_span;
+        let asyncness = self.parse_asyncness();
+        if let IsAsync::Async { .. } = asyncness {
+            self.ban_async_in_2015(self.prev_span);
+        }
+        let asyncness = respan(self.prev_span, asyncness);
+        let unsafety = self.parse_unsafety();
+        let (constness, unsafety, abi) = if is_const_fn {
+            (respan(const_span, Constness::Const), unsafety, Abi::Rust)
+        } else {
+            let abi = self.parse_extern_abi()?;
+            (respan(self.prev_span, Constness::NotConst), unsafety, abi)
+        };
+        if !self.eat_keyword(kw::Fn) {
+            // It is possible for `expect_one_of` to recover given the contents of
+            // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
+            // account for this.
+            if !self.expect_one_of(&[], &[])? { unreachable!() }
+        }
+        Ok(FnHeader { constness, unsafety, asyncness, abi })
+    }
+
+    /// Parse the "signature", including the identifier, parameters, and generics of a function.
+    fn parse_fn_sig(&mut self, cfg: ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
+        let ident = self.parse_ident()?;
+        let mut generics = self.parse_generics()?;
+        let decl = self.parse_fn_decl(cfg, true)?;
+        generics.where_clause = self.parse_where_clause()?;
+        Ok((ident, decl, generics))
+    }
+
+    /// Parses the parameter list and result type of a function declaration.
+    pub(super) fn parse_fn_decl(
+        &mut self,
+        cfg: ParamCfg,
+        ret_allow_plus: bool,
+    ) -> PResult<'a, P<FnDecl>> {
+        Ok(P(FnDecl {
+            inputs: self.parse_fn_params(cfg)?,
+            output: self.parse_ret_ty(ret_allow_plus)?,
+        }))
+    }
+
+    /// Parses the parameter list of a function, including the `(` and `)` delimiters.
+    fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
+        let sp = self.token.span;
+        let is_trait_item = cfg.is_self_allowed;
+        let mut c_variadic = false;
+        // Parse the arguments, starting out with `self` being possibly allowed...
+        let (params, _) = self.parse_paren_comma_seq(|p| {
+            let param = p.parse_param_general(&cfg, is_trait_item);
+            // ...now that we've parsed the first argument, `self` is no longer allowed.
+            cfg.is_self_allowed = false;
+
+            match param {
+                Ok(param) => Ok(
+                    if let TyKind::CVarArgs = param.ty.kind {
+                        c_variadic = true;
+                        if p.token != token::CloseDelim(token::Paren) {
+                            p.span_err(
+                                p.token.span,
+                                "`...` must be the last argument of a C-variadic function",
+                            );
+                            // FIXME(eddyb) this should probably still push `CVarArgs`.
+                            // Maybe AST validation/HIR lowering should emit the above error?
+                            None
+                        } else {
+                            Some(param)
+                        }
+                    } else {
+                        Some(param)
+                    }
+                ),
+                Err(mut e) => {
+                    e.emit();
+                    let lo = p.prev_span;
+                    // Skip every token until next possible arg or end.
+                    p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+                    // Create a placeholder argument for proper arg count (issue #34264).
+                    let span = lo.to(p.prev_span);
+                    Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
+                }
+            }
+        })?;
+
+        let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
+
+        // Replace duplicated recovered params with `_` pattern to avoid unecessary errors.
+        self.deduplicate_recovered_params_names(&mut params);
+
+        if c_variadic && params.len() <= 1 {
+            self.span_err(
+                sp,
+                "C-variadic function must be declared with at least one named argument",
+            );
+        }
+
+        Ok(params)
+    }
+
+    /// Skips unexpected attributes and doc comments in this position and emits an appropriate
+    /// error.
+    /// This version of parse param doesn't necessarily require identifier names.
+    fn parse_param_general(&mut self, cfg: &ParamCfg, is_trait_item: bool) -> PResult<'a, Param> {
+        let lo = self.token.span;
+        let attrs = self.parse_outer_attributes()?;
+
+        // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
+        if let Some(mut param) = self.parse_self_param()? {
+            param.attrs = attrs.into();
+            return if cfg.is_self_allowed {
+                Ok(param)
+            } else {
+                self.recover_bad_self_param(param, is_trait_item)
+            };
+        }
+
+        let is_name_required = match self.token.kind {
+            token::DotDotDot => false,
+            _ => (cfg.is_name_required)(&self.token),
+        };
+        let (pat, ty) = if is_name_required || self.is_named_param() {
+            debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
+
+            let pat = self.parse_fn_param_pat()?;
+            if let Err(mut err) = self.expect(&token::Colon) {
+                return if let Some(ident) = self.parameter_without_type(
+                    &mut err,
+                    pat,
+                    is_name_required,
+                    cfg.is_self_allowed,
+                    is_trait_item,
+                ) {
+                    err.emit();
+                    Ok(dummy_arg(ident))
+                } else {
+                    Err(err)
+                };
+            }
+
+            self.eat_incorrect_doc_comment_for_param_type();
+            (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
+        } else {
+            debug!("parse_param_general ident_to_pat");
+            let parser_snapshot_before_ty = self.clone();
+            self.eat_incorrect_doc_comment_for_param_type();
+            let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
+            if ty.is_ok() && self.token != token::Comma &&
+               self.token != token::CloseDelim(token::Paren) {
+                // This wasn't actually a type, but a pattern looking like a type,
+                // so we are going to rollback and re-parse for recovery.
+                ty = self.unexpected();
+            }
+            match ty {
+                Ok(ty) => {
+                    let ident = Ident::new(kw::Invalid, self.prev_span);
+                    let bm = BindingMode::ByValue(Mutability::Immutable);
+                    let pat = self.mk_pat_ident(ty.span, bm, ident);
+                    (pat, ty)
+                }
+                // If this is a C-variadic argument and we hit an error, return the error.
+                Err(err) if self.token == token::DotDotDot => return Err(err),
+                // Recover from attempting to parse the argument as a type without pattern.
+                Err(mut err) => {
+                    err.cancel();
+                    mem::replace(self, parser_snapshot_before_ty);
+                    self.recover_arg_parse()?
+                }
+            }
+        };
+
+        let span = lo.to(self.token.span);
+
+        Ok(Param {
+            attrs: attrs.into(),
+            id: ast::DUMMY_NODE_ID,
+            is_placeholder: false,
+            pat,
+            span,
+            ty,
+        })
+    }
+
+    /// Returns the parsed optional self parameter and whether a self shortcut was used.
+    ///
+    /// See `parse_self_param_with_attrs` to collect attributes.
+    fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
+        // Extract an identifier *after* having confirmed that the token is one.
+        let expect_self_ident = |this: &mut Self| {
+            match this.token.kind {
+                // Preserve hygienic context.
+                token::Ident(name, _) => {
+                    let span = this.token.span;
+                    this.bump();
+                    Ident::new(name, span)
+                }
+                _ => unreachable!(),
+            }
+        };
+        // Is `self` `n` tokens ahead?
+        let is_isolated_self = |this: &Self, n| {
+            this.is_keyword_ahead(n, &[kw::SelfLower])
+            && this.look_ahead(n + 1, |t| t != &token::ModSep)
+        };
+        // Is `mut self` `n` tokens ahead?
+        let is_isolated_mut_self = |this: &Self, n| {
+            this.is_keyword_ahead(n, &[kw::Mut])
+            && is_isolated_self(this, n + 1)
+        };
+        // Parse `self` or `self: TYPE`. We already know the current token is `self`.
+        let parse_self_possibly_typed = |this: &mut Self, m| {
+            let eself_ident = expect_self_ident(this);
+            let eself_hi = this.prev_span;
+            let eself = if this.eat(&token::Colon) {
+                SelfKind::Explicit(this.parse_ty()?, m)
+            } else {
+                SelfKind::Value(m)
+            };
+            Ok((eself, eself_ident, eself_hi))
+        };
+        // Recover for the grammar `*self`, `*const self`, and `*mut self`.
+        let recover_self_ptr = |this: &mut Self| {
+            let msg = "cannot pass `self` by raw pointer";
+            let span = this.token.span;
+            this.struct_span_err(span, msg)
+                .span_label(span, msg)
+                .emit();
+
+            Ok((SelfKind::Value(Mutability::Immutable), expect_self_ident(this), this.prev_span))
+        };
+
+        // Parse optional `self` parameter of a method.
+        // Only a limited set of initial token sequences is considered `self` parameters; anything
+        // else is parsed as a normal function parameter list, so some lookahead is required.
+        let eself_lo = self.token.span;
+        let (eself, eself_ident, eself_hi) = match self.token.kind {
+            token::BinOp(token::And) => {
+                let eself = if is_isolated_self(self, 1) {
+                    // `&self`
+                    self.bump();
+                    SelfKind::Region(None, Mutability::Immutable)
+                } else if is_isolated_mut_self(self, 1) {
+                    // `&mut self`
+                    self.bump();
+                    self.bump();
+                    SelfKind::Region(None, Mutability::Mutable)
+                } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
+                    // `&'lt self`
+                    self.bump();
+                    let lt = self.expect_lifetime();
+                    SelfKind::Region(Some(lt), Mutability::Immutable)
+                } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) {
+                    // `&'lt mut self`
+                    self.bump();
+                    let lt = self.expect_lifetime();
+                    self.bump();
+                    SelfKind::Region(Some(lt), Mutability::Mutable)
+                } else {
+                    // `&not_self`
+                    return Ok(None);
+                };
+                (eself, expect_self_ident(self), self.prev_span)
+            }
+            // `*self`
+            token::BinOp(token::Star) if is_isolated_self(self, 1) => {
+                self.bump();
+                recover_self_ptr(self)?
+            }
+            // `*mut self` and `*const self`
+            token::BinOp(token::Star) if
+                self.look_ahead(1, |t| t.is_mutability())
+                && is_isolated_self(self, 2) =>
+            {
+                self.bump();
+                self.bump();
+                recover_self_ptr(self)?
+            }
+            // `self` and `self: TYPE`
+            token::Ident(..) if is_isolated_self(self, 0) => {
+                parse_self_possibly_typed(self, Mutability::Immutable)?
+            }
+            // `mut self` and `mut self: TYPE`
+            token::Ident(..) if is_isolated_mut_self(self, 0) => {
+                self.bump();
+                parse_self_possibly_typed(self, Mutability::Mutable)?
+            }
+            _ => return Ok(None),
+        };
+
+        let eself = source_map::respan(eself_lo.to(eself_hi), eself);
+        Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident)))
+    }
+
+    fn is_named_param(&self) -> bool {
+        let offset = match self.token.kind {
+            token::Interpolated(ref nt) => match **nt {
+                token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
+                _ => 0,
+            }
+            token::BinOp(token::And) | token::AndAnd => 1,
+            _ if self.token.is_keyword(kw::Mut) => 1,
+            _ => 0,
+        };
+
+        self.look_ahead(offset, |t| t.is_ident()) &&
+        self.look_ahead(offset + 1, |t| t == &token::Colon)
+    }
+
+    fn recover_first_param(&mut self) -> &'static str {
+        match self.parse_outer_attributes()
+            .and_then(|_| self.parse_self_param())
+            .map_err(|mut e| e.cancel())
+        {
+            Ok(Some(_)) => "method",
+            _ => "function",
+        }
+    }
+}
diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs
index 2d2fb487d7d..a0e4d2bbb7a 100644
--- a/src/libsyntax/parse/parser/module.rs
+++ b/src/libsyntax/parse/parser/module.rs
@@ -1,24 +1,24 @@
 use super::{Parser, PResult};
 use super::item::ItemInfo;
+use super::diagnostics::Error;
 
 use crate::attr;
 use crate::ast::{self, Ident, Attribute, ItemKind, Mod, Crate};
 use crate::parse::{new_sub_parser_from_file, DirectoryOwnership};
 use crate::parse::token::{self, TokenKind};
-use crate::parse::diagnostics::{Error};
 use crate::source_map::{SourceMap, Span, DUMMY_SP, FileName};
 use crate::symbol::sym;
 
 use std::path::{self, Path, PathBuf};
 
 /// Information about the path to a module.
-pub struct ModulePath {
+pub(super) struct ModulePath {
     name: String,
     path_exists: bool,
     pub result: Result<ModulePathSuccess, Error>,
 }
 
-pub struct ModulePathSuccess {
+pub(super) struct ModulePathSuccess {
     pub path: PathBuf,
     pub directory_ownership: DirectoryOwnership,
     warn: bool,
@@ -39,6 +39,8 @@ impl<'a> Parser<'a> {
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
     pub(super) fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> {
         let (in_cfg, outer_attrs) = {
+            // FIXME(Centril): This results in a cycle between config and parsing.
+            // Consider using dynamic dispatch via `self.sess` to disentangle the knot.
             let mut strip_unconfigured = crate::config::StripUnconfigured {
                 sess: self.sess,
                 features: None, // Don't perform gated feature checking.
@@ -198,7 +200,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
+    pub(super) fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
         if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) {
             let s = s.as_str();
 
@@ -215,7 +217,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Returns a path to a module.
-    pub fn default_submod_path(
+    pub(super) fn default_submod_path(
         id: ast::Ident,
         relative: Option<ast::Ident>,
         dir_path: &Path,
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 48f9e301610..af795e51792 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -22,7 +22,7 @@ const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"
 
 /// Whether or not an or-pattern should be gated when occurring in the current context.
 #[derive(PartialEq)]
-pub enum GateOr { Yes, No }
+pub(super) enum GateOr { Yes, No }
 
 /// Whether or not to recover a `,` when parsing or-patterns.
 #[derive(PartialEq, Copy, Clone)]
@@ -367,6 +367,7 @@ impl<'a> Parser<'a> {
 
         let pat = self.mk_pat(lo.to(self.prev_span), pat);
         let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
+        let pat = self.recover_intersection_pat(pat)?;
 
         if !allow_range_pat {
             self.ban_pat_range_if_ambiguous(&pat)?
@@ -375,6 +376,65 @@ impl<'a> Parser<'a> {
         Ok(pat)
     }
 
+    /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
+    ///
+    /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs`
+    /// should already have been parsed by now  at this point,
+    /// if the next token is `@` then we can try to parse the more general form.
+    ///
+    /// Consult `parse_pat_ident` for the `binding` grammar.
+    ///
+    /// The notion of intersection patterns are found in
+    /// e.g. [F#][and] where they are called AND-patterns.
+    ///
+    /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
+    fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
+        if self.token.kind != token::At {
+            // Next token is not `@` so it's not going to be an intersection pattern.
+            return Ok(lhs);
+        }
+
+        // At this point we attempt to parse `@ $pat_rhs` and emit an error.
+        self.bump(); // `@`
+        let mut rhs = self.parse_pat(None)?;
+        let sp = lhs.span.to(rhs.span);
+
+        if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
+            // The user inverted the order, so help them fix that.
+            let mut applicability = Applicability::MachineApplicable;
+            lhs.walk(&mut |p| match p.kind {
+                // `check_match` is unhappy if the subpattern has a binding anywhere.
+                PatKind::Ident(..) => {
+                    applicability = Applicability::MaybeIncorrect;
+                    false // Short-circuit.
+                },
+                _ => true,
+            });
+
+            let lhs_span = lhs.span;
+            // Move the LHS into the RHS as a subpattern.
+            // The RHS is now the full pattern.
+            *sub = Some(lhs);
+
+            self.struct_span_err(sp, "pattern on wrong side of `@`")
+                .span_label(lhs_span, "pattern on the left, should be on the right")
+                .span_label(rhs.span, "binding on the right, should be on the left")
+                .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability)
+                .emit();
+        } else {
+            // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
+            rhs.kind = PatKind::Wild;
+            self.struct_span_err(sp, "left-hand side of `@` must be a binding")
+                .span_label(lhs.span, "interpreted as a pattern, not a binding")
+                .span_label(rhs.span, "also a pattern")
+                .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`")
+                .emit();
+        }
+
+        rhs.span = sp;
+        Ok(rhs)
+    }
+
     /// Ban a range pattern if it has an ambiguous interpretation.
     fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> {
         match pat.kind {
diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs
index ca823991a2e..639d61a2b5c 100644
--- a/src/libsyntax/parse/parser/path.rs
+++ b/src/libsyntax/parse/parser/path.rs
@@ -111,7 +111,7 @@ impl<'a> Parser<'a> {
     /// Like `parse_path`, but also supports parsing `Word` meta items into paths for
     /// backwards-compatibility. This is used when parsing derive macro paths in `#[derive]`
     /// attributes.
-    pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
+    fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
         let meta_ident = match self.token.kind {
             token::Interpolated(ref nt) => match **nt {
                 token::NtMeta(ref item) => match item.tokens.is_empty() {
@@ -129,7 +129,22 @@ impl<'a> Parser<'a> {
         self.parse_path(style)
     }
 
-    crate fn parse_path_segments(
+    /// Parse a list of paths inside `#[derive(path_0, ..., path_n)]`.
+    crate fn parse_derive_paths(&mut self) -> PResult<'a, Vec<Path>> {
+        self.expect(&token::OpenDelim(token::Paren))?;
+        let mut list = Vec::new();
+        while !self.eat(&token::CloseDelim(token::Paren)) {
+            let path = self.parse_path_allowing_meta(PathStyle::Mod)?;
+            list.push(path);
+            if !self.eat(&token::Comma) {
+                self.expect(&token::CloseDelim(token::Paren))?;
+                break
+            }
+        }
+        Ok(list)
+    }
+
+    pub(super) fn parse_path_segments(
         &mut self,
         segments: &mut Vec<PathSegment>,
         style: PathStyle,
diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs
index 855b03ddd6f..d54d9c4b8e9 100644
--- a/src/libsyntax/parse/parser/stmt.rs
+++ b/src/libsyntax/parse/parser/stmt.rs
@@ -2,14 +2,13 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, SemiColonMode, BlockMo
 use super::expr::LhsExpr;
 use super::path::PathStyle;
 use super::pat::GateOr;
+use super::diagnostics::Error;
 
 use crate::ptr::P;
 use crate::{maybe_whole, ThinVec};
 use crate::ast::{self, DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind};
 use crate::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter};
-use crate::ext::base::DummyResult;
 use crate::parse::{classify, DirectoryOwnership};
-use crate::parse::diagnostics::Error;
 use crate::parse::token;
 use crate::source_map::{respan, Span};
 use crate::symbol::{kw, sym};
@@ -373,7 +372,9 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block. Inner attributes are allowed.
-    crate fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
+    pub(super) fn parse_inner_attrs_and_block(
+        &mut self
+    ) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
         maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
 
         let lo = self.token.span;
@@ -400,7 +401,7 @@ impl<'a> Parser<'a> {
                     self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
                     Some(Stmt {
                         id: DUMMY_NODE_ID,
-                        kind: StmtKind::Expr(DummyResult::raw_expr(self.token.span, true)),
+                        kind: StmtKind::Expr(self.mk_expr_err(self.token.span)),
                         span: self.token.span,
                     })
                 }
@@ -422,7 +423,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a statement, including the trailing semicolon.
-    crate fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
+    pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
         maybe_whole!(self, NtStmt, |x| Some(x));
 
@@ -443,7 +444,7 @@ impl<'a> Parser<'a> {
                         self.recover_stmt();
                         // Don't complain about type errors in body tail after parse error (#57383).
                         let sp = expr.span.to(self.prev_span);
-                        stmt.kind = StmtKind::Expr(DummyResult::raw_expr(sp, true));
+                        stmt.kind = StmtKind::Expr(self.mk_expr_err(sp));
                     }
                 }
             }
diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs
index 018b5951e6e..86c94b680b2 100644
--- a/src/libsyntax/parse/parser/ty.rs
+++ b/src/libsyntax/parse/parser/ty.rs
@@ -1,4 +1,5 @@
 use super::{Parser, PResult, PathStyle, PrevTokenKind, TokenType};
+use super::item::ParamCfg;
 
 use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath};
 use crate::ptr::P;
@@ -209,7 +210,7 @@ impl<'a> Parser<'a> {
         };
 
         let span = lo.to(self.prev_span);
-        let ty = P(Ty { kind, span, id: ast::DUMMY_NODE_ID });
+        let ty = self.mk_ty(span, kind);
 
         // Try to recover from use of `+` with incorrect priority.
         self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
@@ -281,7 +282,7 @@ impl<'a> Parser<'a> {
         let unsafety = self.parse_unsafety();
         let abi = self.parse_extern_abi()?;
         self.expect_keyword(kw::Fn)?;
-        let cfg = super::ParamCfg {
+        let cfg = ParamCfg {
             is_self_allowed: false,
             allow_c_variadic: true,
             is_name_required: |_| false,
@@ -295,7 +296,7 @@ impl<'a> Parser<'a> {
         })))
     }
 
-    crate fn parse_generic_bounds(&mut self,
+    pub(super) fn parse_generic_bounds(&mut self,
                                   colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
         self.parse_generic_bounds_common(true, colon_span)
     }
@@ -432,13 +433,13 @@ impl<'a> Parser<'a> {
         }
     }
 
-    crate fn check_lifetime(&mut self) -> bool {
+    pub fn check_lifetime(&mut self) -> bool {
         self.expected_tokens.push(TokenType::Lifetime);
         self.token.is_lifetime()
     }
 
     /// Parses a single lifetime `'a` or panics.
-    crate fn expect_lifetime(&mut self) -> Lifetime {
+    pub fn expect_lifetime(&mut self) -> Lifetime {
         if let Some(ident) = self.token.lifetime() {
             let span = self.token.span;
             self.bump();
@@ -447,4 +448,8 @@ impl<'a> Parser<'a> {
             self.span_bug(self.token.span, "not a lifetime")
         }
     }
+
+    pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> P<Ty> {
+        P(Ty { kind, span, id: ast::DUMMY_NODE_ID })
+    }
 }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index fd78a2bd534..4a8b25c6107 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -4,16 +4,13 @@ pub use DelimToken::*;
 pub use LitKind::*;
 pub use TokenKind::*;
 
-use crate::ast::{self};
-use crate::parse::{parse_stream_from_source_str, ParseSess};
-use crate::print::pprust;
+use crate::ast;
 use crate::ptr::P;
 use crate::symbol::kw;
-use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree};
+use crate::tokenstream::TokenTree;
 
 use syntax_pos::symbol::Symbol;
-use syntax_pos::{self, Span, FileName, DUMMY_SP};
-use log::info;
+use syntax_pos::{self, Span, DUMMY_SP};
 
 use std::fmt;
 use std::mem;
@@ -36,7 +33,7 @@ pub enum BinOpToken {
 }
 
 /// A delimiter token.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum DelimToken {
     /// A round parenthesis (i.e., `(` or `)`).
     Paren,
@@ -288,7 +285,7 @@ impl TokenKind {
 }
 
 impl Token {
-    crate fn new(kind: TokenKind, span: Span) -> Self {
+    pub fn new(kind: TokenKind, span: Span) -> Self {
         Token { kind, span }
     }
 
@@ -298,12 +295,12 @@ impl Token {
     }
 
     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
-    crate fn from_ast_ident(ident: ast::Ident) -> Self {
+    pub fn from_ast_ident(ident: ast::Ident) -> Self {
         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
     }
 
     /// Return this token by value and leave a dummy token in its place.
-    crate fn take(&mut self) -> Self {
+    pub fn take(&mut self) -> Self {
         mem::replace(self, Token::dummy())
     }
 
@@ -324,7 +321,7 @@ impl Token {
     }
 
     /// Returns `true` if the token can appear at the start of an expression.
-    crate fn can_begin_expr(&self) -> bool {
+    pub fn can_begin_expr(&self) -> bool {
         match self.kind {
             Ident(name, is_raw)              =>
                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
@@ -356,7 +353,7 @@ impl Token {
     }
 
     /// Returns `true` if the token can appear at the start of a type.
-    crate fn can_begin_type(&self) -> bool {
+    pub fn can_begin_type(&self) -> bool {
         match self.kind {
             Ident(name, is_raw)        =>
                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
@@ -399,7 +396,7 @@ impl Token {
     }
 
     /// Returns `true` if the token is any literal
-    crate fn is_lit(&self) -> bool {
+    pub fn is_lit(&self) -> bool {
         match self.kind {
             Literal(..) => true,
             _           => false,
@@ -415,7 +412,7 @@ impl Token {
 
     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
     /// for example a '-42', or one of the boolean idents).
-    crate fn can_begin_literal_or_bool(&self) -> bool {
+    pub fn can_begin_literal_or_bool(&self) -> bool {
         match self.kind {
             Literal(..) | BinOp(Minus) => true,
             Ident(name, false) if name.is_bool_lit() => true,
@@ -737,131 +734,3 @@ impl fmt::Debug for Nonterminal {
         }
     }
 }
-
-impl Nonterminal {
-    pub fn to_tokenstream(&self, sess: &ParseSess, span: Span) -> TokenStream {
-        // A `Nonterminal` is often a parsed AST item. At this point we now
-        // need to convert the parsed AST to an actual token stream, e.g.
-        // un-parse it basically.
-        //
-        // Unfortunately there's not really a great way to do that in a
-        // guaranteed lossless fashion right now. The fallback here is to just
-        // stringify the AST node and reparse it, but this loses all span
-        // information.
-        //
-        // As a result, some AST nodes are annotated with the token stream they
-        // came from. Here we attempt to extract these lossless token streams
-        // before we fall back to the stringification.
-        let tokens = match *self {
-            Nonterminal::NtItem(ref item) => {
-                prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
-            }
-            Nonterminal::NtTraitItem(ref item) => {
-                prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
-            }
-            Nonterminal::NtImplItem(ref item) => {
-                prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
-            }
-            Nonterminal::NtIdent(ident, is_raw) => {
-                Some(TokenTree::token(Ident(ident.name, is_raw), ident.span).into())
-            }
-            Nonterminal::NtLifetime(ident) => {
-                Some(TokenTree::token(Lifetime(ident.name), ident.span).into())
-            }
-            Nonterminal::NtTT(ref tt) => {
-                Some(tt.clone().into())
-            }
-            _ => None,
-        };
-
-        // FIXME(#43081): Avoid this pretty-print + reparse hack
-        let source = pprust::nonterminal_to_string(self);
-        let filename = FileName::macro_expansion_source_code(&source);
-        let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span));
-
-        // During early phases of the compiler the AST could get modified
-        // directly (e.g., attributes added or removed) and the internal cache
-        // of tokens my not be invalidated or updated. Consequently if the
-        // "lossless" token stream disagrees with our actual stringification
-        // (which has historically been much more battle-tested) then we go
-        // with the lossy stream anyway (losing span information).
-        //
-        // Note that the comparison isn't `==` here to avoid comparing spans,
-        // but it *also* is a "probable" equality which is a pretty weird
-        // definition. We mostly want to catch actual changes to the AST
-        // like a `#[cfg]` being processed or some weird `macro_rules!`
-        // expansion.
-        //
-        // What we *don't* want to catch is the fact that a user-defined
-        // literal like `0xf` is stringified as `15`, causing the cached token
-        // stream to not be literal `==` token-wise (ignoring spans) to the
-        // token stream we got from stringification.
-        //
-        // Instead the "probably equal" check here is "does each token
-        // recursively have the same discriminant?" We basically don't look at
-        // the token values here and assume that such fine grained token stream
-        // modifications, including adding/removing typically non-semantic
-        // tokens such as extra braces and commas, don't happen.
-        if let Some(tokens) = tokens {
-            if tokens.probably_equal_for_proc_macro(&tokens_for_real) {
-                return tokens
-            }
-            info!("cached tokens found, but they're not \"probably equal\", \
-                   going with stringified version");
-        }
-        return tokens_for_real
-    }
-}
-
-fn prepend_attrs(sess: &ParseSess,
-                 attrs: &[ast::Attribute],
-                 tokens: Option<&tokenstream::TokenStream>,
-                 span: syntax_pos::Span)
-    -> Option<tokenstream::TokenStream>
-{
-    let tokens = tokens?;
-    if attrs.len() == 0 {
-        return Some(tokens.clone())
-    }
-    let mut builder = tokenstream::TokenStreamBuilder::new();
-    for attr in attrs {
-        assert_eq!(attr.style, ast::AttrStyle::Outer,
-                   "inner attributes should prevent cached tokens from existing");
-
-        let source = pprust::attribute_to_string(attr);
-        let macro_filename = FileName::macro_expansion_source_code(&source);
-        if attr.is_sugared_doc {
-            let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
-            builder.push(stream);
-            continue
-        }
-
-        // synthesize # [ $path $tokens ] manually here
-        let mut brackets = tokenstream::TokenStreamBuilder::new();
-
-        // For simple paths, push the identifier directly
-        if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() {
-            let ident = attr.path.segments[0].ident;
-            let token = Ident(ident.name, ident.as_str().starts_with("r#"));
-            brackets.push(tokenstream::TokenTree::token(token, ident.span));
-
-        // ... and for more complicated paths, fall back to a reparse hack that
-        // should eventually be removed.
-        } else {
-            let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
-            brackets.push(stream);
-        }
-
-        brackets.push(attr.tokens.clone());
-
-        // The span we list here for `#` and for `[ ... ]` are both wrong in
-        // that it encompasses more than each token, but it hopefully is "good
-        // enough" for now at least.
-        builder.push(tokenstream::TokenTree::token(Pound, attr.span));
-        let delim_span = DelimSpan::from_single(attr.span);
-        builder.push(tokenstream::TokenTree::Delimited(
-            delim_span, DelimToken::Bracket, brackets.build().into()));
-    }
-    builder.push(tokens.clone());
-    Some(builder.build())
-}
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 7d4ffe493d7..136fc355f89 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -6,10 +6,11 @@ use crate::attr;
 use crate::source_map::{self, SourceMap, Spanned};
 use crate::parse::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
 use crate::parse::lexer::comments;
-use crate::parse::{self, ParseSess};
+use crate::parse;
 use crate::print::pp::{self, Breaks};
 use crate::print::pp::Breaks::{Consistent, Inconsistent};
 use crate::ptr::P;
+use crate::sess::ParseSess;
 use crate::symbol::{kw, sym};
 use crate::tokenstream::{self, TokenStream, TokenTree};
 
@@ -2381,7 +2382,8 @@ impl<'a> State<'a> {
                 }
                 self.print_ident(ident);
                 if let Some(ref p) = *sub {
-                    self.s.word("@");
+                    self.s.space();
+                    self.s.word_space("@");
                     self.print_pat(p);
                 }
             }
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index 7300ce24954..d987dc855b6 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -35,7 +35,6 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
 
 use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 /// An owned smart pointer.
-#[derive(Hash, PartialEq, Eq)]
 pub struct P<T: ?Sized> {
     ptr: Box<T>
 }
diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs
new file mode 100644
index 00000000000..e49d3954f8e
--- /dev/null
+++ b/src/libsyntax/sess.rs
@@ -0,0 +1,124 @@
+//! Contains `ParseSess` which holds state living beyond what one `Parser` might.
+//! It also serves as an input to the parser itself.
+
+use crate::ast::{CrateConfig, NodeId};
+use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
+use crate::source_map::{SourceMap, FilePathMapping};
+use crate::feature_gate::UnstableFeatures;
+
+use errors::{Applicability, Handler, ColorConfig, DiagnosticBuilder};
+use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use rustc_data_structures::sync::{Lrc, Lock, Once};
+use syntax_pos::{Symbol, Span, MultiSpan};
+use syntax_pos::edition::Edition;
+use syntax_pos::hygiene::ExpnId;
+
+use std::path::PathBuf;
+use std::str;
+
+/// Collected spans during parsing for places where a certain feature was
+/// used and should be feature gated accordingly in `check_crate`.
+#[derive(Default)]
+crate struct GatedSpans {
+    /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`.
+    crate let_chains: Lock<Vec<Span>>,
+    /// Spans collected for gating `async_closure`, e.g. `async || ..`.
+    crate async_closure: Lock<Vec<Span>>,
+    /// Spans collected for gating `yield e?` expressions (`generators` gate).
+    crate yields: Lock<Vec<Span>>,
+    /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`.
+    crate or_patterns: Lock<Vec<Span>>,
+    /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`.
+    crate const_extern_fn: Lock<Vec<Span>>,
+}
+
+/// Info about a parsing session.
+pub struct ParseSess {
+    pub span_diagnostic: Handler,
+    crate unstable_features: UnstableFeatures,
+    pub config: CrateConfig,
+    pub edition: Edition,
+    pub missing_fragment_specifiers: Lock<FxHashSet<Span>>,
+    /// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
+    pub raw_identifier_spans: Lock<Vec<Span>>,
+    /// Used to determine and report recursive module inclusions.
+    pub(super) included_mod_stack: Lock<Vec<PathBuf>>,
+    source_map: Lrc<SourceMap>,
+    pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
+    /// Contains the spans of block expressions that could have been incomplete based on the
+    /// operation token that followed it, but that the parser cannot identify without further
+    /// analysis.
+    pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>,
+    pub injected_crate_name: Once<Symbol>,
+    crate gated_spans: GatedSpans,
+}
+
+impl ParseSess {
+    pub fn new(file_path_mapping: FilePathMapping) -> Self {
+        let cm = Lrc::new(SourceMap::new(file_path_mapping));
+        let handler = Handler::with_tty_emitter(
+            ColorConfig::Auto,
+            true,
+            None,
+            Some(cm.clone()),
+        );
+        ParseSess::with_span_handler(handler, cm)
+    }
+
+    pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
+        Self {
+            span_diagnostic: handler,
+            unstable_features: UnstableFeatures::from_environment(),
+            config: FxHashSet::default(),
+            edition: ExpnId::root().expn_data().edition,
+            missing_fragment_specifiers: Lock::new(FxHashSet::default()),
+            raw_identifier_spans: Lock::new(Vec::new()),
+            included_mod_stack: Lock::new(vec![]),
+            source_map,
+            buffered_lints: Lock::new(vec![]),
+            ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
+            injected_crate_name: Once::new(),
+            gated_spans: GatedSpans::default(),
+        }
+    }
+
+    #[inline]
+    pub fn source_map(&self) -> &SourceMap {
+        &self.source_map
+    }
+
+    pub fn buffer_lint(
+        &self,
+        lint_id: BufferedEarlyLintId,
+        span: impl Into<MultiSpan>,
+        id: NodeId,
+        msg: &str,
+    ) {
+        self.buffered_lints.with_lock(|buffered_lints| {
+            buffered_lints.push(BufferedEarlyLint{
+                span: span.into(),
+                id,
+                msg: msg.into(),
+                lint_id,
+            });
+        });
+    }
+
+    /// Extend an error with a suggestion to wrap an expression with parentheses to allow the
+    /// parser to continue parsing the following operation as part of the same expression.
+    pub fn expr_parentheses_needed(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        span: Span,
+        alt_snippet: Option<String>,
+    ) {
+        if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) {
+            err.span_suggestion(
+                span,
+                "parentheses are required to parse this as an expression",
+                format!("({})", snippet),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs
index 5e569f9dae3..a1d147637e2 100644
--- a/src/libsyntax/source_map.rs
+++ b/src/libsyntax/source_map.rs
@@ -41,7 +41,7 @@ pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
 pub struct Spanned<T> {
     pub node: T,
     pub span: Span,
@@ -970,6 +970,9 @@ impl SourceMapper for SourceMap {
     fn span_to_string(&self, sp: Span) -> String {
         self.span_to_string(sp)
     }
+    fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
+        self.span_to_snippet(sp)
+    }
     fn span_to_filename(&self, sp: Span) -> FileName {
         self.span_to_filename(sp)
     }
diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs
index f510ac9273d..881bdaa84d0 100644
--- a/src/libsyntax/tests.rs
+++ b/src/libsyntax/tests.rs
@@ -1,7 +1,8 @@
-use crate::{ast, panictry};
-use crate::parse::{ParseSess, PResult, source_file_to_stream};
+use crate::ast;
+use crate::parse::{PResult, source_file_to_stream};
 use crate::parse::new_parser_from_source_str;
 use crate::parse::parser::Parser;
+use crate::sess::ParseSess;
 use crate::source_map::{SourceMap, FilePathMapping};
 use crate::tokenstream::TokenStream;
 use crate::with_default_globals;
@@ -27,7 +28,7 @@ crate fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F)
     F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
 {
     let mut p = string_to_parser(&ps, s);
-    let x = panictry!(f(&mut p));
+    let x = f(&mut p).unwrap();
     p.sess.span_diagnostic.abort_if_errors();
     x
 }
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index bef12ed4fad..ac155556cda 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -14,7 +14,6 @@
 //! ownership of the original.
 
 use crate::parse::token::{self, DelimToken, Token, TokenKind};
-use crate::print::pprust;
 
 use syntax_pos::{BytePos, Span, DUMMY_SP};
 #[cfg(target_arch = "x86_64")]
@@ -23,7 +22,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
 use smallvec::{SmallVec, smallvec};
 
-use std::{fmt, iter, mem};
+use std::{iter, mem};
 
 #[cfg(test)]
 mod tests;
@@ -137,13 +136,8 @@ impl TokenTree {
 /// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
 /// instead of a representation of the abstract syntax tree.
 /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat.
-///
-/// The use of `Option` is an optimization that avoids the need for an
-/// allocation when the stream is empty. However, it is not guaranteed that an
-/// empty stream is represented with `None`; it may be represented as a `Some`
-/// around an empty `Vec`.
-#[derive(Clone, Debug)]
-pub struct TokenStream(pub Option<Lrc<Vec<TreeAndJoint>>>);
+#[derive(Clone, Debug, Default)]
+pub struct TokenStream(pub Lrc<Vec<TreeAndJoint>>);
 
 pub type TreeAndJoint = (TokenTree, IsJoint);
 
@@ -162,38 +156,36 @@ use IsJoint::*;
 impl TokenStream {
     /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream`
     /// separating the two arguments with a comma for diagnostic suggestions.
-    pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> {
+    pub fn add_comma(&self) -> Option<(TokenStream, Span)> {
         // Used to suggest if a user writes `foo!(a b);`
-        if let Some(ref stream) = self.0 {
-            let mut suggestion = None;
-            let mut iter = stream.iter().enumerate().peekable();
-            while let Some((pos, ts)) = iter.next() {
-                if let Some((_, next)) = iter.peek() {
-                    let sp = match (&ts, &next) {
-                        (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue,
-                        ((TokenTree::Token(token_left), NonJoint),
-                         (TokenTree::Token(token_right), _))
-                        if ((token_left.is_ident() && !token_left.is_reserved_ident())
-                            || token_left.is_lit()) &&
-                            ((token_right.is_ident() && !token_right.is_reserved_ident())
-                            || token_right.is_lit()) => token_left.span,
-                        ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
-                        _ => continue,
-                    };
-                    let sp = sp.shrink_to_hi();
-                    let comma = (TokenTree::token(token::Comma, sp), NonJoint);
-                    suggestion = Some((pos, comma, sp));
-                }
-            }
-            if let Some((pos, comma, sp)) = suggestion {
-                let mut new_stream = vec![];
-                let parts = stream.split_at(pos + 1);
-                new_stream.extend_from_slice(parts.0);
-                new_stream.push(comma);
-                new_stream.extend_from_slice(parts.1);
-                return Some((TokenStream::new(new_stream), sp));
+        let mut suggestion = None;
+        let mut iter = self.0.iter().enumerate().peekable();
+        while let Some((pos, ts)) = iter.next() {
+            if let Some((_, next)) = iter.peek() {
+                let sp = match (&ts, &next) {
+                    (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue,
+                    ((TokenTree::Token(token_left), NonJoint),
+                     (TokenTree::Token(token_right), _))
+                    if ((token_left.is_ident() && !token_left.is_reserved_ident())
+                        || token_left.is_lit()) &&
+                        ((token_right.is_ident() && !token_right.is_reserved_ident())
+                        || token_right.is_lit()) => token_left.span,
+                    ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(),
+                    _ => continue,
+                };
+                let sp = sp.shrink_to_hi();
+                let comma = (TokenTree::token(token::Comma, sp), NonJoint);
+                suggestion = Some((pos, comma, sp));
             }
         }
+        if let Some((pos, comma, sp)) = suggestion {
+            let mut new_stream = vec![];
+            let parts = self.0.split_at(pos + 1);
+            new_stream.extend_from_slice(parts.0);
+            new_stream.push(comma);
+            new_stream.extend_from_slice(parts.1);
+            return Some((TokenStream::new(new_stream), sp));
+        }
         None
     }
 }
@@ -210,9 +202,9 @@ impl From<TokenTree> for TreeAndJoint {
     }
 }
 
-impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream {
-    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
-        TokenStream::from_streams(iter.into_iter().map(Into::into).collect::<SmallVec<_>>())
+impl iter::FromIterator<TokenTree> for TokenStream {
+    fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
+        TokenStream::new(iter.into_iter().map(Into::into).collect::<Vec<TreeAndJoint>>())
     }
 }
 
@@ -225,28 +217,21 @@ impl PartialEq<TokenStream> for TokenStream {
 }
 
 impl TokenStream {
-    pub fn len(&self) -> usize {
-        if let Some(ref slice) = self.0 {
-            slice.len()
-        } else {
-            0
-        }
+    pub fn new(streams: Vec<TreeAndJoint>) -> TokenStream {
+        TokenStream(Lrc::new(streams))
     }
 
-    pub fn empty() -> TokenStream {
-        TokenStream(None)
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
     }
 
-    pub fn is_empty(&self) -> bool {
-        match self.0 {
-            None => true,
-            Some(ref stream) => stream.is_empty(),
-        }
+    pub fn len(&self) -> usize {
+        self.0.len()
     }
 
     pub(crate) fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream {
         match streams.len() {
-            0 => TokenStream::empty(),
+            0 => TokenStream::default(),
             1 => streams.pop().unwrap(),
             _ => {
                 // We are going to extend the first stream in `streams` with
@@ -270,43 +255,22 @@ impl TokenStream {
                 // Get the first stream. If it's `None`, create an empty
                 // stream.
                 let mut iter = streams.drain();
-                let mut first_stream_lrc = match iter.next().unwrap().0 {
-                    Some(first_stream_lrc) => first_stream_lrc,
-                    None => Lrc::new(vec![]),
-                };
+                let mut first_stream_lrc = iter.next().unwrap().0;
 
                 // Append the elements to the first stream, after reserving
                 // space for them.
                 let first_vec_mut = Lrc::make_mut(&mut first_stream_lrc);
                 first_vec_mut.reserve(num_appends);
                 for stream in iter {
-                    if let Some(stream) = stream.0 {
-                        first_vec_mut.extend(stream.iter().cloned());
-                    }
+                    first_vec_mut.extend(stream.0.iter().cloned());
                 }
 
                 // Create the final `TokenStream`.
-                match first_vec_mut.len() {
-                    0 => TokenStream(None),
-                    _ => TokenStream(Some(first_stream_lrc)),
-                }
+                TokenStream(first_stream_lrc)
             }
         }
     }
 
-    pub fn new(streams: Vec<TreeAndJoint>) -> TokenStream {
-        match streams.len() {
-            0 => TokenStream(None),
-            _ => TokenStream(Some(Lrc::new(streams))),
-        }
-    }
-
-    pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec<TreeAndJoint>) {
-        if let Some(stream) = self.0 {
-            vec.extend(stream.iter().cloned());
-        }
-    }
-
     pub fn trees(&self) -> Cursor {
         self.clone().into_trees()
     }
@@ -371,24 +335,22 @@ impl TokenStream {
     }
 
     pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
-        TokenStream(self.0.map(|stream| {
-            Lrc::new(
-                stream
-                    .iter()
-                    .enumerate()
-                    .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
-                    .collect())
-        }))
+        TokenStream(Lrc::new(
+            self.0
+                .iter()
+                .enumerate()
+                .map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
+                .collect()
+        ))
     }
 
     pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
-        TokenStream(self.0.map(|stream| {
-            Lrc::new(
-                stream
-                    .iter()
-                    .map(|(tree, is_joint)| (f(tree.clone()), *is_joint))
-                    .collect())
-        }))
+        TokenStream(Lrc::new(
+            self.0
+                .iter()
+                .map(|(tree, is_joint)| (f(tree.clone()), *is_joint))
+                .collect()
+        ))
     }
 }
 
@@ -406,44 +368,43 @@ impl TokenStreamBuilder {
 
         // If `self` is not empty and the last tree within the last stream is a
         // token tree marked with `Joint`...
-        if let Some(TokenStream(Some(ref mut last_stream_lrc))) = self.0.last_mut() {
+        if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() {
             if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() {
 
                 // ...and `stream` is not empty and the first tree within it is
                 // a token tree...
-                if let TokenStream(Some(ref mut stream_lrc)) = stream {
-                    if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() {
-
-                        // ...and the two tokens can be glued together...
-                        if let Some(glued_tok) = last_token.glue(&token) {
-
-                            // ...then do so, by overwriting the last token
-                            // tree in `self` and removing the first token tree
-                            // from `stream`. This requires using `make_mut()`
-                            // on the last stream in `self` and on `stream`,
-                            // and in practice this doesn't cause cloning 99.9%
-                            // of the time.
-
-                            // Overwrite the last token tree with the merged
-                            // token.
-                            let last_vec_mut = Lrc::make_mut(last_stream_lrc);
-                            *last_vec_mut.last_mut().unwrap() =
-                                (TokenTree::Token(glued_tok), *is_joint);
-
-                            // Remove the first token tree from `stream`. (This
-                            // is almost always the only tree in `stream`.)
-                            let stream_vec_mut = Lrc::make_mut(stream_lrc);
-                            stream_vec_mut.remove(0);
-
-                            // Don't push `stream` if it's empty -- that could
-                            // block subsequent token gluing, by getting
-                            // between two token trees that should be glued
-                            // together.
-                            if !stream.is_empty() {
-                                self.0.push(stream);
-                            }
-                            return;
+                let TokenStream(ref mut stream_lrc) = stream;
+                if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() {
+
+                    // ...and the two tokens can be glued together...
+                    if let Some(glued_tok) = last_token.glue(&token) {
+
+                        // ...then do so, by overwriting the last token
+                        // tree in `self` and removing the first token tree
+                        // from `stream`. This requires using `make_mut()`
+                        // on the last stream in `self` and on `stream`,
+                        // and in practice this doesn't cause cloning 99.9%
+                        // of the time.
+
+                        // Overwrite the last token tree with the merged
+                        // token.
+                        let last_vec_mut = Lrc::make_mut(last_stream_lrc);
+                        *last_vec_mut.last_mut().unwrap() =
+                            (TokenTree::Token(glued_tok), *is_joint);
+
+                        // Remove the first token tree from `stream`. (This
+                        // is almost always the only tree in `stream`.)
+                        let stream_vec_mut = Lrc::make_mut(stream_lrc);
+                        stream_vec_mut.remove(0);
+
+                        // Don't push `stream` if it's empty -- that could
+                        // block subsequent token gluing, by getting
+                        // between two token trees that should be glued
+                        // together.
+                        if !stream.is_empty() {
+                            self.0.push(stream);
                         }
+                        return;
                     }
                 }
             }
@@ -476,16 +437,11 @@ impl Cursor {
     }
 
     pub fn next_with_joint(&mut self) -> Option<TreeAndJoint> {
-        match self.stream.0 {
-            None => None,
-            Some(ref stream) => {
-                if self.index < stream.len() {
-                    self.index += 1;
-                    Some(stream[self.index - 1].clone())
-                } else {
-                    None
-                }
-            }
+        if self.index < self.stream.len() {
+            self.index += 1;
+            Some(self.stream.0[self.index - 1].clone())
+        } else {
+            None
         }
     }
 
@@ -494,22 +450,13 @@ impl Cursor {
             return;
         }
         let index = self.index;
-        let stream = mem::replace(&mut self.stream, TokenStream(None));
+        let stream = mem::take(&mut self.stream);
         *self = TokenStream::from_streams(smallvec![stream, new_stream]).into_trees();
         self.index = index;
     }
 
     pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
-        match self.stream.0 {
-            None => None,
-            Some(ref stream) => stream[self.index ..].get(n).map(|(tree, _)| tree.clone()),
-        }
-    }
-}
-
-impl fmt::Display for TokenStream {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(&pprust::tts_to_string(self.clone()))
+        self.stream.0[self.index ..].get(n).map(|(tree, _)| tree.clone())
     }
 }
 
diff --git a/src/libsyntax_expand/Cargo.toml b/src/libsyntax_expand/Cargo.toml
new file mode 100644
index 00000000000..f063753f599
--- /dev/null
+++ b/src/libsyntax_expand/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "syntax_expand"
+version = "0.0.0"
+edition = "2018"
+build = false
+
+[lib]
+name = "syntax_expand"
+path = "lib.rs"
+doctest = false
+
+[dependencies]
+bitflags = "1.0"
+rustc_serialize = { path = "../libserialize", package = "serialize" }
+log = "0.4"
+scoped-tls = "1.0"
+lazy_static = "1.0.0"
+syntax_pos = { path = "../libsyntax_pos" }
+errors = { path = "../librustc_errors", package = "rustc_errors" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_index = { path = "../librustc_index" }
+rustc_lexer = { path = "../librustc_lexer" }
+rustc_target = { path = "../librustc_target" }
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
+syntax = { path = "../libsyntax" }
diff --git a/src/libsyntax/ext/allocator.rs b/src/libsyntax_expand/allocator.rs
index 99aeb5414c5..3526be17721 100644
--- a/src/libsyntax/ext/allocator.rs
+++ b/src/libsyntax_expand/allocator.rs
@@ -1,5 +1,5 @@
-use crate::{ast, attr, visit};
-use crate::symbol::{sym, Symbol};
+use syntax::{ast, attr, visit};
+use syntax::symbol::{sym, Symbol};
 use syntax_pos::Span;
 
 #[derive(Clone, Copy)]
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax_expand/base.rs
index 583fb3f7701..58edf23a5b1 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax_expand/base.rs
@@ -1,17 +1,19 @@
-use crate::ast::{self, NodeId, Attribute, Name, PatKind};
-use crate::attr::{self, HasAttrs, Stability, Deprecation};
-use crate::source_map::SourceMap;
-use crate::edition::Edition;
-use crate::ext::expand::{self, AstFragment, Invocation};
-use crate::ext::hygiene::ExpnId;
-use crate::mut_visit::{self, MutVisitor};
-use crate::parse::{self, parser, ParseSess, DirectoryOwnership};
-use crate::parse::token;
-use crate::ptr::P;
-use crate::symbol::{kw, sym, Ident, Symbol};
-use crate::{ThinVec, MACRO_ARGUMENTS};
-use crate::tokenstream::{self, TokenStream};
-use crate::visit::Visitor;
+use crate::expand::{self, AstFragment, Invocation};
+use crate::hygiene::ExpnId;
+
+use syntax::ast::{self, NodeId, Attribute, Name, PatKind};
+use syntax::attr::{self, HasAttrs, Stability, Deprecation};
+use syntax::source_map::SourceMap;
+use syntax::edition::Edition;
+use syntax::mut_visit::{self, MutVisitor};
+use syntax::parse::{self, parser, DirectoryOwnership};
+use syntax::parse::token;
+use syntax::ptr::P;
+use syntax::sess::ParseSess;
+use syntax::symbol::{kw, sym, Ident, Symbol};
+use syntax::{ThinVec, MACRO_ARGUMENTS};
+use syntax::tokenstream::{self, TokenStream};
+use syntax::visit::Visitor;
 
 use errors::{DiagnosticBuilder, DiagnosticId};
 use smallvec::{smallvec, SmallVec};
@@ -849,8 +851,7 @@ pub trait Resolver {
     fn next_node_id(&mut self) -> NodeId;
 
     fn resolve_dollar_crates(&mut self);
-    fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
-                                            extra_placeholders: &[NodeId]);
+    fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment);
     fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
 
     fn expansion_for_ast_pass(
@@ -892,7 +893,7 @@ pub struct ExpansionData {
 /// when a macro expansion occurs, the resulting nodes have the `backtrace()
 /// -> expn_data` of their expansion context stored into their span.
 pub struct ExtCtxt<'a> {
-    pub parse_sess: &'a parse::ParseSess,
+    pub parse_sess: &'a ParseSess,
     pub ecfg: expand::ExpansionConfig<'a>,
     pub root_path: PathBuf,
     pub resolver: &'a mut dyn Resolver,
@@ -901,7 +902,7 @@ pub struct ExtCtxt<'a> {
 }
 
 impl<'a> ExtCtxt<'a> {
-    pub fn new(parse_sess: &'a parse::ParseSess,
+    pub fn new(parse_sess: &'a ParseSess,
                ecfg: expand::ExpansionConfig<'a>,
                resolver: &'a mut dyn Resolver)
                -> ExtCtxt<'a> {
@@ -935,7 +936,7 @@ impl<'a> ExtCtxt<'a> {
         parse::stream_to_parser(self.parse_sess, stream, MACRO_ARGUMENTS)
     }
     pub fn source_map(&self) -> &'a SourceMap { self.parse_sess.source_map() }
-    pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
+    pub fn parse_sess(&self) -> &'a ParseSess { self.parse_sess }
     pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config }
     pub fn call_site(&self) -> Span {
         self.current_expansion.id.expn_data().call_site
@@ -1071,7 +1072,11 @@ impl<'a> ExtCtxt<'a> {
     /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
     ///
     /// Returns an absolute path to the file that `path` refers to.
-    pub fn resolve_path(&self, path: impl Into<PathBuf>, span: Span) -> PathBuf {
+    pub fn resolve_path(
+        &self,
+        path: impl Into<PathBuf>,
+        span: Span,
+    ) -> Result<PathBuf, DiagnosticBuilder<'a>> {
         let path = path.into();
 
         // Relative paths are resolved relative to the file in which they are found
@@ -1081,13 +1086,16 @@ impl<'a> ExtCtxt<'a> {
             let mut result = match self.source_map().span_to_unmapped_path(callsite) {
                 FileName::Real(path) => path,
                 FileName::DocTest(path, _) => path,
-                other => panic!("cannot resolve relative path in non-file source `{}`", other),
+                other => return Err(self.struct_span_err(
+                    span,
+                    &format!("cannot resolve relative path in non-file source `{}`", other),
+                )),
             };
             result.pop();
             result.push(path);
-            result
+            Ok(result)
         } else {
-            path
+            Ok(path)
         }
     }
 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax_expand/build.rs
index 8c5289671c9..105ffe3ee8a 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax_expand/build.rs
@@ -1,10 +1,11 @@
-use crate::ast::{self, Ident, Expr, BlockCheckMode, UnOp, PatKind};
-use crate::attr;
-use crate::source_map::{respan, Spanned};
-use crate::ext::base::ExtCtxt;
-use crate::ptr::P;
-use crate::symbol::{kw, sym, Symbol};
-use crate::ThinVec;
+use crate::base::ExtCtxt;
+
+use syntax::ast::{self, Ident, Expr, BlockCheckMode, UnOp, PatKind};
+use syntax::attr;
+use syntax::source_map::{respan, Spanned};
+use syntax::ptr::P;
+use syntax::symbol::{kw, sym, Symbol};
+use syntax::ThinVec;
 
 use syntax_pos::{Pos, Span};
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax_expand/expand.rs
index bbd8da2acef..fc521e5edc0 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax_expand/expand.rs
@@ -1,29 +1,31 @@
-use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
-use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
-use crate::attr::{self, HasAttrs};
-use crate::source_map::respan;
-use crate::config::StripUnconfigured;
-use crate::ext::base::*;
-use crate::ext::proc_macro::{collect_derives, MarkAttrs};
-use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind};
-use crate::ext::mbe::macro_rules::annotate_err_with_kind;
-use crate::ext::placeholders::{placeholder, PlaceholderExpander};
-use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
-use crate::mut_visit::*;
-use crate::parse::{DirectoryOwnership, PResult, ParseSess};
-use crate::parse::token;
-use crate::parse::parser::Parser;
-use crate::ptr::P;
-use crate::symbol::{sym, Symbol};
-use crate::tokenstream::{TokenStream, TokenTree};
-use crate::visit::{self, Visitor};
-use crate::util::map_in_place::MapInPlace;
+use crate::base::*;
+use crate::proc_macro::{collect_derives, MarkAttrs};
+use crate::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind};
+use crate::mbe::macro_rules::annotate_err_with_kind;
+use crate::placeholders::{placeholder, PlaceholderExpander};
+
+use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
+use syntax::ast::{MacStmtStyle, StmtKind, ItemKind};
+use syntax::attr::{self, HasAttrs};
+use syntax::source_map::respan;
+use syntax::configure;
+use syntax::config::StripUnconfigured;
+use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
+use syntax::mut_visit::*;
+use syntax::parse::{DirectoryOwnership, PResult};
+use syntax::parse::token;
+use syntax::parse::parser::Parser;
+use syntax::print::pprust;
+use syntax::ptr::P;
+use syntax::symbol::{sym, Symbol};
+use syntax::tokenstream::{TokenStream, TokenTree};
+use syntax::visit::Visitor;
+use syntax::util::map_in_place::MapInPlace;
 
 use errors::{Applicability, FatalError};
 use smallvec::{smallvec, SmallVec};
 use syntax_pos::{Span, DUMMY_SP, FileName};
 
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use std::io::ErrorKind;
 use std::{iter, mem, slice};
@@ -72,6 +74,22 @@ macro_rules! ast_fragments {
         }
 
         impl AstFragment {
+            pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
+                if placeholders.is_empty() {
+                    return;
+                }
+                match self {
+                    $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
+                        // We are repeating through arguments with `many`, to do that we have to
+                        // mention some macro variable from those arguments even if it's not used.
+                        #[cfg_attr(bootstrap, allow(unused_macros))]
+                        macro _repeating($flat_map_ast_elt) {}
+                        placeholder(AstFragmentKind::$Kind, *id).$make_ast()
+                    })),)?)*
+                    _ => panic!("unexpected AST fragment kind")
+                }
+            }
+
             pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
                 match self {
                     AstFragment::OptExpr(expr) => expr,
@@ -115,8 +133,8 @@ macro_rules! ast_fragments {
             }
         }
 
-        impl<'a> MacResult for crate::ext::mbe::macro_rules::ParserAnyMacro<'a> {
-            $(fn $make_ast(self: Box<crate::ext::mbe::macro_rules::ParserAnyMacro<'a>>)
+        impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
+            $(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
                            -> Option<$AstTy> {
                 Some(self.make(AstFragmentKind::$Kind).$make_ast())
             })*
@@ -339,7 +357,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         // Unresolved macros produce dummy outputs as a recovery measure.
         invocations.reverse();
         let mut expanded_fragments = Vec::new();
-        let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
         let mut undetermined_invocations = Vec::new();
         let (mut progress, mut force) = (false, !self.monotonic);
         loop {
@@ -388,7 +405,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             "`derive` may only be applied to structs, enums and unions");
                         if let ast::AttrStyle::Inner = attr.style {
                             let trait_list = derives.iter()
-                                .map(|t| t.to_string()).collect::<Vec<_>>();
+                                .map(|t| pprust::path_to_string(t))
+                                .collect::<Vec<_>>();
                             let suggestion = format!("#[derive({})]", trait_list.join(", "));
                             err.span_suggestion(
                                 span, "try an outer attribute", suggestion,
@@ -416,9 +434,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY);
                     }
 
-                    let derive_placeholders =
-                        all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
-                    derive_placeholders.reserve(derives.len());
+                    let mut derive_placeholders = Vec::with_capacity(derives.len());
                     invocations.reserve(derives.len());
                     for path in derives {
                         let expn_id = ExpnId::fresh(None);
@@ -434,7 +450,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                     let fragment = invoc.fragment_kind
                         .expect_from_annotatables(::std::iter::once(item));
-                    self.collect_invocations(fragment, derive_placeholders)
+                    self.collect_invocations(fragment, &derive_placeholders)
                 }
             };
 
@@ -453,10 +469,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expanded_fragments) = expanded_fragments.pop() {
             for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
-                let derive_placeholders =
-                    all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
                 placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
-                                         expanded_fragment, derive_placeholders);
+                                         expanded_fragment);
             }
         }
         fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
@@ -489,13 +503,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 monotonic: self.monotonic,
             };
             fragment.mut_visit_with(&mut collector);
+            fragment.add_placeholders(extra_placeholders);
             collector.invocations
         };
 
-        // FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
         if self.monotonic {
             self.cx.resolver.visit_ast_fragment_with_placeholders(
-                self.cx.current_expansion.id, &fragment, extra_placeholders);
+                self.cx.current_expansion.id, &fragment
+            );
         }
 
         (fragment, invocations)
@@ -575,10 +590,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 SyntaxExtensionKind::Bang(expander) => {
                     self.gate_proc_macro_expansion_kind(span, fragment_kind);
                     let tok_result = expander.expand(self.cx, span, mac.stream());
-                    let result =
-                        self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span);
-                    self.gate_proc_macro_expansion(span, &result);
-                    result
+                    self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
                 }
                 SyntaxExtensionKind::LegacyBang(expander) => {
                     let prev = self.cx.current_expansion.prior_type_ascription;
@@ -587,8 +599,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     let result = if let Some(result) = fragment_kind.make_from(tok_result) {
                         result
                     } else {
-                        let msg = format!("non-{kind} macro in {kind} position: {path}",
-                                          kind = fragment_kind.name(), path = mac.path);
+                        let msg = format!(
+                            "non-{kind} macro in {kind} position: {path}",
+                            kind = fragment_kind.name(),
+                            path = pprust::path_to_string(&mac.path),
+                        );
                         self.cx.span_err(span, &msg);
                         self.cx.trace_macros_diag();
                         fragment_kind.dummy(span)
@@ -619,10 +634,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     })), DUMMY_SP).into();
                     let input = self.extract_proc_macro_attr_input(attr.item.tokens, span);
                     let tok_result = expander.expand(self.cx, span, input, item_tok);
-                    let res =
-                        self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span);
-                    self.gate_proc_macro_expansion(span, &res);
-                    res
+                    self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span)
                 }
                 SyntaxExtensionKind::LegacyAttr(expander) => {
                     match attr.parse_meta(self.cx.parse_sess) {
@@ -671,12 +683,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
             }
             Some(TokenTree::Token(..)) => {}
-            None => return TokenStream::empty(),
+            None => return TokenStream::default(),
         }
         self.cx.span_err(span, "custom attribute invocations must be \
             of the form `#[foo]` or `#[foo(..)]`, the macro name must only be \
             followed by a delimiter token");
-        TokenStream::empty()
+        TokenStream::default()
     }
 
     fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
@@ -713,41 +725,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         );
     }
 
-    fn gate_proc_macro_expansion(&self, span: Span, fragment: &AstFragment) {
-        if self.cx.ecfg.proc_macro_hygiene() {
-            return
-        }
-
-        fragment.visit_with(&mut DisallowMacros {
-            span,
-            parse_sess: self.cx.parse_sess,
-        });
-
-        struct DisallowMacros<'a> {
-            span: Span,
-            parse_sess: &'a ParseSess,
-        }
-
-        impl<'ast, 'a> Visitor<'ast> for DisallowMacros<'a> {
-            fn visit_item(&mut self, i: &'ast ast::Item) {
-                if let ast::ItemKind::MacroDef(_) = i.kind {
-                    emit_feature_err(
-                        self.parse_sess,
-                        sym::proc_macro_hygiene,
-                        self.span,
-                        GateIssue::Language,
-                        "procedural macros cannot expand to macro definitions",
-                    );
-                }
-                visit::walk_item(self, i);
-            }
-
-            fn visit_mac(&mut self, _mac: &'ast ast::Mac) {
-                // ...
-            }
-        }
-    }
-
     fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) {
         let kind = match kind {
             AstFragmentKind::Expr |
@@ -788,9 +765,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         span: Span,
     ) -> AstFragment {
         let mut parser = self.cx.new_parser_from_tts(toks);
-        match parser.parse_ast_fragment(kind, false) {
+        match parse_ast_fragment(&mut parser, kind, false) {
             Ok(fragment) => {
-                parser.ensure_complete_parse(path, kind.name(), span);
+                ensure_complete_parse(&mut parser, path, kind.name(), span);
                 fragment
             }
             Err(mut err) => {
@@ -804,100 +781,106 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 }
 
-impl<'a> Parser<'a> {
-    pub fn parse_ast_fragment(&mut self, kind: AstFragmentKind, macro_legacy_warnings: bool)
-                              -> PResult<'a, AstFragment> {
-        Ok(match kind {
-            AstFragmentKind::Items => {
-                let mut items = SmallVec::new();
-                while let Some(item) = self.parse_item()? {
-                    items.push(item);
-                }
-                AstFragment::Items(items)
+pub fn parse_ast_fragment<'a>(
+    this: &mut Parser<'a>,
+    kind: AstFragmentKind,
+    macro_legacy_warnings: bool,
+) -> PResult<'a, AstFragment> {
+    Ok(match kind {
+        AstFragmentKind::Items => {
+            let mut items = SmallVec::new();
+            while let Some(item) = this.parse_item()? {
+                items.push(item);
             }
-            AstFragmentKind::TraitItems => {
-                let mut items = SmallVec::new();
-                while self.token != token::Eof {
-                    items.push(self.parse_trait_item(&mut false)?);
-                }
-                AstFragment::TraitItems(items)
+            AstFragment::Items(items)
+        }
+        AstFragmentKind::TraitItems => {
+            let mut items = SmallVec::new();
+            while this.token != token::Eof {
+                items.push(this.parse_trait_item(&mut false)?);
             }
-            AstFragmentKind::ImplItems => {
-                let mut items = SmallVec::new();
-                while self.token != token::Eof {
-                    items.push(self.parse_impl_item(&mut false)?);
-                }
-                AstFragment::ImplItems(items)
+            AstFragment::TraitItems(items)
+        }
+        AstFragmentKind::ImplItems => {
+            let mut items = SmallVec::new();
+            while this.token != token::Eof {
+                items.push(this.parse_impl_item(&mut false)?);
             }
-            AstFragmentKind::ForeignItems => {
-                let mut items = SmallVec::new();
-                while self.token != token::Eof {
-                    items.push(self.parse_foreign_item(DUMMY_SP)?);
-                }
-                AstFragment::ForeignItems(items)
+            AstFragment::ImplItems(items)
+        }
+        AstFragmentKind::ForeignItems => {
+            let mut items = SmallVec::new();
+            while this.token != token::Eof {
+                items.push(this.parse_foreign_item(DUMMY_SP)?);
             }
-            AstFragmentKind::Stmts => {
-                let mut stmts = SmallVec::new();
-                while self.token != token::Eof &&
-                      // won't make progress on a `}`
-                      self.token != token::CloseDelim(token::Brace) {
-                    if let Some(stmt) = self.parse_full_stmt(macro_legacy_warnings)? {
-                        stmts.push(stmt);
-                    }
+            AstFragment::ForeignItems(items)
+        }
+        AstFragmentKind::Stmts => {
+            let mut stmts = SmallVec::new();
+            while this.token != token::Eof &&
+                    // won't make progress on a `}`
+                    this.token != token::CloseDelim(token::Brace) {
+                if let Some(stmt) = this.parse_full_stmt(macro_legacy_warnings)? {
+                    stmts.push(stmt);
                 }
-                AstFragment::Stmts(stmts)
             }
-            AstFragmentKind::Expr => AstFragment::Expr(self.parse_expr()?),
-            AstFragmentKind::OptExpr => {
-                if self.token != token::Eof {
-                    AstFragment::OptExpr(Some(self.parse_expr()?))
-                } else {
-                    AstFragment::OptExpr(None)
-                }
-            },
-            AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
-            AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
-            AstFragmentKind::Arms
-            | AstFragmentKind::Fields
-            | AstFragmentKind::FieldPats
-            | AstFragmentKind::GenericParams
-            | AstFragmentKind::Params
-            | AstFragmentKind::StructFields
-            | AstFragmentKind::Variants
-                => panic!("unexpected AST fragment kind"),
-        })
-    }
-
-    pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) {
-        if self.token != token::Eof {
-            let msg = format!("macro expansion ignores token `{}` and any following",
-                              self.this_token_to_string());
-            // Avoid emitting backtrace info twice.
-            let def_site_span = self.token.span.with_ctxt(SyntaxContext::root());
-            let mut err = self.diagnostic().struct_span_err(def_site_span, &msg);
-            err.span_label(span, "caused by the macro expansion here");
-            let msg = format!(
-                "the usage of `{}!` is likely invalid in {} context",
-                macro_path,
-                kind_name,
-            );
-            err.note(&msg);
-            let semi_span = self.sess.source_map().next_point(span);
+            AstFragment::Stmts(stmts)
+        }
+        AstFragmentKind::Expr => AstFragment::Expr(this.parse_expr()?),
+        AstFragmentKind::OptExpr => {
+            if this.token != token::Eof {
+                AstFragment::OptExpr(Some(this.parse_expr()?))
+            } else {
+                AstFragment::OptExpr(None)
+            }
+        },
+        AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
+        AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat(None)?),
+        AstFragmentKind::Arms
+        | AstFragmentKind::Fields
+        | AstFragmentKind::FieldPats
+        | AstFragmentKind::GenericParams
+        | AstFragmentKind::Params
+        | AstFragmentKind::StructFields
+        | AstFragmentKind::Variants
+            => panic!("unexpected AST fragment kind"),
+    })
+}
 
-            let semi_full_span = semi_span.to(self.sess.source_map().next_point(semi_span));
-            match self.sess.source_map().span_to_snippet(semi_full_span) {
-                Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
-                    err.span_suggestion(
-                        semi_span,
-                        "you might be missing a semicolon here",
-                        ";".to_owned(),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                _ => {}
+pub fn ensure_complete_parse<'a>(
+    this: &mut Parser<'a>,
+    macro_path: &Path,
+    kind_name: &str,
+    span: Span,
+) {
+    if this.token != token::Eof {
+        let msg = format!("macro expansion ignores token `{}` and any following",
+                            this.this_token_to_string());
+        // Avoid emitting backtrace info twice.
+        let def_site_span = this.token.span.with_ctxt(SyntaxContext::root());
+        let mut err = this.struct_span_err(def_site_span, &msg);
+        err.span_label(span, "caused by the macro expansion here");
+        let msg = format!(
+            "the usage of `{}!` is likely invalid in {} context",
+            pprust::path_to_string(macro_path),
+            kind_name,
+        );
+        err.note(&msg);
+        let semi_span = this.sess.source_map().next_point(span);
+
+        let semi_full_span = semi_span.to(this.sess.source_map().next_point(semi_span));
+        match this.sess.source_map().span_to_snippet(semi_full_span) {
+            Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => {
+                err.span_suggestion(
+                    semi_span,
+                    "you might be missing a semicolon here",
+                    ";".to_owned(),
+                    Applicability::MaybeIncorrect,
+                );
             }
-            err.emit();
+            _ => {}
         }
+        err.emit();
     }
 }
 
@@ -1435,7 +1418,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                         return noop_visit_attribute(at, self);
                     }
 
-                    let filename = self.cx.resolve_path(&*file.as_str(), it.span());
+                    let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) {
+                        Ok(filename) => filename,
+                        Err(mut err) => {
+                            err.emit();
+                            continue;
+                        }
+                    };
+
                     match self.cx.source_map().load_file(&filename) {
                         Ok(source_file) => {
                             let src = source_file.src.as_ref()
diff --git a/src/libsyntax_expand/lib.rs b/src/libsyntax_expand/lib.rs
new file mode 100644
index 00000000000..db292b619be
--- /dev/null
+++ b/src/libsyntax_expand/lib.rs
@@ -0,0 +1,39 @@
+#![feature(crate_visibility_modifier)]
+#![feature(decl_macro)]
+#![feature(proc_macro_diagnostic)]
+#![feature(proc_macro_internals)]
+#![feature(proc_macro_span)]
+
+extern crate proc_macro as pm;
+
+// A variant of 'try!' that panics on an Err. This is used as a crutch on the
+// way towards a non-panic!-prone parser. It should be used for fatal parsing
+// errors; eventually we plan to convert all code using panictry to just use
+// normal try.
+#[macro_export]
+macro_rules! panictry {
+    ($e:expr) => ({
+        use std::result::Result::{Ok, Err};
+        use errors::FatalError;
+        match $e {
+            Ok(e) => e,
+            Err(mut e) => {
+                e.emit();
+                FatalError.raise()
+            }
+        }
+    })
+}
+
+mod placeholders;
+mod proc_macro_server;
+
+pub use syntax_pos::hygiene;
+pub use mbe::macro_rules::compile_declarative_macro;
+pub mod allocator;
+pub mod base;
+pub mod build;
+pub mod expand;
+pub mod proc_macro;
+
+crate mod mbe;
diff --git a/src/libsyntax/ext/mbe.rs b/src/libsyntax_expand/mbe.rs
index a87da791c9b..d0f790638ef 100644
--- a/src/libsyntax/ext/mbe.rs
+++ b/src/libsyntax_expand/mbe.rs
@@ -9,9 +9,9 @@ crate mod macro_parser;
 crate mod macro_rules;
 crate mod quoted;
 
-use crate::ast;
-use crate::parse::token::{self, Token, TokenKind};
-use crate::tokenstream::{DelimSpan};
+use syntax::ast;
+use syntax::parse::token::{self, Token, TokenKind};
+use syntax::tokenstream::{DelimSpan};
 
 use syntax_pos::{BytePos, Span};
 
@@ -73,7 +73,7 @@ impl KleeneToken {
 
 /// A Kleene-style [repetition operator](http://en.wikipedia.org/wiki/Kleene_star)
 /// for token sequences.
-#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
 enum KleeneOp {
     /// Kleene star (`*`) for zero or more repetitions
     ZeroOrMore,
diff --git a/src/libsyntax/ext/mbe/macro_check.rs b/src/libsyntax_expand/mbe/macro_check.rs
index 97074f5cbe4..50abda8d45e 100644
--- a/src/libsyntax/ext/mbe/macro_check.rs
+++ b/src/libsyntax_expand/mbe/macro_check.rs
@@ -104,13 +104,13 @@
 //! Kleene operators under which a meta-variable is repeating is the concatenation of the stacks
 //! stored when entering a macro definition starting from the state in which the meta-variable is
 //! bound.
-use crate::ast::NodeId;
-use crate::early_buffered_lints::BufferedEarlyLintId;
-use crate::ext::mbe::{KleeneToken, TokenTree};
-use crate::parse::token::TokenKind;
-use crate::parse::token::{DelimToken, Token};
-use crate::parse::ParseSess;
-use crate::symbol::{kw, sym};
+use crate::mbe::{KleeneToken, TokenTree};
+
+use syntax::ast::NodeId;
+use syntax::early_buffered_lints::BufferedEarlyLintId;
+use syntax::parse::token::{DelimToken, Token, TokenKind};
+use syntax::sess::ParseSess;
+use syntax::symbol::{kw, sym};
 
 use rustc_data_structures::fx::FxHashMap;
 use smallvec::SmallVec;
diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs
index 0cb5eff1ef2..3efe22626a9 100644
--- a/src/libsyntax/ext/mbe/macro_parser.rs
+++ b/src/libsyntax_expand/mbe/macro_parser.rs
@@ -74,14 +74,16 @@ crate use NamedMatch::*;
 crate use ParseResult::*;
 use TokenTreeOrTokenTreeSlice::*;
 
-use crate::ast::{Ident, Name};
-use crate::ext::mbe::{self, TokenTree};
-use crate::parse::{Directory, ParseSess, PResult};
-use crate::parse::parser::{Parser, PathStyle};
-use crate::parse::token::{self, DocComment, Nonterminal, Token};
-use crate::print::pprust;
-use crate::symbol::{kw, sym, Symbol};
-use crate::tokenstream::{DelimSpan, TokenStream};
+use crate::mbe::{self, TokenTree};
+
+use syntax::ast::{Ident, Name};
+use syntax::parse::{Directory, PResult};
+use syntax::parse::parser::{Parser, PathStyle};
+use syntax::parse::token::{self, DocComment, Nonterminal, Token};
+use syntax::print::pprust;
+use syntax::sess::ParseSess;
+use syntax::symbol::{kw, sym, Symbol};
+use syntax::tokenstream::{DelimSpan, TokenStream};
 
 use errors::FatalError;
 use smallvec::{smallvec, SmallVec};
@@ -650,7 +652,7 @@ pub(super) fn parse(
         directory,
         recurse_into_modules,
         true,
-        crate::MACRO_ARGUMENTS,
+        syntax::MACRO_ARGUMENTS,
     );
 
     // A queue of possible matcher positions. We initialize it with the matcher position in which
@@ -888,6 +890,9 @@ fn may_begin_with(token: &Token, name: Name) -> bool {
 ///
 /// The parsed non-terminal.
 fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
+    // FIXME(Centril): Consider moving this to `parser.rs` to make
+    // the visibilities of the methods used below `pub(super)` at most.
+
     if name == sym::tt {
         return token::NtTT(p.parse_token_tree());
     }
diff --git a/src/libsyntax/ext/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index aec4a683141..9a4130b2d8d 100644
--- a/src/libsyntax/ext/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -1,23 +1,25 @@
-use crate::ast;
-use crate::attr::{self, TransparencyError};
-use crate::edition::Edition;
-use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
-use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
-use crate::ext::expand::{AstFragment, AstFragmentKind};
-use crate::ext::mbe;
-use crate::ext::mbe::macro_check;
-use crate::ext::mbe::macro_parser::parse;
-use crate::ext::mbe::macro_parser::{Error, Failure, Success};
-use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
-use crate::ext::mbe::transcribe::transcribe;
-use crate::feature_gate::Features;
-use crate::parse::parser::Parser;
-use crate::parse::token::TokenKind::*;
-use crate::parse::token::{self, NtTT, Token};
-use crate::parse::{Directory, ParseSess};
-use crate::print::pprust;
-use crate::symbol::{kw, sym, Symbol};
-use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
+use crate::base::{SyntaxExtension, SyntaxExtensionKind};
+use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
+use crate::mbe;
+use crate::mbe::macro_check;
+use crate::mbe::macro_parser::parse;
+use crate::mbe::macro_parser::{Error, Failure, Success};
+use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedParseResult};
+use crate::mbe::transcribe::transcribe;
+
+use syntax::ast;
+use syntax::attr::{self, TransparencyError};
+use syntax::edition::Edition;
+use syntax::feature_gate::Features;
+use syntax::parse::parser::Parser;
+use syntax::parse::token::TokenKind::*;
+use syntax::parse::token::{self, NtTT, Token};
+use syntax::parse::Directory;
+use syntax::print::pprust;
+use syntax::sess::ParseSess;
+use syntax::symbol::{kw, sym, Symbol};
+use syntax::tokenstream::{DelimSpan, TokenStream};
 
 use errors::{DiagnosticBuilder, FatalError};
 use log::debug;
@@ -65,7 +67,7 @@ crate fn annotate_err_with_kind(
 impl<'a> ParserAnyMacro<'a> {
     crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
         let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
-        let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
+        let fragment = panictry!(parse_ast_fragment(parser, kind, true).map_err(|mut e| {
             if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
                 if !e.span.is_dummy() {
                     // early end of macro arm (#52866)
@@ -127,7 +129,7 @@ impl<'a> ParserAnyMacro<'a> {
 
         // Make sure we don't have any tokens left to parse so we don't silently drop anything.
         let path = ast::Path::from_ident(macro_ident.with_span_pos(site_span));
-        parser.ensure_complete_parse(&path, kind.name(), site_span);
+        ensure_complete_parse(parser, &path, kind.name(), site_span);
         fragment
     }
 }
@@ -174,7 +176,8 @@ fn generic_extension<'cx>(
     rhses: &[mbe::TokenTree],
 ) -> Box<dyn MacResult + 'cx> {
     if cx.trace_macros() {
-        trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg));
+        let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone()));
+        trace_macros_note(cx, sp, msg);
     }
 
     // Which arm's failure should we report? (the one furthest along)
@@ -187,7 +190,7 @@ fn generic_extension<'cx>(
             _ => cx.span_bug(sp, "malformed macro lhs"),
         };
 
-        match TokenTree::parse(cx, lhs_tt, arg.clone()) {
+        match parse_tt(cx, lhs_tt, arg.clone()) {
             Success(named_matches) => {
                 let rhs = match rhses[i] {
                     // ignore delimiters
@@ -212,7 +215,8 @@ fn generic_extension<'cx>(
                 }
 
                 if cx.trace_macros() {
-                    trace_macros_note(cx, sp, format!("to `{}`", tts));
+                    let msg = format!("to `{}`", pprust::tts_to_string(tts.clone()));
+                    trace_macros_note(cx, sp, msg);
                 }
 
                 let directory = Directory {
@@ -262,7 +266,7 @@ fn generic_extension<'cx>(
                 mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
                 _ => continue,
             };
-            match TokenTree::parse(cx, lhs_tt, arg.clone()) {
+            match parse_tt(cx, lhs_tt, arg.clone()) {
                 Success(_) => {
                     if comma_span.is_dummy() {
                         err.note("you might be missing a comma");
@@ -1155,7 +1159,7 @@ fn is_legal_fragment_specifier(
 
 fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     match *tt {
-        mbe::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
+        mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
         mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
         mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
         _ => panic!(
@@ -1165,17 +1169,14 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
     }
 }
 
-impl TokenTree {
-    /// Use this token tree as a matcher to parse given tts.
-    fn parse(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream)
-             -> NamedParseResult {
-        // `None` is because we're not interpolating
-        let directory = Directory {
-            path: Cow::from(cx.current_expansion.module.directory.as_path()),
-            ownership: cx.current_expansion.directory_ownership,
-        };
-        parse(cx.parse_sess(), tts, mtch, Some(directory), true)
-    }
+/// Use this token tree as a matcher to parse given tts.
+fn parse_tt(cx: &ExtCtxt<'_>, mtch: &[mbe::TokenTree], tts: TokenStream) -> NamedParseResult {
+    // `None` is because we're not interpolating
+    let directory = Directory {
+        path: Cow::from(cx.current_expansion.module.directory.as_path()),
+        ownership: cx.current_expansion.directory_ownership,
+    };
+    parse(cx.parse_sess(), tts, mtch, Some(directory), true)
 }
 
 /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
diff --git a/src/libsyntax/ext/mbe/quoted.rs b/src/libsyntax_expand/mbe/quoted.rs
index 8cb85bdef76..cedd59233ad 100644
--- a/src/libsyntax/ext/mbe/quoted.rs
+++ b/src/libsyntax_expand/mbe/quoted.rs
@@ -1,11 +1,12 @@
-use crate::ast;
-use crate::ext::mbe::macro_parser;
-use crate::ext::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited};
-use crate::parse::token::{self, Token};
-use crate::parse::ParseSess;
-use crate::print::pprust;
-use crate::symbol::kw;
-use crate::tokenstream;
+use crate::mbe::macro_parser;
+use crate::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited};
+
+use syntax::ast;
+use syntax::parse::token::{self, Token};
+use syntax::print::pprust;
+use syntax::sess::ParseSess;
+use syntax::symbol::kw;
+use syntax::tokenstream;
 
 use syntax_pos::Span;
 
diff --git a/src/libsyntax/ext/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs
index ba818ebd35c..94523bbf91b 100644
--- a/src/libsyntax/ext/mbe/transcribe.rs
+++ b/src/libsyntax_expand/mbe/transcribe.rs
@@ -1,10 +1,11 @@
-use crate::ast::{Ident, Mac};
-use crate::ext::base::ExtCtxt;
-use crate::ext::mbe;
-use crate::ext::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
-use crate::mut_visit::{self, MutVisitor};
-use crate::parse::token::{self, NtTT, Token};
-use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
+use crate::base::ExtCtxt;
+use crate::mbe;
+use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
+
+use syntax::ast::{Ident, Mac};
+use syntax::mut_visit::{self, MutVisitor};
+use syntax::parse::token::{self, NtTT, Token};
+use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
 
 use smallvec::{smallvec, SmallVec};
 
@@ -95,7 +96,7 @@ pub(super) fn transcribe(
 ) -> TokenStream {
     // Nothing for us to transcribe...
     if src.is_empty() {
-        return TokenStream::empty();
+        return TokenStream::default();
     }
 
     // We descend into the RHS (`src`), expanding things as we go. This stack contains the things
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index 8eecef1020d..e595888dae7 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -1,11 +1,12 @@
-use crate::ast::{self, NodeId};
-use crate::source_map::{DUMMY_SP, dummy_spanned};
-use crate::ext::base::ExtCtxt;
-use crate::ext::expand::{AstFragment, AstFragmentKind};
-use crate::tokenstream::TokenStream;
-use crate::mut_visit::*;
-use crate::ptr::P;
-use crate::ThinVec;
+use crate::base::ExtCtxt;
+use crate::expand::{AstFragment, AstFragmentKind};
+
+use syntax::ast;
+use syntax::source_map::{DUMMY_SP, dummy_spanned};
+use syntax::tokenstream::TokenStream;
+use syntax::mut_visit::*;
+use syntax::ptr::P;
+use syntax::ThinVec;
 
 use smallvec::{smallvec, SmallVec};
 
@@ -15,7 +16,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
     fn mac_placeholder() -> ast::Mac {
         ast::Mac {
             path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
-            tts: TokenStream::empty().into(),
+            tts: TokenStream::default().into(),
             delim: ast::MacDelimiter::Brace,
             span: DUMMY_SP,
             prior_type_ascription: None,
@@ -32,12 +33,12 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
         attrs: ThinVec::new(),
         kind: ast::ExprKind::Mac(mac_placeholder()),
     });
-    let ty = P(ast::Ty {
+    let ty = || P(ast::Ty {
         id,
         kind: ast::TyKind::Mac(mac_placeholder()),
         span,
     });
-    let pat = P(ast::Pat {
+    let pat = || P(ast::Pat {
         id,
         kind: ast::PatKind::Mac(mac_placeholder()),
         span,
@@ -83,7 +84,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
                 body: expr_placeholder(),
                 guard: None,
                 id,
-                pat,
+                pat: pat(),
                 span,
                 is_placeholder: true,
             }
@@ -105,7 +106,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
                 id,
                 ident,
                 is_shorthand: false,
-                pat,
+                pat: pat(),
                 span,
                 is_placeholder: true,
             }
@@ -124,9 +125,9 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
             ast::Param {
                 attrs: Default::default(),
                 id,
-                pat,
+                pat: pat(),
                 span,
-                ty,
+                ty: ty(),
                 is_placeholder: true,
             }
         ]),
@@ -136,7 +137,7 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
                 id,
                 ident: None,
                 span,
-                ty,
+                ty: ty(),
                 vis,
                 is_placeholder: true,
             }
@@ -170,17 +171,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
         }
     }
 
-    pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
+    pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
         fragment.mut_visit_with(self);
-        if let AstFragment::Items(mut items) = fragment {
-            for placeholder in placeholders {
-                match self.remove(placeholder) {
-                    AstFragment::Items(derived_items) => items.extend(derived_items),
-                    _ => unreachable!(),
-                }
-            }
-            fragment = AstFragment::Items(items);
-        }
         self.expanded_fragments.insert(id, fragment);
     }
 
diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs
index e17bbf79fd5..07b618c99a5 100644
--- a/src/libsyntax/ext/proc_macro.rs
+++ b/src/libsyntax_expand/proc_macro.rs
@@ -1,23 +1,22 @@
-use crate::ast::{self, ItemKind, Attribute, Mac};
-use crate::attr::{mark_used, mark_known};
-use crate::errors::{Applicability, FatalError};
-use crate::ext::base::{self, *};
-use crate::ext::proc_macro_server;
-use crate::parse::{self, token};
-use crate::parse::parser::PathStyle;
-use crate::symbol::sym;
-use crate::tokenstream::{self, TokenStream};
-use crate::visit::Visitor;
+use crate::base::{self, *};
+use crate::proc_macro_server;
+
+use syntax::ast::{self, ItemKind, Attribute, Mac};
+use syntax::attr::{mark_used, mark_known};
+use syntax::errors::{Applicability, FatalError};
+use syntax::parse::{self, token};
+use syntax::symbol::sym;
+use syntax::tokenstream::{self, TokenStream};
+use syntax::visit::Visitor;
 
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::{Span, DUMMY_SP};
 
-const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
-    proc_macro::bridge::server::SameThread;
+const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
 
 pub struct BangProcMacro {
-    pub client: proc_macro::bridge::client::Client<
-        fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
+    pub client: pm::bridge::client::Client<
+        fn(pm::TokenStream) -> pm::TokenStream,
     >,
 }
 
@@ -45,9 +44,7 @@ impl base::ProcMacro for BangProcMacro {
 }
 
 pub struct AttrProcMacro {
-    pub client: proc_macro::bridge::client::Client<
-        fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
-    >,
+    pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>,
 }
 
 impl base::AttrProcMacro for AttrProcMacro {
@@ -75,9 +72,7 @@ impl base::AttrProcMacro for AttrProcMacro {
 }
 
 pub struct ProcMacroDerive {
-    pub client: proc_macro::bridge::client::Client<
-        fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
-    >,
+    pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>,
 }
 
 impl MultiItemModifier for ProcMacroDerive {
@@ -205,8 +200,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
             return false;
         }
 
-        match attr.parse_list(cx.parse_sess,
-                              |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
+        match attr.parse_derive_paths(cx.parse_sess) {
             Ok(traits) => {
                 result.extend(traits);
                 true
diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax_expand/proc_macro_server.rs
index 021ec46d987..4ce99cfe73b 100644
--- a/src/libsyntax/ext/proc_macro_server.rs
+++ b/src/libsyntax_expand/proc_macro_server.rs
@@ -1,16 +1,19 @@
-use crate::ast;
-use crate::ext::base::ExtCtxt;
-use crate::parse::{self, token, ParseSess};
-use crate::parse::lexer::comments;
-use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
+use crate::base::ExtCtxt;
+
+use syntax::ast;
+use syntax::parse::{self, token};
+use syntax::parse::lexer::comments;
+use syntax::print::pprust;
+use syntax::sess::ParseSess;
+use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
 
 use errors::Diagnostic;
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
 use syntax_pos::symbol::{kw, sym, Symbol};
 
-use proc_macro::{Delimiter, Level, LineColumn, Spacing};
-use proc_macro::bridge::{server, TokenTree};
+use pm::{Delimiter, Level, LineColumn, Spacing};
+use pm::bridge::{server, TokenTree};
 use std::{ascii, panic};
 use std::ops::Bound;
 
@@ -49,7 +52,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
 {
     fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
                     -> Self {
-        use crate::parse::token::*;
+        use syntax::parse::token::*;
 
         let joint = is_joint == Joint;
         let Token { kind, span } = match tree {
@@ -174,7 +177,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
             }
 
             Interpolated(nt) => {
-                let stream = nt.to_tokenstream(sess, span);
+                let stream = parse::nt_to_tokenstream(&nt, sess, span);
                 TokenTree::Group(Group {
                     delimiter: Delimiter::None,
                     stream,
@@ -190,7 +193,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
 
 impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
     fn to_internal(self) -> TokenStream {
-        use crate::parse::token::*;
+        use syntax::parse::token::*;
 
         let (ch, joint, span) = match self {
             TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
@@ -332,8 +335,7 @@ impl Ident {
         if !Self::is_valid(&string) {
             panic!("`{:?}` is not a valid identifier", string)
         }
-        // Get rid of gensyms to conservatively check rawness on the string contents only.
-        if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() {
+        if is_raw && !sym.can_be_raw() {
             panic!("`{}` cannot be a raw identifier", string);
         }
         Ident { sym, is_raw, span }
@@ -393,7 +395,7 @@ impl server::Types for Rustc<'_> {
 
 impl server::TokenStream for Rustc<'_> {
     fn new(&mut self) -> Self::TokenStream {
-        TokenStream::empty()
+        TokenStream::default()
     }
     fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
         stream.is_empty()
@@ -407,7 +409,7 @@ impl server::TokenStream for Rustc<'_> {
         )
     }
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
-        stream.to_string()
+        pprust::tts_to_string(stream.clone())
     }
     fn from_token_tree(
         &mut self,
diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml
index 73310df305b..440873f3c2b 100644
--- a/src/libsyntax_ext/Cargo.toml
+++ b/src/libsyntax_ext/Cargo.toml
@@ -17,4 +17,5 @@ rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_target = { path = "../librustc_target" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
 syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
 syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index becbf6d60a0..8c9a34713ea 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use errors::DiagnosticBuilder;
 
 use syntax::ast;
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax::parse::token::{self, Token};
 use syntax::ptr::P;
 use syntax::symbol::{kw, sym, Symbol};
diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs
index cbfe14fa439..f4d1f7fb09c 100644
--- a/src/libsyntax_ext/assert.rs
+++ b/src/libsyntax_ext/assert.rs
@@ -1,7 +1,7 @@
 use errors::{Applicability, DiagnosticBuilder};
 
 use syntax::ast::{self, *};
-use syntax::ext::base::*;
+use syntax_expand::base::*;
 use syntax::parse::token::{self, TokenKind};
 use syntax::parse::parser::Parser;
 use syntax::print::pprust;
diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs
index 3c33baf95a5..9e693f29c5a 100644
--- a/src/libsyntax_ext/cfg.rs
+++ b/src/libsyntax_ext/cfg.rs
@@ -5,7 +5,7 @@
 use errors::DiagnosticBuilder;
 
 use syntax::ast;
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax::attr;
 use syntax::tokenstream::TokenStream;
 use syntax::parse::token;
diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs
index 203c4a83489..2d981526a39 100644
--- a/src/libsyntax_ext/cmdline_attrs.rs
+++ b/src/libsyntax_ext/cmdline_attrs.rs
@@ -2,8 +2,9 @@
 
 use syntax::ast::{self, AttrItem, AttrStyle};
 use syntax::attr::mk_attr;
-use syntax::panictry;
-use syntax::parse::{self, token, ParseSess};
+use syntax::parse::{self, token};
+use syntax::sess::ParseSess;
+use syntax_expand::panictry;
 use syntax_pos::FileName;
 
 pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
diff --git a/src/libsyntax_ext/compile_error.rs b/src/libsyntax_ext/compile_error.rs
index 24f3a66d4ae..cd7f78e9e34 100644
--- a/src/libsyntax_ext/compile_error.rs
+++ b/src/libsyntax_ext/compile_error.rs
@@ -1,6 +1,6 @@
 // The compiler code necessary to support the compile_error! extension.
 
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax_pos::Span;
 use syntax::tokenstream::TokenStream;
 
diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs
index 790fdad5b3f..47bade698a8 100644
--- a/src/libsyntax_ext/concat.rs
+++ b/src/libsyntax_ext/concat.rs
@@ -1,5 +1,5 @@
 use syntax::ast;
-use syntax::ext::base::{self, DummyResult};
+use syntax_expand::base::{self, DummyResult};
 use syntax::symbol::Symbol;
 use syntax::tokenstream::TokenStream;
 
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index f6747658c07..a132a4136ea 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 
 use syntax::ast;
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax::parse::token::{self, Token};
 use syntax::ptr::P;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs
index d5b8a00c75b..6a9b7092024 100644
--- a/src/libsyntax_ext/deriving/bounds.rs
+++ b/src/libsyntax_ext/deriving/bounds.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::MetaItem;
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax_pos::Span;
 
 pub fn expand_deriving_copy(cx: &mut ExtCtxt<'_>,
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
index 9ef2c033b07..67ef69babdc 100644
--- a/src/libsyntax_ext/deriving/clone.rs
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{self, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData};
-use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives};
+use syntax_expand::base::{Annotatable, ExtCtxt, SpecialDerives};
 use syntax::ptr::P;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax_pos::Span;
@@ -174,14 +174,12 @@ fn cs_clone(name: &str,
             all_fields = af;
             vdata = &variant.data;
         }
-        EnumNonMatchingCollapsed(..) => {
-            cx.span_bug(trait_span,
-                        &format!("non-matching enum variants in \
-                                 `derive({})`",
-                                 name))
-        }
+        EnumNonMatchingCollapsed(..) => cx.span_bug(trait_span, &format!(
+            "non-matching enum variants in `derive({})`",
+            name,
+        )),
         StaticEnum(..) | StaticStruct(..) => {
-            cx.span_bug(trait_span, &format!("static method in `derive({})`", name))
+            cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
         }
     }
 
@@ -191,12 +189,10 @@ fn cs_clone(name: &str,
                 .map(|field| {
                     let ident = match field.name {
                         Some(i) => i,
-                        None => {
-                            cx.span_bug(trait_span,
-                                        &format!("unnamed field in normal struct in \
-                                                `derive({})`",
-                                                    name))
-                        }
+                        None => cx.span_bug(trait_span, &format!(
+                            "unnamed field in normal struct in `derive({})`",
+                            name,
+                        )),
                     };
                     let call = subcall(cx, field);
                     cx.field_imm(field.span, ident, call)
diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs
index c92339dd2fb..92721dab878 100644
--- a/src/libsyntax_ext/deriving/cmp/eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/eq.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{self, Ident, Expr, MetaItem, GenericArg};
-use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives};
+use syntax_expand::base::{Annotatable, ExtCtxt, SpecialDerives};
 use syntax::ptr::P;
 use syntax::symbol::{sym, Symbol};
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs
index 1f4f5aa3709..3eeed95aff7 100644
--- a/src/libsyntax_ext/deriving/cmp/ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/ord.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{self, Expr, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::sym;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
index 91e1e80e4fb..1615d991792 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{BinOpKind, Expr, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives};
+use syntax_expand::base::{Annotatable, ExtCtxt, SpecialDerives};
 use syntax::ptr::P;
 use syntax::symbol::sym;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
index 13d63aaf2a8..af8aacc6eb9 100644
--- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs
@@ -5,7 +5,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{self, BinOpKind, Expr, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::{sym, Symbol};
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index 003c2423576..35298211e4d 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 
 use syntax::ast::{self, Ident};
 use syntax::ast::{Expr, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::sym;
 use syntax_pos::{DUMMY_SP, Span};
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index cde72abbdef..3a0379a0eb0 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -6,7 +6,7 @@ use crate::deriving::generic::ty::*;
 
 use syntax::ast;
 use syntax::ast::{Expr, MetaItem, Mutability};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs
index 2fdea10b76f..cfc0f3cd6cb 100644
--- a/src/libsyntax_ext/deriving/default.rs
+++ b/src/libsyntax_ext/deriving/default.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{Expr, MetaItem};
-use syntax::ext::base::{Annotatable, DummyResult, ExtCtxt};
+use syntax_expand::base::{Annotatable, DummyResult, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::{kw, sym};
 use syntax::span_err;
@@ -75,6 +75,6 @@ fn default_substructure(cx: &mut ExtCtxt<'_>,
             // let compilation continue
             DummyResult::raw_expr(trait_span, true)
         }
-        _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`"),
+        _ => cx.span_bug(trait_span, "method in `derive(Default)`"),
     };
 }
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index 655d3bb7c4a..2105946b666 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -90,7 +90,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{Expr, ExprKind, MetaItem, Mutability};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index abdcb6c8e3d..216338c1a88 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -186,12 +186,12 @@ use rustc_target::spec::abi::Abi;
 use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind};
 use syntax::ast::{VariantData, GenericParamKind, GenericArg};
 use syntax::attr;
-use syntax::ext::base::{Annotatable, ExtCtxt, SpecialDerives};
 use syntax::source_map::respan;
 use syntax::util::map_in_place::MapInPlace;
 use syntax::ptr::P;
+use syntax::sess::ParseSess;
 use syntax::symbol::{Symbol, kw, sym};
-use syntax::parse::ParseSess;
+use syntax_expand::base::{Annotatable, ExtCtxt, SpecialDerives};
 use syntax_pos::{Span};
 
 use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
@@ -1055,9 +1055,7 @@ impl<'a> MethodDef<'a> {
                 })
                 .collect()
         } else {
-            cx.span_bug(trait_.span,
-                        "no self arguments to non-static method in generic \
-                         `derive`")
+            cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
         };
 
         // body of the inner most destructuring match
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index 6ae02a5cab1..607746597a5 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -5,7 +5,7 @@ pub use PtrTy::*;
 pub use Ty::*;
 
 use syntax::ast::{self, Expr, GenericParamKind, Generics, Ident, SelfKind, GenericArg};
-use syntax::ext::base::ExtCtxt;
+use syntax_expand::base::ExtCtxt;
 use syntax::source_map::{respan, DUMMY_SP};
 use syntax::ptr::P;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs
index 2fc594abd70..fe9ef78bb1b 100644
--- a/src/libsyntax_ext/deriving/hash.rs
+++ b/src/libsyntax_ext/deriving/hash.rs
@@ -3,7 +3,7 @@ use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
 
 use syntax::ast::{Expr, MetaItem, Mutability};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::sym;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index 60b6eba7a4b..f0471a857dc 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -1,7 +1,7 @@
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
 use syntax::ast::{self, MetaItem};
-use syntax::ext::base::{Annotatable, ExtCtxt, MultiItemModifier};
+use syntax_expand::base::{Annotatable, ExtCtxt, MultiItemModifier};
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
index 02757bf6b16..58fe56bd235 100644
--- a/src/libsyntax_ext/env.rs
+++ b/src/libsyntax_ext/env.rs
@@ -4,7 +4,7 @@
 //
 
 use syntax::ast::{self, Ident, GenericArg};
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax::symbol::{kw, sym, Symbol};
 use syntax_pos::Span;
 use syntax::tokenstream::TokenStream;
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 8fc64021b51..45d9f79c28f 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -8,7 +8,7 @@ use errors::Applicability;
 use errors::pluralise;
 
 use syntax::ast;
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, sym};
diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs
index cd2a9b61a76..75dda9535b3 100644
--- a/src/libsyntax_ext/global_allocator.rs
+++ b/src/libsyntax_ext/global_allocator.rs
@@ -1,8 +1,9 @@
+use crate::util::check_builtin_macro_attribute;
+
 use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety};
 use syntax::ast::{self, Param, Attribute, Expr, FnHeader, Generics, Ident};
-use syntax::attr::check_builtin_macro_attribute;
-use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
-use syntax::ext::base::{Annotatable, ExtCtxt};
+use syntax_expand::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
+use syntax_expand::base::{Annotatable, ExtCtxt};
 use syntax::ptr::P;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs
index 72fb5b47c21..879ae1e4215 100644
--- a/src/libsyntax_ext/global_asm.rs
+++ b/src/libsyntax_ext/global_asm.rs
@@ -12,7 +12,7 @@ use errors::DiagnosticBuilder;
 
 use syntax::ast;
 use syntax::source_map::respan;
-use syntax::ext::base::{self, *};
+use syntax_expand::base::{self, *};
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax_pos::Span;
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 64d46a84cba..5516f276422 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -15,9 +15,9 @@ use crate::deriving::*;
 
 use syntax::ast::Ident;
 use syntax::edition::Edition;
-use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn};
-use syntax::ext::proc_macro::BangProcMacro;
 use syntax::symbol::sym;
+use syntax_expand::base::{Resolver, SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn};
+use syntax_expand::proc_macro::BangProcMacro;
 
 mod error_codes;
 
@@ -37,6 +37,7 @@ mod log_syntax;
 mod source_util;
 mod test;
 mod trace_macros;
+mod util;
 
 pub mod cmdline_attrs;
 pub mod plugin_macro_defs;
@@ -44,7 +45,7 @@ pub mod proc_macro_harness;
 pub mod standard_library_imports;
 pub mod test_harness;
 
-pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) {
+pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) {
     let mut register = |name, kind| resolver.register_builtin_macro(
         Ident::with_dummy_span(name), SyntaxExtension {
             is_builtin: true, ..SyntaxExtension::default(kind, edition)
diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs
index 92130bfaf68..2202375e5e7 100644
--- a/src/libsyntax_ext/log_syntax.rs
+++ b/src/libsyntax_ext/log_syntax.rs
@@ -1,4 +1,4 @@
-use syntax::ext::base;
+use syntax_expand::base;
 use syntax::print;
 use syntax::tokenstream::TokenStream;
 use syntax_pos;
diff --git a/src/libsyntax_ext/plugin_macro_defs.rs b/src/libsyntax_ext/plugin_macro_defs.rs
index 315babceae3..1ca9422eb9d 100644
--- a/src/libsyntax_ext/plugin_macro_defs.rs
+++ b/src/libsyntax_ext/plugin_macro_defs.rs
@@ -4,7 +4,7 @@
 use syntax::ast::*;
 use syntax::attr;
 use syntax::edition::Edition;
-use syntax::ext::base::{Resolver, NamedSyntaxExtension};
+use syntax_expand::base::{Resolver, NamedSyntaxExtension};
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax::source_map::respan;
@@ -20,7 +20,7 @@ fn plugin_macro_def(name: Name, span: Span) -> P<Item> {
         attr::mk_word_item(Ident::new(sym::rustc_builtin_macro, span)));
 
     let parens: TreeAndJoint = TokenTree::Delimited(
-        DelimSpan::from_single(span), token::Paren, TokenStream::empty()
+        DelimSpan::from_single(span), token::Paren, TokenStream::default()
     ).into();
     let trees = vec![parens.clone(), TokenTree::token(token::FatArrow, span).into(), parens];
 
diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs
index 9b53bcb841c..96d0c3fcab1 100644
--- a/src/libsyntax_ext/proc_macro_harness.rs
+++ b/src/libsyntax_ext/proc_macro_harness.rs
@@ -3,13 +3,14 @@ use std::mem;
 use smallvec::smallvec;
 use syntax::ast::{self, Ident};
 use syntax::attr;
-use syntax::ext::base::ExtCtxt;
-use syntax::ext::expand::{AstFragment, ExpansionConfig};
-use syntax::ext::proc_macro::is_proc_macro_attr;
-use syntax::parse::ParseSess;
+use syntax::print::pprust;
 use syntax::ptr::P;
+use syntax::sess::ParseSess;
 use syntax::symbol::{kw, sym};
 use syntax::visit::{self, Visitor};
+use syntax_expand::base::{ExtCtxt, Resolver};
+use syntax_expand::expand::{AstFragment, ExpansionConfig};
+use syntax_expand::proc_macro::is_proc_macro_attr;
 use syntax_pos::{Span, DUMMY_SP};
 use syntax_pos::hygiene::AstPass;
 
@@ -45,7 +46,7 @@ struct CollectProcMacros<'a> {
 }
 
 pub fn inject(sess: &ParseSess,
-              resolver: &mut dyn (::syntax::ext::base::Resolver),
+              resolver: &mut dyn Resolver,
               mut krate: ast::Crate,
               is_proc_macro_crate: bool,
               has_proc_macro_decls: bool,
@@ -248,13 +249,20 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         for attr in &item.attrs {
             if is_proc_macro_attr(&attr) {
                 if let Some(prev_attr) = found_attr {
+                    let path_str = pprust::path_to_string(&attr.path);
                     let msg = if attr.path.segments[0].ident.name ==
                                  prev_attr.path.segments[0].ident.name {
-                        format!("only one `#[{}]` attribute is allowed on any given function",
-                                attr.path)
+                        format!(
+                            "only one `#[{}]` attribute is allowed on any given function",
+                            path_str,
+                        )
                     } else {
-                        format!("`#[{}]` and `#[{}]` attributes cannot both be applied \
-                                to the same function", attr.path, prev_attr.path)
+                        format!(
+                            "`#[{}]` and `#[{}]` attributes cannot both be applied
+                            to the same function",
+                            path_str,
+                            pprust::path_to_string(&prev_attr.path),
+                        )
                     };
 
                     self.handler.struct_span_err(attr.span, &msg)
@@ -280,8 +288,10 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         };
 
         if !is_fn {
-            let msg = format!("the `#[{}]` attribute may only be used on bare functions",
-                              attr.path);
+            let msg = format!(
+                "the `#[{}]` attribute may only be used on bare functions",
+                pprust::path_to_string(&attr.path),
+            );
 
             self.handler.span_err(attr.span, &msg);
             return;
@@ -292,8 +302,10 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         }
 
         if !self.is_proc_macro_crate {
-            let msg = format!("the `#[{}]` attribute is only usable with crates of the \
-                              `proc-macro` crate type", attr.path);
+            let msg = format!(
+                "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type",
+                pprust::path_to_string(&attr.path),
+            );
 
             self.handler.span_err(attr.span, &msg);
             return;
diff --git a/src/libsyntax_ext/source_util.rs b/src/libsyntax_ext/source_util.rs
index f74507dcc21..f6c58fcdfa1 100644
--- a/src/libsyntax_ext/source_util.rs
+++ b/src/libsyntax_ext/source_util.rs
@@ -1,5 +1,6 @@
-use syntax::{ast, panictry};
-use syntax::ext::base::{self, *};
+use syntax_expand::panictry;
+use syntax_expand::base::{self, *};
+use syntax::ast;
 use syntax::parse::{self, token, DirectoryOwnership};
 use syntax::print::pprust;
 use syntax::ptr::P;
@@ -75,7 +76,13 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream)
         None => return DummyResult::any(sp),
     };
     // The file will be added to the code map by the parser
-    let file = cx.resolve_path(file, sp);
+    let file = match cx.resolve_path(file, sp) {
+        Ok(f) => f,
+        Err(mut err) => {
+            err.emit();
+            return DummyResult::any(sp);
+        },
+    };
     let directory_ownership = DirectoryOwnership::Owned { relative: None };
     let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
 
@@ -121,7 +128,13 @@ pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream)
         Some(f) => f,
         None => return DummyResult::any(sp)
     };
-    let file = cx.resolve_path(file, sp);
+    let file = match cx.resolve_path(file, sp) {
+        Ok(f) => f,
+        Err(mut err) => {
+            err.emit();
+            return DummyResult::any(sp);
+        },
+    };
     match cx.source_map().load_binary_file(&file) {
         Ok(bytes) => match std::str::from_utf8(&bytes) {
             Ok(src) => {
@@ -146,7 +159,13 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream)
         Some(f) => f,
         None => return DummyResult::any(sp)
     };
-    let file = cx.resolve_path(file, sp);
+    let file = match cx.resolve_path(file, sp) {
+        Ok(f) => f,
+        Err(mut err) => {
+            err.emit();
+            return DummyResult::any(sp);
+        },
+    };
     match cx.source_map().load_binary_file(&file) {
         Ok(bytes) => {
             base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes))))
diff --git a/src/libsyntax_ext/standard_library_imports.rs b/src/libsyntax_ext/standard_library_imports.rs
index c577b1e33cf..fd27a218906 100644
--- a/src/libsyntax_ext/standard_library_imports.rs
+++ b/src/libsyntax_ext/standard_library_imports.rs
@@ -1,11 +1,11 @@
 use syntax::{ast, attr};
 use syntax::edition::Edition;
-use syntax::ext::expand::ExpansionConfig;
-use syntax::ext::hygiene::AstPass;
-use syntax::ext::base::{ExtCtxt, Resolver};
-use syntax::parse::ParseSess;
 use syntax::ptr::P;
+use syntax::sess::ParseSess;
 use syntax::symbol::{Ident, Symbol, kw, sym};
+use syntax_expand::expand::ExpansionConfig;
+use syntax_expand::hygiene::AstPass;
+use syntax_expand::base::{ExtCtxt, Resolver};
 use syntax_pos::DUMMY_SP;
 
 pub fn inject(
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index d4638c45473..b0da413d63a 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -1,9 +1,11 @@
 /// The expansion from a test function to the appropriate test struct for libtest
 /// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
 
+use crate::util::check_builtin_macro_attribute;
+
 use syntax::ast;
-use syntax::attr::{self, check_builtin_macro_attribute};
-use syntax::ext::base::*;
+use syntax::attr;
+use syntax_expand::base::*;
 use syntax::print::pprust;
 use syntax::source_map::respan;
 use syntax::symbol::{Symbol, sym};
diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs
index f79ad1419e0..33d41a7f53e 100644
--- a/src/libsyntax_ext/test_harness.rs
+++ b/src/libsyntax_ext/test_harness.rs
@@ -6,12 +6,12 @@ use rustc_target::spec::PanicStrategy;
 use syntax::ast::{self, Ident};
 use syntax::attr;
 use syntax::entry::{self, EntryPointType};
-use syntax::ext::base::{ExtCtxt, Resolver};
-use syntax::ext::expand::{AstFragment, ExpansionConfig};
+use syntax_expand::base::{ExtCtxt, Resolver};
+use syntax_expand::expand::{AstFragment, ExpansionConfig};
 use syntax::feature_gate::Features;
 use syntax::mut_visit::{*, ExpectOne};
-use syntax::parse::ParseSess;
 use syntax::ptr::P;
+use syntax::sess::ParseSess;
 use syntax::source_map::respan;
 use syntax::symbol::{sym, Symbol};
 use syntax_pos::{Span, DUMMY_SP};
diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs
index d83c24046d9..dbf96d3b561 100644
--- a/src/libsyntax_ext/trace_macros.rs
+++ b/src/libsyntax_ext/trace_macros.rs
@@ -1,4 +1,4 @@
-use syntax::ext::base::{self, ExtCtxt};
+use syntax_expand::base::{self, ExtCtxt};
 use syntax::symbol::kw;
 use syntax_pos::Span;
 use syntax::tokenstream::{TokenTree, TokenStream};
diff --git a/src/libsyntax_ext/util.rs b/src/libsyntax_ext/util.rs
new file mode 100644
index 00000000000..d84fe19b3ea
--- /dev/null
+++ b/src/libsyntax_ext/util.rs
@@ -0,0 +1,11 @@
+use syntax_pos::Symbol;
+use syntax::ast::MetaItem;
+use syntax::attr::{check_builtin_attribute, AttributeTemplate};
+use syntax_expand::base::ExtCtxt;
+
+pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
+    // All the built-in macro attributes are "words" at the moment.
+    let template = AttributeTemplate::only_word();
+    let attr = ecx.attribute(meta_item.clone());
+    check_builtin_attribute(ecx.parse_sess, &attr, name, template);
+}
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 30ee9b90515..7e42b931961 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -12,7 +12,7 @@
 #![feature(non_exhaustive)]
 #![feature(optin_builtin_traits)]
 #![feature(rustc_attrs)]
-#![feature(proc_macro_hygiene)]
+#![cfg_attr(bootstrap, feature(proc_macro_hygiene))]
 #![feature(specialization)]
 #![feature(step_trait)]
 
@@ -1311,7 +1311,7 @@ pub struct BytePos(pub u32);
 /// A character offset. Because of multibyte UTF-8 characters, a byte offset
 /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
 /// values to `CharPos` values as necessary.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct CharPos(pub usize);
 
 // FIXME: lots of boilerplate in these impls, but so far my attempts to fix
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index b80c5f83830..634f58c5285 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -809,25 +809,13 @@ impl Ident {
         Ident::new(self.name, self.span.modern_and_legacy())
     }
 
-    /// Transforms an underscore identifier into one with the same name, but
-    /// gensymed. Leaves non-underscore identifiers unchanged.
-    pub fn gensym_if_underscore(self) -> Ident {
-        if self.name == kw::Underscore {
-            let name = with_interner(|interner| interner.gensymed(self.name));
-            Ident::new(name, self.span)
-        } else {
-            self
-        }
-    }
-
     /// Convert the name to a `LocalInternedString`. This is a slowish
     /// operation because it requires locking the symbol interner.
     pub fn as_str(self) -> LocalInternedString {
         self.name.as_str()
     }
 
-    /// Convert the name to an `InternedString`. This is a slowish operation
-    /// because it requires locking the symbol interner.
+    /// Convert the name to an `InternedString`.
     pub fn as_interned_str(self) -> InternedString {
         self.name.as_interned_str()
     }
@@ -882,26 +870,9 @@ impl UseSpecializedDecodable for Ident {
     }
 }
 
-/// A symbol is an interned or gensymed string. A gensym is a symbol that is
-/// never equal to any other symbol.
+/// An interned string.
 ///
-/// Conceptually, a gensym can be thought of as a normal symbol with an
-/// invisible unique suffix. Gensyms are useful when creating new identifiers
-/// that must not match any existing identifiers, e.g. during macro expansion
-/// and syntax desugaring. Because gensyms should always be identifiers, all
-/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
-/// future the gensym-ness may be moved from `Symbol` to hygiene data.)
-///
-/// Examples:
-/// ```
-/// assert_eq!(Ident::from_str("_"), Ident::from_str("_"))
-/// assert_ne!(Ident::from_str("_").gensym_if_underscore(), Ident::from_str("_"))
-/// assert_ne!(
-///     Ident::from_str("_").gensym_if_underscore(),
-///     Ident::from_str("_").gensym_if_underscore(),
-/// )
-/// ```
-/// Internally, a symbol is implemented as an index, and all operations
+/// Internally, a `Symbol` is implemented as an index, and all operations
 /// (including hashing, equality, and ordering) operate on that index. The use
 /// of `rustc_index::newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
 /// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes.
@@ -952,12 +923,9 @@ impl Symbol {
         })
     }
 
-    /// Convert to an `InternedString`. This is a slowish operation because it
-    /// requires locking the symbol interner.
+    /// Convert to an `InternedString`.
     pub fn as_interned_str(self) -> InternedString {
-        with_interner(|interner| InternedString {
-            symbol: interner.interned(self)
-        })
+        InternedString { symbol: self }
     }
 
     pub fn as_u32(self) -> u32 {
@@ -967,24 +935,19 @@ impl Symbol {
 
 impl fmt::Debug for Symbol {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let is_gensymed = with_interner(|interner| interner.is_gensymed(*self));
-        if is_gensymed {
-            write!(f, "{}({:?})", self, self.0)
-        } else {
-            write!(f, "{}", self)
-        }
+        self.with(|str| fmt::Debug::fmt(&str, f))
     }
 }
 
 impl fmt::Display for Symbol {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&self.as_str(), f)
+        self.with(|str| fmt::Display::fmt(&str, f))
     }
 }
 
 impl Encodable for Symbol {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(&self.as_str())
+        self.with(|string| s.emit_str(string))
     }
 }
 
@@ -995,15 +958,11 @@ impl Decodable for Symbol {
 }
 
 // The `&'static str`s in this type actually point into the arena.
-//
-// Note that normal symbols are indexed upward from 0, and gensyms are indexed
-// downward from SymbolIndex::MAX_AS_U32.
 #[derive(Default)]
 pub struct Interner {
     arena: DroplessArena,
     names: FxHashMap<&'static str, Symbol>,
     strings: Vec<&'static str>,
-    gensyms: Vec<Symbol>,
 }
 
 impl Interner {
@@ -1036,34 +995,10 @@ impl Interner {
         self.names.insert(string, name);
         name
     }
-
-    fn interned(&self, symbol: Symbol) -> Symbol {
-        if (symbol.0.as_usize()) < self.strings.len() {
-            symbol
-        } else {
-            self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]
-        }
-    }
-
-    fn gensymed(&mut self, symbol: Symbol) -> Symbol {
-        self.gensyms.push(symbol);
-        Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
-    }
-
-    fn is_gensymed(&mut self, symbol: Symbol) -> bool {
-        symbol.0.as_usize() >= self.strings.len()
-    }
-
     // Get the symbol as a string. `Symbol::as_str()` should be used in
     // preference to this function.
     pub fn get(&self, symbol: Symbol) -> &str {
-        match self.strings.get(symbol.0.as_usize()) {
-            Some(string) => string,
-            None => {
-                let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize];
-                self.strings[symbol.0.as_usize()]
-            }
-        }
+        self.strings[symbol.0.as_usize()]
     }
 }
 
@@ -1172,8 +1107,8 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
 }
 
 /// An alternative to `Symbol` and `InternedString`, useful when the chars
-/// within the symbol need to be accessed. It is best used for temporary
-/// values.
+/// within the symbol need to be accessed. It deliberately has limited
+/// functionality and should only be used for temporary values.
 ///
 /// Because the interner outlives any thread which uses this type, we can
 /// safely treat `string` which points to interner data, as an immortal string,
@@ -1182,7 +1117,7 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
 // FIXME: ensure that the interner outlives any thread which uses
 // `LocalInternedString`, by creating a new thread right after constructing the
 // interner.
-#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
+#[derive(Eq, PartialOrd, Ord)]
 pub struct LocalInternedString {
     string: &'static str,
 }
@@ -1203,30 +1138,6 @@ impl<T: std::ops::Deref<Target = str>> std::cmp::PartialEq<T> for LocalInternedS
     }
 }
 
-impl std::cmp::PartialEq<LocalInternedString> for str {
-    fn eq(&self, other: &LocalInternedString) -> bool {
-        self == other.string
-    }
-}
-
-impl<'a> std::cmp::PartialEq<LocalInternedString> for &'a str {
-    fn eq(&self, other: &LocalInternedString) -> bool {
-        *self == other.string
-    }
-}
-
-impl std::cmp::PartialEq<LocalInternedString> for String {
-    fn eq(&self, other: &LocalInternedString) -> bool {
-        self == other.string
-    }
-}
-
-impl<'a> std::cmp::PartialEq<LocalInternedString> for &'a String {
-    fn eq(&self, other: &LocalInternedString) -> bool {
-        *self == other.string
-    }
-}
-
 impl !Send for LocalInternedString {}
 impl !Sync for LocalInternedString {}
 
@@ -1248,19 +1159,12 @@ impl fmt::Display for LocalInternedString {
     }
 }
 
-/// An alternative to `Symbol` that is focused on string contents. It has two
-/// main differences to `Symbol`.
+/// An alternative to `Symbol` that is focused on string contents.
 ///
-/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
+/// Its implementations of `Hash`, `PartialOrd` and `Ord` work with the
 /// string chars rather than the symbol integer. This is useful when hash
 /// stability is required across compile sessions, or a guaranteed sort
 /// ordering is required.
-///
-/// Second, gensym-ness is irrelevant. E.g.:
-/// ```
-/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
-/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
-/// ```
 #[derive(Clone, Copy, PartialEq, Eq)]
 pub struct InternedString {
     symbol: Symbol,
diff --git a/src/libsyntax_pos/symbol/tests.rs b/src/libsyntax_pos/symbol/tests.rs
index 1b91c9bb845..f74b9a0cd1d 100644
--- a/src/libsyntax_pos/symbol/tests.rs
+++ b/src/libsyntax_pos/symbol/tests.rs
@@ -14,13 +14,6 @@ fn interner_tests() {
     assert_eq!(i.intern("cat"), Symbol::new(1));
     // dog is still at zero
     assert_eq!(i.intern("dog"), Symbol::new(0));
-    let z = i.intern("zebra");
-    assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32));
-    // gensym of same string gets new number:
-    assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
-    // gensym of *existing* string gets new number:
-    let d = i.intern("dog");
-    assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
 }
 
 #[test]
diff --git a/src/libtest/bench.rs b/src/libtest/bench.rs
new file mode 100644
index 00000000000..c142c5213d2
--- /dev/null
+++ b/src/libtest/bench.rs
@@ -0,0 +1,258 @@
+//! Benchmarking module.
+pub use std::hint::black_box;
+
+use super::{
+    event::CompletedTest,
+    helpers::sink::Sink,
+    options::BenchMode,
+    types::TestDesc,
+    test_result::TestResult,
+    Sender,
+};
+
+use crate::stats;
+use std::time::{Duration, Instant};
+use std::cmp;
+use std::io;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+use std::sync::{Arc, Mutex};
+
+/// Manager of the benchmarking runs.
+///
+/// This is fed into functions marked with `#[bench]` to allow for
+/// set-up & tear-down before running a piece of code repeatedly via a
+/// call to `iter`.
+#[derive(Clone)]
+pub struct Bencher {
+    mode: BenchMode,
+    summary: Option<stats::Summary>,
+    pub bytes: u64,
+}
+
+impl Bencher {
+    /// Callback for benchmark functions to run in their body.
+    pub fn iter<T, F>(&mut self, mut inner: F)
+    where
+        F: FnMut() -> T,
+    {
+        if self.mode == BenchMode::Single {
+            ns_iter_inner(&mut inner, 1);
+            return;
+        }
+
+        self.summary = Some(iter(&mut inner));
+    }
+
+    pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary>
+    where
+        F: FnMut(&mut Bencher),
+    {
+        f(self);
+        return self.summary;
+    }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct BenchSamples {
+    pub ns_iter_summ: stats::Summary,
+    pub mb_s: usize,
+}
+
+pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
+    use std::fmt::Write;
+    let mut output = String::new();
+
+    let median = bs.ns_iter_summ.median as usize;
+    let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+
+    output
+        .write_fmt(format_args!(
+            "{:>11} ns/iter (+/- {})",
+            fmt_thousands_sep(median, ','),
+            fmt_thousands_sep(deviation, ',')
+        ))
+        .unwrap();
+    if bs.mb_s != 0 {
+        output
+            .write_fmt(format_args!(" = {} MB/s", bs.mb_s))
+            .unwrap();
+    }
+    output
+}
+
+// Format a number with thousands separators
+fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
+    use std::fmt::Write;
+    let mut output = String::new();
+    let mut trailing = false;
+    for &pow in &[9, 6, 3, 0] {
+        let base = 10_usize.pow(pow);
+        if pow == 0 || trailing || n / base != 0 {
+            if !trailing {
+                output.write_fmt(format_args!("{}", n / base)).unwrap();
+            } else {
+                output.write_fmt(format_args!("{:03}", n / base)).unwrap();
+            }
+            if pow != 0 {
+                output.push(sep);
+            }
+            trailing = true;
+        }
+        n %= base;
+    }
+
+    output
+}
+
+fn ns_from_dur(dur: Duration) -> u64 {
+    dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64)
+}
+
+fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
+where
+    F: FnMut() -> T,
+{
+    let start = Instant::now();
+    for _ in 0..k {
+        black_box(inner());
+    }
+    return ns_from_dur(start.elapsed());
+}
+
+pub fn iter<T, F>(inner: &mut F) -> stats::Summary
+where
+    F: FnMut() -> T,
+{
+    // Initial bench run to get ballpark figure.
+    let ns_single = ns_iter_inner(inner, 1);
+
+    // Try to estimate iter count for 1ms falling back to 1m
+    // iterations if first run took < 1ns.
+    let ns_target_total = 1_000_000; // 1ms
+    let mut n = ns_target_total / cmp::max(1, ns_single);
+
+    // if the first run took more than 1ms we don't want to just
+    // be left doing 0 iterations on every loop. The unfortunate
+    // side effect of not being able to do as many runs is
+    // automatically handled by the statistical analysis below
+    // (i.e., larger error bars).
+    n = cmp::max(1, n);
+
+    let mut total_run = Duration::new(0, 0);
+    let samples: &mut [f64] = &mut [0.0_f64; 50];
+    loop {
+        let loop_start = Instant::now();
+
+        for p in &mut *samples {
+            *p = ns_iter_inner(inner, n) as f64 / n as f64;
+        }
+
+        stats::winsorize(samples, 5.0);
+        let summ = stats::Summary::new(samples);
+
+        for p in &mut *samples {
+            let ns = ns_iter_inner(inner, 5 * n);
+            *p = ns as f64 / (5 * n) as f64;
+        }
+
+        stats::winsorize(samples, 5.0);
+        let summ5 = stats::Summary::new(samples);
+
+        let loop_run = loop_start.elapsed();
+
+        // If we've run for 100ms and seem to have converged to a
+        // stable median.
+        if loop_run > Duration::from_millis(100)
+            && summ.median_abs_dev_pct < 1.0
+            && summ.median - summ5.median < summ5.median_abs_dev
+        {
+            return summ5;
+        }
+
+        total_run = total_run + loop_run;
+        // Longest we ever run for is 3s.
+        if total_run > Duration::from_secs(3) {
+            return summ5;
+        }
+
+        // If we overflow here just return the results so far. We check a
+        // multiplier of 10 because we're about to multiply by 2 and the
+        // next iteration of the loop will also multiply by 5 (to calculate
+        // the summ5 result)
+        n = match n.checked_mul(10) {
+            Some(_) => n * 2,
+            None => {
+                return summ5;
+            }
+        };
+    }
+}
+
+pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<CompletedTest>, nocapture: bool, f: F)
+where
+    F: FnMut(&mut Bencher),
+{
+    let mut bs = Bencher {
+        mode: BenchMode::Auto,
+        summary: None,
+        bytes: 0,
+    };
+
+    let data = Arc::new(Mutex::new(Vec::new()));
+    let oldio = if !nocapture {
+        Some((
+            io::set_print(Some(Sink::new_boxed(&data))),
+            io::set_panic(Some(Sink::new_boxed(&data))),
+        ))
+    } else {
+        None
+    };
+
+    let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
+
+    if let Some((printio, panicio)) = oldio {
+        io::set_print(printio);
+        io::set_panic(panicio);
+    }
+
+    let test_result = match result {
+        //bs.bench(f) {
+        Ok(Some(ns_iter_summ)) => {
+            let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
+            let mb_s = bs.bytes * 1000 / ns_iter;
+
+            let bs = BenchSamples {
+                ns_iter_summ,
+                mb_s: mb_s as usize,
+            };
+            TestResult::TrBench(bs)
+        }
+        Ok(None) => {
+            // iter not called, so no data.
+            // FIXME: error in this case?
+            let samples: &mut [f64] = &mut [0.0_f64; 1];
+            let bs = BenchSamples {
+                ns_iter_summ: stats::Summary::new(samples),
+                mb_s: 0,
+            };
+            TestResult::TrBench(bs)
+        }
+        Err(_) => TestResult::TrFailed,
+    };
+
+    let stdout = data.lock().unwrap().to_vec();
+    let message = CompletedTest::new(desc, test_result, None, stdout);
+    monitor_ch.send(message).unwrap();
+}
+
+pub fn run_once<F>(f: F)
+where
+    F: FnMut(&mut Bencher),
+{
+    let mut bs = Bencher {
+        mode: BenchMode::Single,
+        summary: None,
+        bytes: 0,
+    };
+    bs.bench(f);
+}
diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs
new file mode 100644
index 00000000000..f95d5aad18a
--- /dev/null
+++ b/src/libtest/cli.rs
@@ -0,0 +1,444 @@
+//! Module converting command-line arguments into test configuration.
+
+use std::env;
+use std::path::PathBuf;
+use getopts;
+
+use super::options::{RunIgnored, ColorConfig, OutputFormat, Options};
+use super::time::TestTimeOptions;
+use super::helpers::isatty;
+
+#[derive(Debug)]
+pub struct TestOpts {
+    pub list: bool,
+    pub filter: Option<String>,
+    pub filter_exact: bool,
+    pub exclude_should_panic: bool,
+    pub run_ignored: RunIgnored,
+    pub run_tests: bool,
+    pub bench_benchmarks: bool,
+    pub logfile: Option<PathBuf>,
+    pub nocapture: bool,
+    pub color: ColorConfig,
+    pub format: OutputFormat,
+    pub test_threads: Option<usize>,
+    pub skip: Vec<String>,
+    pub time_options: Option<TestTimeOptions>,
+    pub options: Options,
+}
+
+impl TestOpts {
+    pub fn use_color(&self) -> bool {
+        match self.color {
+            ColorConfig::AutoColor => !self.nocapture && isatty::stdout_isatty(),
+            ColorConfig::AlwaysColor => true,
+            ColorConfig::NeverColor => false,
+        }
+    }
+}
+
+/// Result of parsing the options.
+pub type OptRes = Result<TestOpts, String>;
+/// Result of parsing the option part.
+type OptPartRes<T> = Result<T, String>;
+
+fn optgroups() -> getopts::Options {
+    let mut opts = getopts::Options::new();
+    opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
+        .optflag("", "ignored", "Run only ignored tests")
+        .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
+        .optflag("", "test", "Run tests and not benchmarks")
+        .optflag("", "bench", "Run benchmarks instead of tests")
+        .optflag("", "list", "List all tests and benchmarks")
+        .optflag("h", "help", "Display this message (longer with --help)")
+        .optopt(
+            "",
+            "logfile",
+            "Write logs to the specified file instead \
+             of stdout",
+            "PATH",
+        )
+        .optflag(
+            "",
+            "nocapture",
+            "don't capture stdout/stderr of each \
+             task, allow printing directly",
+        )
+        .optopt(
+            "",
+            "test-threads",
+            "Number of threads used for running tests \
+             in parallel",
+            "n_threads",
+        )
+        .optmulti(
+            "",
+            "skip",
+            "Skip tests whose names contain FILTER (this flag can \
+             be used multiple times)",
+            "FILTER",
+        )
+        .optflag(
+            "q",
+            "quiet",
+            "Display one character per test instead of one line. \
+             Alias to --format=terse",
+        )
+        .optflag(
+            "",
+            "exact",
+            "Exactly match filters rather than by substring",
+        )
+        .optopt(
+            "",
+            "color",
+            "Configure coloring of output:
+            auto   = colorize if stdout is a tty and tests are run on serially (default);
+            always = always colorize output;
+            never  = never colorize output;",
+            "auto|always|never",
+        )
+        .optopt(
+            "",
+            "format",
+            "Configure formatting of output:
+            pretty = Print verbose output;
+            terse  = Display one character per test;
+            json   = Output a json document",
+            "pretty|terse|json",
+        )
+        .optflag(
+            "",
+            "show-output",
+            "Show captured stdout of successful tests"
+        )
+        .optopt(
+            "Z",
+            "",
+            "Enable nightly-only flags:
+            unstable-options = Allow use of experimental features",
+            "unstable-options",
+        )
+        .optflagopt(
+            "",
+            "report-time",
+            "Show execution time of each test. Awailable values:
+            plain   = do not colorize the execution time (default);
+            colored = colorize output according to the `color` parameter value;
+
+            Threshold values for colorized output can be configured via
+            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
+            `RUST_TEST_TIME_DOCTEST` environment variables.
+
+            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
+
+            Not available for --format=terse",
+            "plain|colored"
+        )
+        .optflag(
+            "",
+            "ensure-time",
+            "Treat excess of the test execution time limit as error.
+
+            Threshold values for this option can be configured via
+            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
+            `RUST_TEST_TIME_DOCTEST` environment variables.
+
+            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
+
+            `CRITICAL_TIME` here means the limit that should not be exceeded by test.
+            "
+        );
+    return opts;
+}
+
+fn usage(binary: &str, options: &getopts::Options) {
+    let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
+    println!(
+        r#"{usage}
+
+The FILTER string is tested against the name of all tests, and only those
+tests whose names contain the filter are run.
+
+By default, all tests are run in parallel. This can be altered with the
+--test-threads flag or the RUST_TEST_THREADS environment variable when running
+tests (set it to 1).
+
+All tests have their standard output and standard error captured by default.
+This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
+environment variable to a value other than "0". Logging is not captured by default.
+
+Test Attributes:
+
+    `#[test]`        - Indicates a function is a test to be run. This function
+                       takes no arguments.
+    `#[bench]`       - Indicates a function is a benchmark to be run. This
+                       function takes one argument (test::Bencher).
+    `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if
+                        the code causes a panic (an assertion failure or panic!)
+                        A message may be provided, which the failure string must
+                        contain: #[should_panic(expected = "foo")].
+    `#[ignore]`       - When applied to a function which is already attributed as a
+                        test, then the test runner will ignore these tests during
+                        normal test runs. Running with --ignored or --include-ignored will run
+                        these tests."#,
+        usage = options.usage(&message)
+    );
+}
+
+/// Parses command line arguments into test options.
+/// Returns `None` if help was requested (since we only show help message and don't run tests),
+/// returns `Some(Err(..))` if provided arguments are incorrect,
+/// otherwise creates a `TestOpts` object and returns it.
+pub fn parse_opts(args: &[String]) -> Option<OptRes> {
+    // Parse matches.
+    let opts = optgroups();
+    let args = args.get(1..).unwrap_or(args);
+    let matches = match opts.parse(args) {
+        Ok(m) => m,
+        Err(f) => return Some(Err(f.to_string())),
+    };
+
+    // Check if help was requested.
+    if matches.opt_present("h") {
+        // Show help and do nothing more.
+        usage(&args[0], &opts);
+        return None;
+    }
+
+    // Actually parse the opts.
+    let opts_result = parse_opts_impl(matches);
+
+    Some(opts_result)
+}
+
+// Gets the option value and checks if unstable features are enabled.
+macro_rules! unstable_optflag {
+    ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{
+        let opt = $matches.opt_present($option_name);
+        if !$allow_unstable && opt {
+            return Err(format!(
+                "The \"{}\" flag is only accepted on the nightly compiler",
+                $option_name
+            ));
+        }
+
+        opt
+    }};
+}
+
+// Implementation of `parse_opts` that doesn't care about help message
+// and returns a `Result`.
+fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
+    let allow_unstable = get_allow_unstable(&matches)?;
+
+    // Unstable flags
+    let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic");
+    let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored");
+    let time_options = get_time_options(&matches, allow_unstable)?;
+
+    let quiet = matches.opt_present("quiet");
+    let exact = matches.opt_present("exact");
+    let list = matches.opt_present("list");
+    let skip = matches.opt_strs("skip");
+
+    let bench_benchmarks = matches.opt_present("bench");
+    let run_tests = !bench_benchmarks || matches.opt_present("test");
+
+    let logfile = get_log_file(&matches)?;
+    let run_ignored = get_run_ignored(&matches, include_ignored)?;
+    let filter = get_filter(&matches)?;
+    let nocapture = get_nocapture(&matches)?;
+    let test_threads = get_test_threads(&matches)?;
+    let color = get_color_config(&matches)?;
+    let format = get_format(&matches, quiet, allow_unstable)?;
+
+    let options = Options::new().display_output(matches.opt_present("show-output"));
+
+    let test_opts = TestOpts {
+        list,
+        filter,
+        filter_exact: exact,
+        exclude_should_panic,
+        run_ignored,
+        run_tests,
+        bench_benchmarks,
+        logfile,
+        nocapture,
+        color,
+        format,
+        test_threads,
+        skip,
+        time_options,
+        options,
+    };
+
+    Ok(test_opts)
+}
+
+// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
+fn is_nightly() -> bool {
+    // Whether this is a feature-staged build, i.e., on the beta or stable channel
+    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+    // Whether we should enable unstable features for bootstrapping
+    let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
+
+    bootstrap || !disable_unstable_features
+}
+
+// Gets the CLI options assotiated with `report-time` feature.
+fn get_time_options(
+    matches: &getopts::Matches,
+    allow_unstable: bool)
+-> OptPartRes<Option<TestTimeOptions>> {
+    let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
+    let colored_opt_str = matches.opt_str("report-time");
+    let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
+    let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time");
+
+    // If `ensure-test-time` option is provided, time output is enforced,
+    // so user won't be confused if any of tests will silently fail.
+    let options = if report_time || ensure_test_time {
+        if ensure_test_time && !report_time {
+            report_time_colored = true;
+        }
+        Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored))
+    } else {
+        None
+    };
+
+    Ok(options)
+}
+
+fn get_test_threads(matches: &getopts::Matches) -> OptPartRes<Option<usize>> {
+    let test_threads = match matches.opt_str("test-threads") {
+        Some(n_str) => match n_str.parse::<usize>() {
+            Ok(0) => return Err("argument for --test-threads must not be 0".to_string()),
+            Ok(n) => Some(n),
+            Err(e) => {
+                return Err(format!(
+                    "argument for --test-threads must be a number > 0 \
+                     (error: {})",
+                    e
+                ));
+            }
+        },
+        None => None,
+    };
+
+    Ok(test_threads)
+}
+
+fn get_format(
+    matches: &getopts::Matches,
+    quiet: bool,
+    allow_unstable: bool
+) -> OptPartRes<OutputFormat> {
+    let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
+        None if quiet => OutputFormat::Terse,
+        Some("pretty") | None => OutputFormat::Pretty,
+        Some("terse") => OutputFormat::Terse,
+        Some("json") => {
+            if !allow_unstable {
+                return Err(
+                    "The \"json\" format is only accepted on the nightly compiler".into(),
+                );
+            }
+            OutputFormat::Json
+        }
+
+        Some(v) => {
+            return Err(format!(
+                "argument for --format must be pretty, terse, or json (was \
+                 {})",
+                v
+            ));
+        }
+    };
+
+    Ok(format)
+}
+
+fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> {
+    let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
+        Some("auto") | None => ColorConfig::AutoColor,
+        Some("always") => ColorConfig::AlwaysColor,
+        Some("never") => ColorConfig::NeverColor,
+
+        Some(v) => {
+            return Err(format!(
+                "argument for --color must be auto, always, or never (was \
+                 {})",
+                v
+            ));
+        }
+    };
+
+    Ok(color)
+}
+
+fn get_nocapture(matches: &getopts::Matches) -> OptPartRes<bool> {
+    let mut nocapture = matches.opt_present("nocapture");
+    if !nocapture {
+        nocapture = match env::var("RUST_TEST_NOCAPTURE") {
+            Ok(val) => &val != "0",
+            Err(_) => false,
+        };
+    }
+
+    Ok(nocapture)
+}
+
+fn get_run_ignored(matches: &getopts::Matches, include_ignored: bool) -> OptPartRes<RunIgnored> {
+    let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
+        (true, true) => {
+            return Err(
+                "the options --include-ignored and --ignored are mutually exclusive".into(),
+            );
+        }
+        (true, false) => RunIgnored::Yes,
+        (false, true) => RunIgnored::Only,
+        (false, false) => RunIgnored::No,
+    };
+
+    Ok(run_ignored)
+}
+
+fn get_filter(matches: &getopts::Matches) -> OptPartRes<Option<String>> {
+    let filter = if !matches.free.is_empty() {
+        Some(matches.free[0].clone())
+    } else {
+        None
+    };
+
+    Ok(filter)
+}
+
+fn get_allow_unstable(matches: &getopts::Matches) -> OptPartRes<bool> {
+    let mut allow_unstable = false;
+
+    if let Some(opt) = matches.opt_str("Z") {
+        if !is_nightly() {
+            return Err(
+                "the option `Z` is only accepted on the nightly compiler".into(),
+            );
+        }
+
+        match &*opt {
+            "unstable-options" => {
+                allow_unstable = true;
+            }
+            _ => {
+                return Err("Unrecognized option to `Z`".into());
+            }
+        }
+    };
+
+    Ok(allow_unstable)
+}
+
+fn get_log_file(matches: &getopts::Matches) -> OptPartRes<Option<PathBuf>> {
+    let logfile = matches.opt_str("logfile").map(|s| PathBuf::from(&s));
+
+    Ok(logfile)
+}
diff --git a/src/libtest/console.rs b/src/libtest/console.rs
new file mode 100644
index 00000000000..e17030726ce
--- /dev/null
+++ b/src/libtest/console.rs
@@ -0,0 +1,308 @@
+//! Module providing interface for running tests in the console.
+
+use std::fs::File;
+use std::io::prelude::Write;
+use std::io;
+
+use term;
+
+use super::{
+    bench::fmt_bench_samples,
+    cli::TestOpts,
+    event::{TestEvent, CompletedTest},
+    formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
+    helpers::{
+        concurrency::get_concurrency,
+        metrics::MetricMap,
+    },
+    types::{TestDesc, TestDescAndFn, NamePadding},
+    options::{Options, OutputFormat},
+    test_result::TestResult,
+    time::TestExecTime,
+    run_tests,
+    filter_tests,
+};
+
+/// Generic wrapper over stdout.
+pub enum OutputLocation<T> {
+    Pretty(Box<term::StdoutTerminal>),
+    Raw(T),
+}
+
+impl<T: Write> Write for OutputLocation<T> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match *self {
+            OutputLocation::Pretty(ref mut term) => term.write(buf),
+            OutputLocation::Raw(ref mut stdout) => stdout.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match *self {
+            OutputLocation::Pretty(ref mut term) => term.flush(),
+            OutputLocation::Raw(ref mut stdout) => stdout.flush(),
+        }
+    }
+}
+
+pub struct ConsoleTestState {
+    pub log_out: Option<File>,
+    pub total: usize,
+    pub passed: usize,
+    pub failed: usize,
+    pub ignored: usize,
+    pub allowed_fail: usize,
+    pub filtered_out: usize,
+    pub measured: usize,
+    pub metrics: MetricMap,
+    pub failures: Vec<(TestDesc, Vec<u8>)>,
+    pub not_failures: Vec<(TestDesc, Vec<u8>)>,
+    pub time_failures: Vec<(TestDesc, Vec<u8>)>,
+    pub options: Options,
+}
+
+impl ConsoleTestState {
+    pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
+        let log_out = match opts.logfile {
+            Some(ref path) => Some(File::create(path)?),
+            None => None,
+        };
+
+        Ok(ConsoleTestState {
+            log_out,
+            total: 0,
+            passed: 0,
+            failed: 0,
+            ignored: 0,
+            allowed_fail: 0,
+            filtered_out: 0,
+            measured: 0,
+            metrics: MetricMap::new(),
+            failures: Vec::new(),
+            not_failures: Vec::new(),
+            time_failures: Vec::new(),
+            options: opts.options,
+        })
+    }
+
+    pub fn write_log<F, S>(
+        &mut self,
+        msg: F,
+    ) -> io::Result<()>
+    where
+        S: AsRef<str>,
+        F: FnOnce() -> S,
+    {
+        match self.log_out {
+            None => Ok(()),
+            Some(ref mut o) => {
+                let msg = msg();
+                let msg = msg.as_ref();
+                o.write_all(msg.as_bytes())
+            },
+        }
+    }
+
+    pub fn write_log_result(&mut self,test: &TestDesc,
+        result: &TestResult,
+        exec_time: Option<&TestExecTime>,
+    ) -> io::Result<()> {
+        self.write_log(|| format!(
+            "{} {}",
+            match *result {
+                TestResult::TrOk => "ok".to_owned(),
+                TestResult::TrFailed => "failed".to_owned(),
+                TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
+                TestResult::TrIgnored => "ignored".to_owned(),
+                TestResult::TrAllowedFail => "failed (allowed)".to_owned(),
+                TestResult::TrBench(ref bs) => fmt_bench_samples(bs),
+                TestResult::TrTimedFail => "failed (time limit exceeded)".to_owned(),
+            },
+            test.name,
+        ))?;
+        if let Some(exec_time) = exec_time {
+            self.write_log(|| format!(" <{}>", exec_time))?;
+        }
+        self.write_log(|| "\n")
+    }
+
+    fn current_test_count(&self) -> usize {
+        self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
+    }
+}
+
+// List the tests to console, and optionally to logfile. Filters are honored.
+pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
+    let mut output = match term::stdout() {
+        None => OutputLocation::Raw(io::stdout()),
+        Some(t) => OutputLocation::Pretty(t),
+    };
+
+    let quiet = opts.format == OutputFormat::Terse;
+    let mut st = ConsoleTestState::new(opts)?;
+
+    let mut ntest = 0;
+    let mut nbench = 0;
+
+    for test in filter_tests(&opts, tests) {
+        use crate::TestFn::*;
+
+        let TestDescAndFn {
+            desc: TestDesc { name, .. },
+            testfn,
+        } = test;
+
+        let fntype = match testfn {
+            StaticTestFn(..) | DynTestFn(..) => {
+                ntest += 1;
+                "test"
+            }
+            StaticBenchFn(..) | DynBenchFn(..) => {
+                nbench += 1;
+                "benchmark"
+            }
+        };
+
+        writeln!(output, "{}: {}", name, fntype)?;
+        st.write_log(|| format!("{} {}\n", fntype, name))?;
+    }
+
+    fn plural(count: u32, s: &str) -> String {
+        match count {
+            1 => format!("{} {}", 1, s),
+            n => format!("{} {}s", n, s),
+        }
+    }
+
+    if !quiet {
+        if ntest != 0 || nbench != 0 {
+            writeln!(output, "")?;
+        }
+
+        writeln!(
+            output,
+            "{}, {}",
+            plural(ntest, "test"),
+            plural(nbench, "benchmark")
+        )?;
+    }
+
+    Ok(())
+}
+
+// Updates `ConsoleTestState` depending on result of the test execution.
+fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest) {
+    let test = completed_test.desc;
+    let stdout = completed_test.stdout;
+    match completed_test.result {
+        TestResult::TrOk => {
+            st.passed += 1;
+            st.not_failures.push((test, stdout));
+        }
+        TestResult::TrIgnored => st.ignored += 1,
+        TestResult::TrAllowedFail => st.allowed_fail += 1,
+        TestResult::TrBench(bs) => {
+            st.metrics.insert_metric(
+                test.name.as_slice(),
+                bs.ns_iter_summ.median,
+                bs.ns_iter_summ.max - bs.ns_iter_summ.min,
+            );
+            st.measured += 1
+        }
+        TestResult::TrFailed => {
+            st.failed += 1;
+            st.failures.push((test, stdout));
+        }
+        TestResult::TrFailedMsg(msg) => {
+            st.failed += 1;
+            let mut stdout = stdout;
+            stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
+            st.failures.push((test, stdout));
+        }
+        TestResult::TrTimedFail => {
+            st.failed += 1;
+            st.time_failures.push((test, stdout));
+        }
+    }
+}
+
+// Handler for events that occur during test execution.
+// It is provided as a callback to the `run_tests` function.
+fn on_test_event(
+    event: &TestEvent,
+    st: &mut ConsoleTestState,
+    out: &mut dyn OutputFormatter,
+) -> io::Result<()> {
+    match (*event).clone() {
+        TestEvent::TeFiltered(ref filtered_tests) => {
+            st.total = filtered_tests.len();
+            out.write_run_start(filtered_tests.len())?;
+        }
+        TestEvent::TeFilteredOut(filtered_out) => {
+            st.filtered_out = filtered_out;
+        }
+        TestEvent::TeWait(ref test) => out.write_test_start(test)?,
+        TestEvent::TeTimeout(ref test) => out.write_timeout(test)?,
+        TestEvent::TeResult(completed_test) => {
+            let test = &completed_test.desc;
+            let result = &completed_test.result;
+            let exec_time = &completed_test.exec_time;
+            let stdout = &completed_test.stdout;
+
+            st.write_log_result(test, result, exec_time.as_ref())?;
+            out.write_result(test, result, exec_time.as_ref(), &*stdout, st)?;
+            handle_test_result(st, completed_test);
+        }
+    }
+
+    Ok(())
+}
+
+/// A simple console test runner.
+/// Runs provided tests reporting process and results to the stdout.
+pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
+    let output = match term::stdout() {
+        None => OutputLocation::Raw(io::stdout()),
+        Some(t) => OutputLocation::Pretty(t),
+    };
+
+    let max_name_len = tests
+        .iter()
+        .max_by_key(|t| len_if_padded(*t))
+        .map(|t| t.desc.name.as_slice().len())
+        .unwrap_or(0);
+
+    let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1;
+
+    let mut out: Box<dyn OutputFormatter> = match opts.format {
+        OutputFormat::Pretty => Box::new(PrettyFormatter::new(
+            output,
+            opts.use_color(),
+            max_name_len,
+            is_multithreaded,
+            opts.time_options,
+        )),
+        OutputFormat::Terse => Box::new(TerseFormatter::new(
+            output,
+            opts.use_color(),
+            max_name_len,
+            is_multithreaded,
+        )),
+        OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+    };
+    let mut st = ConsoleTestState::new(opts)?;
+
+    run_tests(opts, tests, |x| on_test_event(&x, &mut st, &mut *out))?;
+
+    assert!(st.current_test_count() == st.total);
+
+    return out.write_run_finish(&st);
+}
+
+// Calculates padding for given test description.
+fn len_if_padded(t: &TestDescAndFn) -> usize {
+    match t.testfn.padding() {
+        NamePadding::PadNone => 0,
+        NamePadding::PadOnRight => t.desc.name.as_slice().len(),
+    }
+}
diff --git a/src/libtest/event.rs b/src/libtest/event.rs
new file mode 100644
index 00000000000..eefbd2d6a81
--- /dev/null
+++ b/src/libtest/event.rs
@@ -0,0 +1,41 @@
+//! Module containing different events that can occur
+//! during tests execution process.
+
+use super::types::TestDesc;
+use super::test_result::TestResult;
+use super::time::TestExecTime;
+
+#[derive(Debug, Clone)]
+pub struct CompletedTest {
+    pub desc: TestDesc,
+    pub result: TestResult,
+    pub exec_time: Option<TestExecTime>,
+    pub stdout: Vec<u8>,
+}
+
+impl CompletedTest {
+    pub fn new(
+        desc: TestDesc,
+        result: TestResult,
+        exec_time: Option<TestExecTime>,
+        stdout: Vec<u8>
+    ) -> Self {
+        Self {
+            desc,
+            result,
+            exec_time,
+            stdout,
+        }
+    }
+}
+
+unsafe impl Send for CompletedTest {}
+
+#[derive(Debug, Clone)]
+pub enum TestEvent {
+    TeFiltered(Vec<TestDesc>),
+    TeWait(TestDesc),
+    TeResult(CompletedTest),
+    TeTimeout(TestDesc),
+    TeFilteredOut(usize),
+}
diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs
index dcd733620bf..b73d7349678 100644
--- a/src/libtest/formatters/json.rs
+++ b/src/libtest/formatters/json.rs
@@ -1,4 +1,16 @@
-use super::*;
+use std::{
+    io,
+    io::prelude::Write,
+    borrow::Cow,
+};
+
+use crate::{
+    types::TestDesc,
+    time,
+    test_result::TestResult,
+    console::{ConsoleTestState, OutputLocation},
+};
+use super::OutputFormatter;
 
 pub(crate) struct JsonFormatter<T> {
     out: OutputLocation<T>,
@@ -27,7 +39,7 @@ impl<T: Write> JsonFormatter<T> {
         ty: &str,
         name: &str,
         evt: &str,
-        exec_time: Option<&TestExecTime>,
+        exec_time: Option<&time::TestExecTime>,
         stdout: Option<Cow<'_, str>>,
         extra: Option<&str>,
     ) -> io::Result<()> {
@@ -76,25 +88,26 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
         &mut self,
         desc: &TestDesc,
         result: &TestResult,
-        exec_time: Option<&TestExecTime>,
+        exec_time: Option<&time::TestExecTime>,
         stdout: &[u8],
         state: &ConsoleTestState,
     ) -> io::Result<()> {
-        let stdout = if (state.options.display_output || *result != TrOk) && stdout.len() > 0 {
+        let display_stdout = state.options.display_output || *result != TestResult::TrOk;
+        let stdout = if display_stdout && stdout.len() > 0 {
             Some(String::from_utf8_lossy(stdout))
         } else {
             None
         };
         match *result {
-            TrOk => {
+            TestResult::TrOk => {
                 self.write_event("test", desc.name.as_slice(), "ok", exec_time, stdout, None)
             }
 
-            TrFailed => {
+            TestResult::TrFailed => {
                 self.write_event("test", desc.name.as_slice(), "failed", exec_time, stdout, None)
             }
 
-            TrTimedFail => self.write_event(
+            TestResult::TrTimedFail => self.write_event(
                 "test",
                 desc.name.as_slice(),
                 "failed",
@@ -103,7 +116,7 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
                 Some(r#""reason": "time limit exceeded""#),
             ),
 
-            TrFailedMsg(ref m) => self.write_event(
+            TestResult::TrFailedMsg(ref m) => self.write_event(
                 "test",
                 desc.name.as_slice(),
                 "failed",
@@ -112,11 +125,11 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
                 Some(&*format!(r#""message": "{}""#, EscapedString(m))),
             ),
 
-            TrIgnored => {
+            TestResult::TrIgnored => {
                 self.write_event("test", desc.name.as_slice(), "ignored", exec_time, stdout, None)
             }
 
-            TrAllowedFail => self.write_event(
+            TestResult::TrAllowedFail => self.write_event(
                 "test",
                 desc.name.as_slice(),
                 "allowed_failure",
@@ -125,7 +138,7 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
                 None,
             ),
 
-            TrBench(ref bs) => {
+            TestResult::TrBench(ref bs) => {
                 let median = bs.ns_iter_summ.median as usize;
                 let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
 
diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs
index dd202fb3ab6..b6649a3effc 100644
--- a/src/libtest/formatters/mod.rs
+++ b/src/libtest/formatters/mod.rs
@@ -1,4 +1,14 @@
-use super::*;
+use std::{
+    io,
+    io::prelude::Write,
+};
+
+use crate::{
+    types::{TestDesc, TestName},
+    time,
+    test_result::TestResult,
+    console::{ConsoleTestState},
+};
 
 mod pretty;
 mod json;
@@ -16,7 +26,7 @@ pub(crate) trait OutputFormatter {
         &mut self,
         desc: &TestDesc,
         result: &TestResult,
-        exec_time: Option<&TestExecTime>,
+        exec_time: Option<&time::TestExecTime>,
         stdout: &[u8],
         state: &ConsoleTestState,
     ) -> io::Result<()>;
diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs
index 2935b4c99ce..2fdbc63d513 100644
--- a/src/libtest/formatters/pretty.rs
+++ b/src/libtest/formatters/pretty.rs
@@ -1,9 +1,21 @@
-use super::*;
+use std::{
+    io,
+    io::prelude::Write,
+};
+
+use crate::{
+    types::TestDesc,
+    time,
+    test_result::TestResult,
+    console::{ConsoleTestState, OutputLocation},
+    bench::fmt_bench_samples,
+};
+use super::OutputFormatter;
 
 pub(crate) struct PrettyFormatter<T> {
     out: OutputLocation<T>,
     use_color: bool,
-    time_options: Option<TestTimeOptions>,
+    time_options: Option<time::TestTimeOptions>,
 
     /// Number of columns to fill when aligning names
     max_name_len: usize,
@@ -17,7 +29,7 @@ impl<T: Write> PrettyFormatter<T> {
         use_color: bool,
         max_name_len: usize,
         is_multithreaded: bool,
-        time_options: Option<TestTimeOptions>,
+        time_options: Option<time::TestTimeOptions>,
     ) -> Self {
         PrettyFormatter {
             out,
@@ -67,7 +79,7 @@ impl<T: Write> PrettyFormatter<T> {
 
     pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
         match self.out {
-            Pretty(ref mut term) => {
+            OutputLocation::Pretty(ref mut term) => {
                 if self.use_color {
                     term.fg(color)?;
                 }
@@ -77,7 +89,7 @@ impl<T: Write> PrettyFormatter<T> {
                 }
                 term.flush()
             }
-            Raw(ref mut stdout) => {
+            OutputLocation::Raw(ref mut stdout) => {
                 stdout.write_all(word.as_bytes())?;
                 stdout.flush()
             }
@@ -93,7 +105,7 @@ impl<T: Write> PrettyFormatter<T> {
     fn write_time(
         &mut self,
         desc: &TestDesc,
-        exec_time: Option<&TestExecTime>
+        exec_time: Option<&time::TestExecTime>
     ) -> io::Result<()> {
         if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
             let time_str = format!(" <{}>", time);
@@ -194,7 +206,7 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
         &mut self,
         desc: &TestDesc,
         result: &TestResult,
-        exec_time: Option<&TestExecTime>,
+        exec_time: Option<&time::TestExecTime>,
         _: &[u8],
         _: &ConsoleTestState,
     ) -> io::Result<()> {
@@ -203,15 +215,15 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
         }
 
         match *result {
-            TrOk => self.write_ok()?,
-            TrFailed | TrFailedMsg(_) => self.write_failed()?,
-            TrIgnored => self.write_ignored()?,
-            TrAllowedFail => self.write_allowed_fail()?,
-            TrBench(ref bs) => {
+            TestResult::TrOk => self.write_ok()?,
+            TestResult::TrFailed | TestResult::TrFailedMsg(_) => self.write_failed()?,
+            TestResult::TrIgnored => self.write_ignored()?,
+            TestResult::TrAllowedFail => self.write_allowed_fail()?,
+            TestResult::TrBench(ref bs) => {
                 self.write_bench()?;
                 self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?;
             }
-            TrTimedFail => self.write_time_failed()?,
+            TestResult::TrTimedFail => self.write_time_failed()?,
         }
 
         self.write_time(desc, exec_time)?;
@@ -225,7 +237,7 @@ impl<T: Write> OutputFormatter for PrettyFormatter<T> {
 
         self.write_plain(&format!(
             "test {} has been running for over {} seconds\n",
-            desc.name, TEST_WARN_TIMEOUT_S
+            desc.name, time::TEST_WARN_TIMEOUT_S
         ))
     }
 
diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs
index 8914e7b6b56..fe56157d9c1 100644
--- a/src/libtest/formatters/terse.rs
+++ b/src/libtest/formatters/terse.rs
@@ -1,4 +1,20 @@
-use super::*;
+use std::{
+    io,
+    io::prelude::Write,
+};
+
+use crate::{
+    types::TestDesc,
+    time,
+    test_result::TestResult,
+    types::NamePadding,
+    console::{ConsoleTestState, OutputLocation},
+    bench::fmt_bench_samples,
+};
+use super::OutputFormatter;
+
+// insert a '\n' after 100 tests in quiet mode
+const QUIET_MODE_MAX_COLUMN: usize = 100;
 
 pub(crate) struct TerseFormatter<T> {
     out: OutputLocation<T>,
@@ -68,7 +84,7 @@ impl<T: Write> TerseFormatter<T> {
 
     pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
         match self.out {
-            Pretty(ref mut term) => {
+            OutputLocation::Pretty(ref mut term) => {
                 if self.use_color {
                     term.fg(color)?;
                 }
@@ -78,7 +94,7 @@ impl<T: Write> TerseFormatter<T> {
                 }
                 term.flush()
             }
-            Raw(ref mut stdout) => {
+            OutputLocation::Raw(ref mut stdout) => {
                 stdout.write_all(word.as_bytes())?;
                 stdout.flush()
             }
@@ -163,7 +179,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
         // in order to indicate benchmarks.
         // When running benchmarks, terse-mode should still print their name as if
         // it is the Pretty formatter.
-        if !self.is_multithreaded && desc.name.padding() == PadOnRight {
+        if !self.is_multithreaded && desc.name.padding() == NamePadding::PadOnRight {
             self.write_test_name(desc)?;
         }
 
@@ -174,16 +190,18 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
         &mut self,
         desc: &TestDesc,
         result: &TestResult,
-        _: Option<&TestExecTime>,
+        _: Option<&time::TestExecTime>,
         _: &[u8],
         _: &ConsoleTestState,
     ) -> io::Result<()> {
         match *result {
-            TrOk => self.write_ok(),
-            TrFailed | TrFailedMsg(_) | TrTimedFail => self.write_failed(),
-            TrIgnored => self.write_ignored(),
-            TrAllowedFail => self.write_allowed_fail(),
-            TrBench(ref bs) => {
+            TestResult::TrOk => self.write_ok(),
+            TestResult::TrFailed
+                | TestResult::TrFailedMsg(_)
+                | TestResult::TrTimedFail => self.write_failed(),
+            TestResult::TrIgnored => self.write_ignored(),
+            TestResult::TrAllowedFail => self.write_allowed_fail(),
+            TestResult::TrBench(ref bs) => {
                 if self.is_multithreaded {
                     self.write_test_name(desc)?;
                 }
@@ -196,7 +214,7 @@ impl<T: Write> OutputFormatter for TerseFormatter<T> {
     fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
         self.write_plain(&format!(
             "test {} has been running for over {} seconds\n",
-            desc.name, TEST_WARN_TIMEOUT_S
+            desc.name, time::TEST_WARN_TIMEOUT_S
         ))
     }
 
diff --git a/src/libtest/helpers/concurrency.rs b/src/libtest/helpers/concurrency.rs
new file mode 100644
index 00000000000..61651a927c5
--- /dev/null
+++ b/src/libtest/helpers/concurrency.rs
@@ -0,0 +1,143 @@
+//! Helper module which helps to determine amount of threads to be used
+//! during tests execution.
+use std::env;
+
+#[allow(deprecated)]
+pub fn get_concurrency() -> usize {
+    return match env::var("RUST_TEST_THREADS") {
+        Ok(s) => {
+            let opt_n: Option<usize> = s.parse().ok();
+            match opt_n {
+                Some(n) if n > 0 => n,
+                _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s),
+            }
+        }
+        Err(..) => num_cpus(),
+    };
+
+    #[cfg(windows)]
+    #[allow(nonstandard_style)]
+    fn num_cpus() -> usize {
+        #[repr(C)]
+        struct SYSTEM_INFO {
+            wProcessorArchitecture: u16,
+            wReserved: u16,
+            dwPageSize: u32,
+            lpMinimumApplicationAddress: *mut u8,
+            lpMaximumApplicationAddress: *mut u8,
+            dwActiveProcessorMask: *mut u8,
+            dwNumberOfProcessors: u32,
+            dwProcessorType: u32,
+            dwAllocationGranularity: u32,
+            wProcessorLevel: u16,
+            wProcessorRevision: u16,
+        }
+        extern "system" {
+            fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
+        }
+        unsafe {
+            let mut sysinfo = std::mem::zeroed();
+            GetSystemInfo(&mut sysinfo);
+            sysinfo.dwNumberOfProcessors as usize
+        }
+    }
+
+    #[cfg(target_os = "vxworks")]
+    fn num_cpus() -> usize {
+        // FIXME: Implement num_cpus on vxWorks
+        1
+    }
+
+    #[cfg(target_os = "redox")]
+    fn num_cpus() -> usize {
+        // FIXME: Implement num_cpus on Redox
+        1
+    }
+
+    #[cfg(any(
+        all(target_arch = "wasm32", not(target_os = "emscripten")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    ))]
+    fn num_cpus() -> usize {
+        1
+    }
+
+    #[cfg(any(
+        target_os = "android",
+        target_os = "cloudabi",
+        target_os = "emscripten",
+        target_os = "fuchsia",
+        target_os = "ios",
+        target_os = "linux",
+        target_os = "macos",
+        target_os = "solaris",
+    ))]
+    fn num_cpus() -> usize {
+        unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
+    }
+
+    #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))]
+    fn num_cpus() -> usize {
+        use std::ptr;
+
+        let mut cpus: libc::c_uint = 0;
+        let mut cpus_size = std::mem::size_of_val(&cpus);
+
+        unsafe {
+            cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
+        }
+        if cpus < 1 {
+            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+            unsafe {
+                libc::sysctl(
+                    mib.as_mut_ptr(),
+                    2,
+                    &mut cpus as *mut _ as *mut _,
+                    &mut cpus_size as *mut _ as *mut _,
+                    ptr::null_mut(),
+                    0,
+                );
+            }
+            if cpus < 1 {
+                cpus = 1;
+            }
+        }
+        cpus as usize
+    }
+
+    #[cfg(target_os = "openbsd")]
+    fn num_cpus() -> usize {
+        use std::ptr;
+
+        let mut cpus: libc::c_uint = 0;
+        let mut cpus_size = std::mem::size_of_val(&cpus);
+        let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
+
+        unsafe {
+            libc::sysctl(
+                mib.as_mut_ptr(),
+                2,
+                &mut cpus as *mut _ as *mut _,
+                &mut cpus_size as *mut _ as *mut _,
+                ptr::null_mut(),
+                0,
+            );
+        }
+        if cpus < 1 {
+            cpus = 1;
+        }
+        cpus as usize
+    }
+
+    #[cfg(target_os = "haiku")]
+    fn num_cpus() -> usize {
+        // FIXME: implement
+        1
+    }
+
+    #[cfg(target_os = "l4re")]
+    fn num_cpus() -> usize {
+        // FIXME: implement
+        1
+    }
+}
diff --git a/src/libtest/helpers/exit_code.rs b/src/libtest/helpers/exit_code.rs
new file mode 100644
index 00000000000..831bef3b118
--- /dev/null
+++ b/src/libtest/helpers/exit_code.rs
@@ -0,0 +1,20 @@
+//! Helper module to detect subprocess exit code.
+
+use std::process::ExitStatus;
+
+#[cfg(not(unix))]
+pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
+    status.code().ok_or("received no exit code from child process".into())
+}
+
+#[cfg(unix)]
+pub fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
+    use std::os::unix::process::ExitStatusExt;
+    match status.code() {
+        Some(code) => Ok(code),
+        None => match status.signal() {
+            Some(signal) => Err(format!("child process exited with signal {}", signal)),
+            None => Err("child process exited with unknown signal".into()),
+        }
+    }
+}
diff --git a/src/libtest/helpers/isatty.rs b/src/libtest/helpers/isatty.rs
new file mode 100644
index 00000000000..6e4954778e6
--- /dev/null
+++ b/src/libtest/helpers/isatty.rs
@@ -0,0 +1,33 @@
+//! Helper module which provides a function to test
+//! if stdout is a tty.
+
+#[cfg(any(
+    target_os = "cloudabi",
+    all(target_arch = "wasm32", not(target_os = "emscripten")),
+    all(target_vendor = "fortanix", target_env = "sgx")
+))]
+pub fn stdout_isatty() -> bool {
+    // FIXME: Implement isatty on SGX
+    false
+}
+#[cfg(unix)]
+pub fn stdout_isatty() -> bool {
+    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
+}
+#[cfg(windows)]
+pub fn stdout_isatty() -> bool {
+    type DWORD = u32;
+    type BOOL = i32;
+    type HANDLE = *mut u8;
+    type LPDWORD = *mut u32;
+    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+    extern "system" {
+        fn GetStdHandle(which: DWORD) -> HANDLE;
+        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
+    }
+    unsafe {
+        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
+        let mut out = 0;
+        GetConsoleMode(handle, &mut out) != 0
+    }
+}
diff --git a/src/libtest/helpers/metrics.rs b/src/libtest/helpers/metrics.rs
new file mode 100644
index 00000000000..f77a23e6875
--- /dev/null
+++ b/src/libtest/helpers/metrics.rs
@@ -0,0 +1,50 @@
+//! Benchmark metrics.
+use std::collections::BTreeMap;
+
+#[derive(Clone, PartialEq, Debug, Copy)]
+pub struct Metric {
+    value: f64,
+    noise: f64,
+}
+
+impl Metric {
+    pub fn new(value: f64, noise: f64) -> Metric {
+        Metric { value, noise }
+    }
+}
+
+#[derive(Clone, PartialEq)]
+pub struct MetricMap(BTreeMap<String, Metric>);
+
+impl MetricMap {
+    pub fn new() -> MetricMap {
+        MetricMap(BTreeMap::new())
+    }
+
+    /// Insert a named `value` (+/- `noise`) metric into the map. The value
+    /// must be non-negative. The `noise` indicates the uncertainty of the
+    /// metric, which doubles as the "noise range" of acceptable
+    /// pairwise-regressions on this named value, when comparing from one
+    /// metric to the next using `compare_to_old`.
+    ///
+    /// If `noise` is positive, then it means this metric is of a value
+    /// you want to see grow smaller, so a change larger than `noise` in the
+    /// positive direction represents a regression.
+    ///
+    /// If `noise` is negative, then it means this metric is of a value
+    /// you want to see grow larger, so a change larger than `noise` in the
+    /// negative direction represents a regression.
+    pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
+        let m = Metric { value, noise };
+        self.0.insert(name.to_owned(), m);
+    }
+
+    pub fn fmt_metrics(&self) -> String {
+        let v = self
+            .0
+            .iter()
+            .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
+            .collect::<Vec<_>>();
+        v.join(", ")
+    }
+}
diff --git a/src/libtest/helpers/mod.rs b/src/libtest/helpers/mod.rs
new file mode 100644
index 00000000000..6a2ef6086cb
--- /dev/null
+++ b/src/libtest/helpers/mod.rs
@@ -0,0 +1,8 @@
+//! Module with common helpers not directly related to tests
+//! but used in `libtest`.
+
+pub mod concurrency;
+pub mod isatty;
+pub mod metrics;
+pub mod sink;
+pub mod exit_code;
diff --git a/src/libtest/helpers/sink.rs b/src/libtest/helpers/sink.rs
new file mode 100644
index 00000000000..aa7fe248773
--- /dev/null
+++ b/src/libtest/helpers/sink.rs
@@ -0,0 +1,24 @@
+//! Module providing a helper structure to capture output in subprocesses.
+
+use std::{
+    io,
+    io::prelude::Write,
+    sync::{Arc, Mutex},
+};
+
+pub struct Sink(Arc<Mutex<Vec<u8>>>);
+
+impl Sink {
+    pub fn new_boxed(data: &Arc<Mutex<Vec<u8>>>) -> Box<Self> {
+        Box::new(Self(data.clone()))
+    }
+}
+
+impl Write for Sink {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        Write::write(&mut *self.0.lock().unwrap(), data)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 5a77413b2cb..8c1e9f1722a 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -30,320 +30,81 @@
 #![feature(termination_trait_lib)]
 #![feature(test)]
 
-use getopts;
-#[cfg(any(unix, target_os = "cloudabi"))]
-extern crate libc;
-use term;
-
+// Public reexports
 pub use self::ColorConfig::*;
-use self::NamePadding::*;
-use self::OutputLocation::*;
-use self::TestEvent::*;
-pub use self::TestFn::*;
-pub use self::TestName::*;
-pub use self::TestResult::*;
-
-use std::any::Any;
-use std::borrow::Cow;
-use std::cmp;
-use std::collections::BTreeMap;
-use std::env;
-use std::fmt;
-use std::fs::File;
-use std::io;
-use std::io::prelude::*;
-use std::panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo};
-use std::path::PathBuf;
-use std::process;
-use std::process::{ExitStatus, Command, Termination};
-use std::str::FromStr;
-use std::sync::mpsc::{channel, Sender};
-use std::sync::{Arc, Mutex};
-use std::thread;
-use std::time::{Duration, Instant};
-
-#[cfg(test)]
-mod tests;
-
-const TEST_WARN_TIMEOUT_S: u64 = 60;
-const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
-
-const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE";
-
-// Return codes for secondary process.
-// Start somewhere other than 0 so we know the return code means what we think
-// it means.
-const TR_OK: i32 = 50;
-const TR_FAILED: i32 = 51;
-
-/// This small module contains constants used by `report-time` option.
-/// Those constants values will be used if corresponding environment variables are not set.
-///
-/// To override values for unit-tests, use a constant `RUST_TEST_TIME_UNIT`,
-/// To override values for integration tests, use a constant `RUST_TEST_TIME_INTEGRATION`,
-/// To override values for doctests, use a constant `RUST_TEST_TIME_DOCTEST`.
-///
-/// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means
-/// warn time, and 200 means critical time.
-pub mod time_constants {
-    use std::time::Duration;
-    use super::TEST_WARN_TIMEOUT_S;
-
-    /// Environment variable for overriding default threshold for unit-tests.
-    pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT";
-
-    // Unit tests are supposed to be really quick.
-    pub const UNIT_WARN: Duration = Duration::from_millis(50);
-    pub const UNIT_CRITICAL: Duration = Duration::from_millis(100);
-
-    /// Environment variable for overriding default threshold for unit-tests.
-    pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION";
-
-    // Integration tests may have a lot of work, so they can take longer to execute.
-    pub const INTEGRATION_WARN: Duration = Duration::from_millis(500);
-    pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000);
-
-    /// Environment variable for overriding default threshold for unit-tests.
-    pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST";
-
-    // Doctests are similar to integration tests, because they can include a lot of
-    // initialization code.
-    pub const DOCTEST_WARN: Duration = INTEGRATION_WARN;
-    pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL;
-
-    // Do not suppose anything about unknown tests, base limits on the
-    // `TEST_WARN_TIMEOUT_S` constant.
-    pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S);
-    pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2);
-}
-
-// to be used by rustc to compile tests in libtest
+pub use self::types::*;
+pub use self::types::TestName::*;
+pub use self::options::{ColorConfig, Options, OutputFormat, RunIgnored, ShouldPanic};
+pub use self::bench::{Bencher, black_box};
+pub use self::console::run_tests_console;
+pub use cli::TestOpts;
+
+// Module to be used by rustc to compile tests in libtest
 pub mod test {
     pub use crate::{
-        assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
-        Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, RunStrategy,
-        ShouldPanic, StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName,
-        TestOpts, TestTimeOptions, TestType, TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
+        bench::Bencher,
+        cli::{parse_opts, TestOpts},
+        helpers::metrics::{Metric, MetricMap},
+        options::{ShouldPanic, Options, RunIgnored, RunStrategy},
+        test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk},
+        time::{TestTimeOptions, TestExecTime},
+        types::{
+            DynTestFn, DynTestName, StaticBenchFn, StaticTestFn, StaticTestName,
+            TestDesc, TestDescAndFn, TestName, TestType,
+        },
+        assert_test_result, filter_tests, run_test, test_main, test_main_static,
     };
 }
 
-mod formatters;
-pub mod stats;
-
-use crate::formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter};
-
-/// Whether to execute tests concurrently or not
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Concurrent {
-    Yes,
-    No,
-}
-
-/// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html)
-/// conventions.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum TestType {
-    /// Unit-tests are expected to be in the `src` folder of the crate.
-    UnitTest,
-    /// Integration-style tests are expected to be in the `tests` folder of the crate.
-    IntegrationTest,
-    /// Doctests are created by the `librustdoc` manually, so it's a different type of test.
-    DocTest,
-    /// Tests for the sources that don't follow the project layout convention
-    /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly).
-    Unknown,
-}
-
-// The name of a test. By convention this follows the rules for rust
-// paths; i.e., it should be a series of identifiers separated by double
-// colons. This way if some test runner wants to arrange the tests
-// hierarchically it may.
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub enum TestName {
-    StaticTestName(&'static str),
-    DynTestName(String),
-    AlignedTestName(Cow<'static, str>, NamePadding),
-}
-impl TestName {
-    fn as_slice(&self) -> &str {
-        match *self {
-            StaticTestName(s) => s,
-            DynTestName(ref s) => s,
-            AlignedTestName(ref s, _) => &*s,
-        }
-    }
-
-    fn padding(&self) -> NamePadding {
-        match self {
-            &AlignedTestName(_, p) => p,
-            _ => PadNone,
-        }
-    }
-
-    fn with_padding(&self, padding: NamePadding) -> TestName {
-        let name = match self {
-            &TestName::StaticTestName(name) => Cow::Borrowed(name),
-            &TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
-            &TestName::AlignedTestName(ref name, _) => name.clone(),
-        };
-
-        TestName::AlignedTestName(name, padding)
-    }
-}
-impl fmt::Display for TestName {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self.as_slice(), f)
-    }
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum NamePadding {
-    PadNone,
-    PadOnRight,
-}
-
-impl TestDesc {
-    fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
-        let mut name = String::from(self.name.as_slice());
-        let fill = column_count.saturating_sub(name.len());
-        let pad = " ".repeat(fill);
-        match align {
-            PadNone => name,
-            PadOnRight => {
-                name.push_str(&pad);
-                name
-            }
-        }
-    }
-}
-
-/// Represents a benchmark function.
-pub trait TDynBenchFn: Send {
-    fn run(&self, harness: &mut Bencher);
-}
-
-// A function that runs a test. If the function returns successfully,
-// the test succeeds; if the function panics then the test fails. We
-// may need to come up with a more clever definition of test in order
-// to support isolation of tests into threads.
-pub enum TestFn {
-    StaticTestFn(fn()),
-    StaticBenchFn(fn(&mut Bencher)),
-    DynTestFn(Box<dyn FnOnce() + Send>),
-    DynBenchFn(Box<dyn TDynBenchFn + 'static>),
-}
-
-impl TestFn {
-    fn padding(&self) -> NamePadding {
-        match *self {
-            StaticTestFn(..) => PadNone,
-            StaticBenchFn(..) => PadOnRight,
-            DynTestFn(..) => PadNone,
-            DynBenchFn(..) => PadOnRight,
-        }
-    }
-}
-
-impl fmt::Debug for TestFn {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match *self {
-            StaticTestFn(..) => "StaticTestFn(..)",
-            StaticBenchFn(..) => "StaticBenchFn(..)",
-            DynTestFn(..) => "DynTestFn(..)",
-            DynBenchFn(..) => "DynBenchFn(..)",
-        })
-    }
-}
+use std::{
+    env,
+    io,
+    io::prelude::Write,
+    panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo},
+    process,
+    process::{Command, Termination},
+    sync::mpsc::{channel, Sender},
+    sync::{Arc, Mutex},
+    thread,
+    time::{Duration, Instant},
+};
 
-/// Manager of the benchmarking runs.
-///
-/// This is fed into functions marked with `#[bench]` to allow for
-/// set-up & tear-down before running a piece of code repeatedly via a
-/// call to `iter`.
-#[derive(Clone)]
-pub struct Bencher {
-    mode: BenchMode,
-    summary: Option<stats::Summary>,
-    pub bytes: u64,
-}
-
-#[derive(Clone, PartialEq, Eq)]
-pub enum BenchMode {
-    Auto,
-    Single,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum ShouldPanic {
-    No,
-    Yes,
-    YesWithMessage(&'static str),
-}
-
-// The definition of a single test. A test runner will run a list of
-// these.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub struct TestDesc {
-    pub name: TestName,
-    pub ignore: bool,
-    pub should_panic: ShouldPanic,
-    pub allow_fail: bool,
-    pub test_type: TestType,
-}
-
-#[derive(Debug)]
-pub struct TestDescAndFn {
-    pub desc: TestDesc,
-    pub testfn: TestFn,
-}
-
-#[derive(Clone, PartialEq, Debug, Copy)]
-pub struct Metric {
-    value: f64,
-    noise: f64,
-}
-
-impl Metric {
-    pub fn new(value: f64, noise: f64) -> Metric {
-        Metric { value, noise }
-    }
-}
+pub mod stats;
+pub mod bench;
+mod formatters;
+mod cli;
+mod console;
+mod event;
+mod helpers;
+mod time;
+mod types;
+mod options;
+mod test_result;
 
-/// In case we want to add other options as well, just add them in this struct.
-#[derive(Copy, Clone, Debug)]
-pub struct Options {
-    display_output: bool,
-    panic_abort: bool,
-}
+#[cfg(test)]
+mod tests;
 
-impl Options {
-    pub fn new() -> Options {
-        Options {
-            display_output: false,
-            panic_abort: false,
-        }
-    }
+use test_result::*;
+use time::TestExecTime;
+use options::{RunStrategy, Concurrent};
+use event::{CompletedTest, TestEvent};
+use helpers::sink::Sink;
+use helpers::concurrency::get_concurrency;
+use helpers::exit_code::get_exit_code;
 
-    pub fn display_output(mut self, display_output: bool) -> Options {
-        self.display_output = display_output;
-        self
-    }
+// Process exit code to be used to indicate test failures.
+const ERROR_EXIT_CODE: i32 = 101;
 
-    pub fn panic_abort(mut self, panic_abort: bool) -> Options {
-        self.panic_abort = panic_abort;
-        self
-    }
-}
+const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE";
 
 // The default console test runner. It accepts the command line
 // arguments and a vector of test_descs.
 pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Options>) {
-    let mut opts = match parse_opts(args) {
+    let mut opts = match cli::parse_opts(args) {
         Some(Ok(o)) => o,
         Some(Err(msg)) => {
             eprintln!("error: {}", msg);
-            process::exit(101);
+            process::exit(ERROR_EXIT_CODE);
         }
         None => return,
     };
@@ -351,17 +112,17 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
         opts.options = options;
     }
     if opts.list {
-        if let Err(e) = list_tests_console(&opts, tests) {
+        if let Err(e) = console::list_tests_console(&opts, tests) {
             eprintln!("error: io error when listing tests: {:?}", e);
-            process::exit(101);
+            process::exit(ERROR_EXIT_CODE);
         }
     } else {
-        match run_tests_console(&opts, tests) {
+        match console::run_tests_console(&opts, tests) {
             Ok(true) => {}
-            Ok(false) => process::exit(101),
+            Ok(false) => process::exit(ERROR_EXIT_CODE),
             Err(e) => {
                 eprintln!("error: io error when listing tests: {:?}", e);
-                process::exit(101);
+                process::exit(ERROR_EXIT_CODE);
             }
         }
     }
@@ -440,938 +201,11 @@ pub fn assert_test_result<T: Termination>(result: T) {
     );
 }
 
-#[derive(Copy, Clone, Debug)]
-pub enum ColorConfig {
-    AutoColor,
-    AlwaysColor,
-    NeverColor,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum OutputFormat {
-    Pretty,
-    Terse,
-    Json,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum RunIgnored {
-    Yes,
-    No,
-    Only,
-}
-
-/// Structure denoting time limits for test execution.
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
-pub struct TimeThreshold {
-    pub warn: Duration,
-    pub critical: Duration,
-}
-
-impl TimeThreshold {
-    /// Creates a new `TimeThreshold` instance with provided durations.
-    pub fn new(warn: Duration, critical: Duration) -> Self {
-        Self {
-            warn,
-            critical,
-        }
-    }
-
-    /// Attempts to create a `TimeThreshold` instance with values obtained
-    /// from the environment variable, and returns `None` if the variable
-    /// is not set.
-    /// Environment variable format is expected to match `\d+,\d+`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if variable with provided name is set but contains inappropriate
-    /// value.
-    pub fn from_env_var(env_var_name: &str) -> Option<Self> {
-        let durations_str = env::var(env_var_name).ok()?;
-
-        // Split string into 2 substrings by comma and try to parse numbers.
-        let mut durations = durations_str
-            .splitn(2, ',')
-            .map(|v| {
-                u64::from_str(v).unwrap_or_else(|_| {
-                    panic!(
-                        "Duration value in variable {} is expected to be a number, but got {}",
-                        env_var_name, v
-                    )
-                })
-            });
-
-        // Callback to be called if the environment variable has unexpected structure.
-        let panic_on_incorrect_value = || {
-            panic!(
-                "Duration variable {} expected to have 2 numbers separated by comma, but got {}",
-                env_var_name, durations_str
-            );
-        };
-
-        let (warn, critical) = (
-            durations.next().unwrap_or_else(panic_on_incorrect_value),
-            durations.next().unwrap_or_else(panic_on_incorrect_value)
-        );
-
-        if warn > critical {
-            panic!("Test execution warn time should be less or equal to the critical time");
-        }
-
-        Some(Self::new(Duration::from_millis(warn), Duration::from_millis(critical)))
-    }
-}
-
-/// Structure with parameters for calculating test execution time.
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
-pub struct TestTimeOptions {
-    /// Denotes if the test critical execution time limit excess should be considered
-    /// a test failure.
-    pub error_on_excess: bool,
-    pub colored: bool,
-    pub unit_threshold: TimeThreshold,
-    pub integration_threshold: TimeThreshold,
-    pub doctest_threshold: TimeThreshold,
-}
-
-impl TestTimeOptions {
-    pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self {
-        let unit_threshold =
-            TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME)
-                .unwrap_or_else(Self::default_unit);
-
-        let integration_threshold =
-            TimeThreshold::from_env_var(time_constants::INTEGRATION_ENV_NAME)
-                .unwrap_or_else(Self::default_integration);
-
-        let doctest_threshold =
-            TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME)
-                .unwrap_or_else(Self::default_doctest);
-
-        Self {
-            error_on_excess,
-            colored,
-            unit_threshold,
-            integration_threshold,
-            doctest_threshold,
-        }
-    }
-
-    pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool {
-        exec_time.0 >= self.warn_time(test)
-    }
-
-    pub fn is_critical(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool {
-        exec_time.0 >= self.critical_time(test)
-    }
-
-    fn warn_time(&self, test: &TestDesc) -> Duration {
-        match test.test_type {
-            TestType::UnitTest => self.unit_threshold.warn,
-            TestType::IntegrationTest => self.integration_threshold.warn,
-            TestType::DocTest => self.doctest_threshold.warn,
-            TestType::Unknown => time_constants::UNKNOWN_WARN,
-        }
-    }
-
-    fn critical_time(&self, test: &TestDesc) -> Duration {
-        match test.test_type {
-            TestType::UnitTest => self.unit_threshold.critical,
-            TestType::IntegrationTest => self.integration_threshold.critical,
-            TestType::DocTest => self.doctest_threshold.critical,
-            TestType::Unknown => time_constants::UNKNOWN_CRITICAL,
-        }
-    }
-
-    fn default_unit() -> TimeThreshold {
-        TimeThreshold::new(time_constants::UNIT_WARN, time_constants::UNIT_CRITICAL)
-    }
-
-    fn default_integration() -> TimeThreshold {
-        TimeThreshold::new(time_constants::INTEGRATION_WARN, time_constants::INTEGRATION_CRITICAL)
-    }
-
-    fn default_doctest() -> TimeThreshold {
-        TimeThreshold::new(time_constants::DOCTEST_WARN, time_constants::DOCTEST_CRITICAL)
-    }
-}
-
-#[derive(Debug)]
-pub struct TestOpts {
-    pub list: bool,
-    pub filter: Option<String>,
-    pub filter_exact: bool,
-    pub exclude_should_panic: bool,
-    pub run_ignored: RunIgnored,
-    pub run_tests: bool,
-    pub bench_benchmarks: bool,
-    pub logfile: Option<PathBuf>,
-    pub nocapture: bool,
-    pub color: ColorConfig,
-    pub format: OutputFormat,
-    pub test_threads: Option<usize>,
-    pub skip: Vec<String>,
-    pub time_options: Option<TestTimeOptions>,
-    pub options: Options,
-}
-
-/// Result of parsing the options.
-pub type OptRes = Result<TestOpts, String>;
-/// Result of parsing the option part.
-type OptPartRes<T> = Result<Option<T>, String>;
-
-fn optgroups() -> getopts::Options {
-    let mut opts = getopts::Options::new();
-    opts.optflag("", "include-ignored", "Run ignored and not ignored tests")
-        .optflag("", "ignored", "Run only ignored tests")
-        .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
-        .optflag("", "test", "Run tests and not benchmarks")
-        .optflag("", "bench", "Run benchmarks instead of tests")
-        .optflag("", "list", "List all tests and benchmarks")
-        .optflag("h", "help", "Display this message (longer with --help)")
-        .optopt(
-            "",
-            "logfile",
-            "Write logs to the specified file instead \
-             of stdout",
-            "PATH",
-        )
-        .optflag(
-            "",
-            "nocapture",
-            "don't capture stdout/stderr of each \
-             task, allow printing directly",
-        )
-        .optopt(
-            "",
-            "test-threads",
-            "Number of threads used for running tests \
-             in parallel",
-            "n_threads",
-        )
-        .optmulti(
-            "",
-            "skip",
-            "Skip tests whose names contain FILTER (this flag can \
-             be used multiple times)",
-            "FILTER",
-        )
-        .optflag(
-            "q",
-            "quiet",
-            "Display one character per test instead of one line. \
-             Alias to --format=terse",
-        )
-        .optflag(
-            "",
-            "exact",
-            "Exactly match filters rather than by substring",
-        )
-        .optopt(
-            "",
-            "color",
-            "Configure coloring of output:
-            auto   = colorize if stdout is a tty and tests are run on serially (default);
-            always = always colorize output;
-            never  = never colorize output;",
-            "auto|always|never",
-        )
-        .optopt(
-            "",
-            "format",
-            "Configure formatting of output:
-            pretty = Print verbose output;
-            terse  = Display one character per test;
-            json   = Output a json document",
-            "pretty|terse|json",
-        )
-        .optflag(
-            "",
-            "show-output",
-            "Show captured stdout of successful tests"
-        )
-        .optopt(
-            "Z",
-            "",
-            "Enable nightly-only flags:
-            unstable-options = Allow use of experimental features",
-            "unstable-options",
-        )
-        .optflagopt(
-            "",
-            "report-time",
-            "Show execution time of each test. Awailable values:
-            plain   = do not colorize the execution time (default);
-            colored = colorize output according to the `color` parameter value;
-
-            Threshold values for colorized output can be configured via
-            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
-            `RUST_TEST_TIME_DOCTEST` environment variables.
-
-            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
-
-            Not available for --format=terse",
-            "plain|colored"
-        )
-        .optflag(
-            "",
-            "ensure-time",
-            "Treat excess of the test execution time limit as error.
-
-            Threshold values for this option can be configured via
-            `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
-            `RUST_TEST_TIME_DOCTEST` environment variables.
-
-            Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
-
-            `CRITICAL_TIME` here means the limit that should not be exceeded by test.
-            "
-        );
-    return opts;
-}
-
-fn usage(binary: &str, options: &getopts::Options) {
-    let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
-    println!(
-        r#"{usage}
-
-The FILTER string is tested against the name of all tests, and only those
-tests whose names contain the filter are run.
-
-By default, all tests are run in parallel. This can be altered with the
---test-threads flag or the RUST_TEST_THREADS environment variable when running
-tests (set it to 1).
-
-All tests have their standard output and standard error captured by default.
-This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
-environment variable to a value other than "0". Logging is not captured by default.
-
-Test Attributes:
-
-    `#[test]`        - Indicates a function is a test to be run. This function
-                       takes no arguments.
-    `#[bench]`       - Indicates a function is a benchmark to be run. This
-                       function takes one argument (test::Bencher).
-    `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if
-                        the code causes a panic (an assertion failure or panic!)
-                        A message may be provided, which the failure string must
-                        contain: #[should_panic(expected = "foo")].
-    `#[ignore]`       - When applied to a function which is already attributed as a
-                        test, then the test runner will ignore these tests during
-                        normal test runs. Running with --ignored or --include-ignored will run
-                        these tests."#,
-        usage = options.usage(&message)
-    );
-}
-
-// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
-fn is_nightly() -> bool {
-    // Whether this is a feature-staged build, i.e., on the beta or stable channel
-    let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
-    // Whether we should enable unstable features for bootstrapping
-    let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
-
-    bootstrap || !disable_unstable_features
-}
-
-// Gets the option value and checks if unstable features are enabled.
-macro_rules! unstable_optflag {
-    ($matches:ident, $allow_unstable:ident, $option_name:literal) => {{
-        let opt = $matches.opt_present($option_name);
-        if !$allow_unstable && opt {
-            return Some(Err(format!(
-                "The \"{}\" flag is only accepted on the nightly compiler",
-                $option_name
-            )));
-        }
-
-        opt
-    }};
-}
-
-// Gets the CLI options assotiated with `report-time` feature.
-fn get_time_options(
-    matches: &getopts::Matches,
-    allow_unstable: bool)
--> Option<OptPartRes<TestTimeOptions>> {
-    let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
-    let colored_opt_str = matches.opt_str("report-time");
-    let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
-    let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time");
-
-    // If `ensure-test-time` option is provided, time output is enforced,
-    // so user won't be confused if any of tests will silently fail.
-    let options = if report_time || ensure_test_time {
-        if ensure_test_time && !report_time {
-            report_time_colored = true;
-        }
-        Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored))
-    } else {
-        None
-    };
-
-    Some(Ok(options))
-}
-
-// Parses command line arguments into test options
-pub fn parse_opts(args: &[String]) -> Option<OptRes> {
-    let mut allow_unstable = false;
-    let opts = optgroups();
-    let args = args.get(1..).unwrap_or(args);
-    let matches = match opts.parse(args) {
-        Ok(m) => m,
-        Err(f) => return Some(Err(f.to_string())),
-    };
-
-    if let Some(opt) = matches.opt_str("Z") {
-        if !is_nightly() {
-            return Some(Err(
-                "the option `Z` is only accepted on the nightly compiler".into(),
-            ));
-        }
-
-        match &*opt {
-            "unstable-options" => {
-                allow_unstable = true;
-            }
-            _ => {
-                return Some(Err("Unrecognized option to `Z`".into()));
-            }
-        }
-    };
-
-    if matches.opt_present("h") {
-        usage(&args[0], &opts);
-        return None;
-    }
-
-    let filter = if !matches.free.is_empty() {
-        Some(matches.free[0].clone())
-    } else {
-        None
-    };
-
-    let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic");
-
-    let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored");
-
-    let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
-        (true, true) => {
-            return Some(Err(
-                "the options --include-ignored and --ignored are mutually exclusive".into(),
-            ));
-        }
-        (true, false) => RunIgnored::Yes,
-        (false, true) => RunIgnored::Only,
-        (false, false) => RunIgnored::No,
-    };
-    let quiet = matches.opt_present("quiet");
-    let exact = matches.opt_present("exact");
-    let list = matches.opt_present("list");
-
-    let logfile = matches.opt_str("logfile");
-    let logfile = logfile.map(|s| PathBuf::from(&s));
-
-    let bench_benchmarks = matches.opt_present("bench");
-    let run_tests = !bench_benchmarks || matches.opt_present("test");
-
-    let mut nocapture = matches.opt_present("nocapture");
-    if !nocapture {
-        nocapture = match env::var("RUST_TEST_NOCAPTURE") {
-            Ok(val) => &val != "0",
-            Err(_) => false,
-        };
-    }
-
-    let time_options = match get_time_options(&matches, allow_unstable) {
-        Some(Ok(val)) => val,
-        Some(Err(e)) => return Some(Err(e)),
-        None => panic!("Unexpected output from `get_time_options`"),
-    };
-
-    let test_threads = match matches.opt_str("test-threads") {
-        Some(n_str) => match n_str.parse::<usize>() {
-            Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())),
-            Ok(n) => Some(n),
-            Err(e) => {
-                return Some(Err(format!(
-                    "argument for --test-threads must be a number > 0 \
-                     (error: {})",
-                    e
-                )));
-            }
-        },
-        None => None,
-    };
-
-    let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
-        Some("auto") | None => AutoColor,
-        Some("always") => AlwaysColor,
-        Some("never") => NeverColor,
-
-        Some(v) => {
-            return Some(Err(format!(
-                "argument for --color must be auto, always, or never (was \
-                 {})",
-                v
-            )));
-        }
-    };
-
-    let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
-        None if quiet => OutputFormat::Terse,
-        Some("pretty") | None => OutputFormat::Pretty,
-        Some("terse") => OutputFormat::Terse,
-        Some("json") => {
-            if !allow_unstable {
-                return Some(Err(
-                    "The \"json\" format is only accepted on the nightly compiler".into(),
-                ));
-            }
-            OutputFormat::Json
-        }
-
-        Some(v) => {
-            return Some(Err(format!(
-                "argument for --format must be pretty, terse, or json (was \
-                 {})",
-                v
-            )));
-        }
-    };
-
-    let test_opts = TestOpts {
-        list,
-        filter,
-        filter_exact: exact,
-        exclude_should_panic,
-        run_ignored,
-        run_tests,
-        bench_benchmarks,
-        logfile,
-        nocapture,
-        color,
-        format,
-        test_threads,
-        skip: matches.opt_strs("skip"),
-        time_options,
-        options: Options::new().display_output(matches.opt_present("show-output")),
-    };
-
-    Some(Ok(test_opts))
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct BenchSamples {
-    ns_iter_summ: stats::Summary,
-    mb_s: usize,
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum TestResult {
-    TrOk,
-    TrFailed,
-    TrFailedMsg(String),
-    TrIgnored,
-    TrAllowedFail,
-    TrBench(BenchSamples),
-    TrTimedFail,
-}
-
-unsafe impl Send for TestResult {}
-
-/// The meassured execution time of a unit test.
-#[derive(Clone, PartialEq)]
-pub struct TestExecTime(Duration);
-
-impl fmt::Display for TestExecTime {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:.3}s", self.0.as_secs_f64())
-    }
-}
-
-enum OutputLocation<T> {
-    Pretty(Box<term::StdoutTerminal>),
-    Raw(T),
-}
-
-impl<T: Write> Write for OutputLocation<T> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        match *self {
-            Pretty(ref mut term) => term.write(buf),
-            Raw(ref mut stdout) => stdout.write(buf),
-        }
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        match *self {
-            Pretty(ref mut term) => term.flush(),
-            Raw(ref mut stdout) => stdout.flush(),
-        }
-    }
-}
-
-struct ConsoleTestState {
-    log_out: Option<File>,
-    total: usize,
-    passed: usize,
-    failed: usize,
-    ignored: usize,
-    allowed_fail: usize,
-    filtered_out: usize,
-    measured: usize,
-    metrics: MetricMap,
-    failures: Vec<(TestDesc, Vec<u8>)>,
-    not_failures: Vec<(TestDesc, Vec<u8>)>,
-    time_failures: Vec<(TestDesc, Vec<u8>)>,
-    options: Options,
-}
-
-impl ConsoleTestState {
-    pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
-        let log_out = match opts.logfile {
-            Some(ref path) => Some(File::create(path)?),
-            None => None,
-        };
-
-        Ok(ConsoleTestState {
-            log_out,
-            total: 0,
-            passed: 0,
-            failed: 0,
-            ignored: 0,
-            allowed_fail: 0,
-            filtered_out: 0,
-            measured: 0,
-            metrics: MetricMap::new(),
-            failures: Vec::new(),
-            not_failures: Vec::new(),
-            time_failures: Vec::new(),
-            options: opts.options,
-        })
-    }
-
-    pub fn write_log<F, S>(
-        &mut self,
-        msg: F,
-    ) -> io::Result<()>
-    where
-        S: AsRef<str>,
-        F: FnOnce() -> S,
-    {
-        match self.log_out {
-            None => Ok(()),
-            Some(ref mut o) => {
-                let msg = msg();
-                let msg = msg.as_ref();
-                o.write_all(msg.as_bytes())
-            },
-        }
-    }
-
-    pub fn write_log_result(&mut self,test: &TestDesc,
-        result: &TestResult,
-        exec_time: Option<&TestExecTime>,
-    ) -> io::Result<()> {
-        self.write_log(|| format!(
-            "{} {}",
-            match *result {
-                TrOk => "ok".to_owned(),
-                TrFailed => "failed".to_owned(),
-                TrFailedMsg(ref msg) => format!("failed: {}", msg),
-                TrIgnored => "ignored".to_owned(),
-                TrAllowedFail => "failed (allowed)".to_owned(),
-                TrBench(ref bs) => fmt_bench_samples(bs),
-                TrTimedFail => "failed (time limit exceeded)".to_owned(),
-            },
-            test.name,
-        ))?;
-        if let Some(exec_time) = exec_time {
-            self.write_log(|| format!(" <{}>", exec_time))?;
-        }
-        self.write_log(|| "\n")
-    }
-
-    fn current_test_count(&self) -> usize {
-        self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
-    }
-}
-
-// Format a number with thousands separators
-fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
-    use std::fmt::Write;
-    let mut output = String::new();
-    let mut trailing = false;
-    for &pow in &[9, 6, 3, 0] {
-        let base = 10_usize.pow(pow);
-        if pow == 0 || trailing || n / base != 0 {
-            if !trailing {
-                output.write_fmt(format_args!("{}", n / base)).unwrap();
-            } else {
-                output.write_fmt(format_args!("{:03}", n / base)).unwrap();
-            }
-            if pow != 0 {
-                output.push(sep);
-            }
-            trailing = true;
-        }
-        n %= base;
-    }
-
-    output
-}
-
-pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
-    use std::fmt::Write;
-    let mut output = String::new();
-
-    let median = bs.ns_iter_summ.median as usize;
-    let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
-
-    output
-        .write_fmt(format_args!(
-            "{:>11} ns/iter (+/- {})",
-            fmt_thousands_sep(median, ','),
-            fmt_thousands_sep(deviation, ',')
-        ))
-        .unwrap();
-    if bs.mb_s != 0 {
-        output
-            .write_fmt(format_args!(" = {} MB/s", bs.mb_s))
-            .unwrap();
-    }
-    output
-}
-
-// List the tests to console, and optionally to logfile. Filters are honored.
-pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
-    let mut output = match term::stdout() {
-        None => Raw(io::stdout()),
-        Some(t) => Pretty(t),
-    };
-
-    let quiet = opts.format == OutputFormat::Terse;
-    let mut st = ConsoleTestState::new(opts)?;
-
-    let mut ntest = 0;
-    let mut nbench = 0;
-
-    for test in filter_tests(&opts, tests) {
-        use crate::TestFn::*;
-
-        let TestDescAndFn {
-            desc: TestDesc { name, .. },
-            testfn,
-        } = test;
-
-        let fntype = match testfn {
-            StaticTestFn(..) | DynTestFn(..) => {
-                ntest += 1;
-                "test"
-            }
-            StaticBenchFn(..) | DynBenchFn(..) => {
-                nbench += 1;
-                "benchmark"
-            }
-        };
-
-        writeln!(output, "{}: {}", name, fntype)?;
-        st.write_log(|| format!("{} {}\n", fntype, name))?;
-    }
-
-    fn plural(count: u32, s: &str) -> String {
-        match count {
-            1 => format!("{} {}", 1, s),
-            n => format!("{} {}s", n, s),
-        }
-    }
-
-    if !quiet {
-        if ntest != 0 || nbench != 0 {
-            writeln!(output, "")?;
-        }
-
-        writeln!(
-            output,
-            "{}, {}",
-            plural(ntest, "test"),
-            plural(nbench, "benchmark")
-        )?;
-    }
-
-    Ok(())
-}
-
-// A simple console test runner
-pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
-    fn callback(
-        event: &TestEvent,
-        st: &mut ConsoleTestState,
-        out: &mut dyn OutputFormatter,
-    ) -> io::Result<()> {
-        match (*event).clone() {
-            TeFiltered(ref filtered_tests) => {
-                st.total = filtered_tests.len();
-                out.write_run_start(filtered_tests.len())
-            }
-            TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out),
-            TeWait(ref test) => out.write_test_start(test),
-            TeTimeout(ref test) => out.write_timeout(test),
-            TeResult(test, result, exec_time, stdout) => {
-                st.write_log_result(&test, &result, exec_time.as_ref())?;
-                out.write_result(&test, &result, exec_time.as_ref(), &*stdout, &st)?;
-                match result {
-                    TrOk => {
-                        st.passed += 1;
-                        st.not_failures.push((test, stdout));
-                    }
-                    TrIgnored => st.ignored += 1,
-                    TrAllowedFail => st.allowed_fail += 1,
-                    TrBench(bs) => {
-                        st.metrics.insert_metric(
-                            test.name.as_slice(),
-                            bs.ns_iter_summ.median,
-                            bs.ns_iter_summ.max - bs.ns_iter_summ.min,
-                        );
-                        st.measured += 1
-                    }
-                    TrFailed => {
-                        st.failed += 1;
-                        st.failures.push((test, stdout));
-                    }
-                    TrFailedMsg(msg) => {
-                        st.failed += 1;
-                        let mut stdout = stdout;
-                        stdout.extend_from_slice(format!("note: {}", msg).as_bytes());
-                        st.failures.push((test, stdout));
-                    }
-                    TrTimedFail => {
-                        st.failed += 1;
-                        st.time_failures.push((test, stdout));
-                    }
-                }
-                Ok(())
-            }
-        }
-    }
-
-    let output = match term::stdout() {
-        None => Raw(io::stdout()),
-        Some(t) => Pretty(t),
-    };
-
-    let max_name_len = tests
-        .iter()
-        .max_by_key(|t| len_if_padded(*t))
-        .map(|t| t.desc.name.as_slice().len())
-        .unwrap_or(0);
-
-    let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1;
-
-    let mut out: Box<dyn OutputFormatter> = match opts.format {
-        OutputFormat::Pretty => Box::new(PrettyFormatter::new(
-            output,
-            use_color(opts),
-            max_name_len,
-            is_multithreaded,
-            opts.time_options,
-        )),
-        OutputFormat::Terse => Box::new(TerseFormatter::new(
-            output,
-            use_color(opts),
-            max_name_len,
-            is_multithreaded,
-        )),
-        OutputFormat::Json => Box::new(JsonFormatter::new(output)),
-    };
-    let mut st = ConsoleTestState::new(opts)?;
-    fn len_if_padded(t: &TestDescAndFn) -> usize {
-        match t.testfn.padding() {
-            PadNone => 0,
-            PadOnRight => t.desc.name.as_slice().len(),
-        }
-    }
-
-    run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?;
-
-    assert!(st.current_test_count() == st.total);
-
-    return out.write_run_finish(&st);
-}
-
-fn use_color(opts: &TestOpts) -> bool {
-    match opts.color {
-        AutoColor => !opts.nocapture && stdout_isatty(),
-        AlwaysColor => true,
-        NeverColor => false,
-    }
-}
-
-#[cfg(any(
-    target_os = "cloudabi",
-    all(target_arch = "wasm32", not(target_os = "emscripten")),
-    all(target_vendor = "fortanix", target_env = "sgx")
-))]
-fn stdout_isatty() -> bool {
-    // FIXME: Implement isatty on SGX
-    false
-}
-#[cfg(unix)]
-fn stdout_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
-}
-#[cfg(windows)]
-fn stdout_isatty() -> bool {
-    type DWORD = u32;
-    type BOOL = i32;
-    type HANDLE = *mut u8;
-    type LPDWORD = *mut u32;
-    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
-    extern "system" {
-        fn GetStdHandle(which: DWORD) -> HANDLE;
-        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
-    }
-    unsafe {
-        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
-    }
-}
-
-#[derive(Clone)]
-pub enum TestEvent {
-    TeFiltered(Vec<TestDesc>),
-    TeWait(TestDesc),
-    TeResult(TestDesc, TestResult, Option<TestExecTime>, Vec<u8>),
-    TeTimeout(TestDesc),
-    TeFilteredOut(usize),
-}
-
-pub type MonitorMsg = (TestDesc, TestResult, Option<TestExecTime>, Vec<u8>);
-
-struct Sink(Arc<Mutex<Vec<u8>>>);
-impl Write for Sink {
-    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
-        Write::write(&mut *self.0.lock().unwrap(), data)
-    }
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-#[derive(Clone, Copy)]
-pub enum RunStrategy {
-    /// Runs the test in the current process, and sends the result back over the
-    /// supplied channel.
-    InProcess,
-
-    /// Spawns a subprocess to run the test, and sends the result back over the
-    /// supplied channel. Requires `argv[0]` to exist and point to the binary
-    /// that's currently running.
-    SpawnPrimary,
-}
-
-pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
+pub fn run_tests<F>(
+    opts: &TestOpts,
+    tests: Vec<TestDescAndFn>,
+    mut notify_about_test_event: F
+) -> io::Result<()>
 where
     F: FnMut(TestEvent) -> io::Result<()>,
 {
@@ -1399,11 +233,13 @@ where
     };
 
     let filtered_out = tests_len - filtered_tests.len();
-    callback(TeFilteredOut(filtered_out))?;
+    let event = TestEvent::TeFilteredOut(filtered_out);
+    notify_about_test_event(event)?;
 
     let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect();
 
-    callback(TeFiltered(filtered_descs))?;
+    let event = TestEvent::TeFiltered(filtered_descs);
+    notify_about_test_event(event)?;
 
     let (filtered_tests, filtered_benchs): (Vec<_>, _) =
         filtered_tests.into_iter().partition(|e| match e.testfn {
@@ -1417,7 +253,7 @@ where
     remaining.reverse();
     let mut pending = 0;
 
-    let (tx, rx) = channel::<MonitorMsg>();
+    let (tx, rx) = channel::<CompletedTest>();
     let run_strategy = if opts.options.panic_abort {
         RunStrategy::SpawnPrimary
     } else {
@@ -1458,18 +294,23 @@ where
     if concurrency == 1 {
         while !remaining.is_empty() {
             let test = remaining.pop().unwrap();
-            callback(TeWait(test.desc.clone()))?;
+            let event = TestEvent::TeWait(test.desc.clone());
+            notify_about_test_event(event)?;
             run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No);
-            let (test, result, exec_time, stdout) = rx.recv().unwrap();
-            callback(TeResult(test, result, exec_time, stdout))?;
+            let completed_test = rx.recv().unwrap();
+
+            let event = TestEvent::TeResult(completed_test);
+            notify_about_test_event(event)?;
         }
     } else {
         while pending > 0 || !remaining.is_empty() {
             while pending < concurrency && !remaining.is_empty() {
                 let test = remaining.pop().unwrap();
-                let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
+                let timeout = time::get_default_test_timeout();
                 running_tests.insert(test.desc.clone(), timeout);
-                callback(TeWait(test.desc.clone()))?; //here no pad
+
+                let event = TestEvent::TeWait(test.desc.clone());
+                notify_about_test_event(event)?; //here no pad
                 run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes);
                 pending += 1;
             }
@@ -1479,10 +320,18 @@ where
                 if let Some(timeout) = calc_timeout(&running_tests) {
                     res = rx.recv_timeout(timeout);
                     for test in get_timed_out_tests(&mut running_tests) {
-                        callback(TeTimeout(test))?;
+                        let event = TestEvent::TeTimeout(test);
+                        notify_about_test_event(event)?;
                     }
-                    if res != Err(RecvTimeoutError::Timeout) {
-                        break;
+
+                    match res {
+                        Err(RecvTimeoutError::Timeout) => {
+                            // Result is not yet ready, continue waiting.
+                        }
+                        _ => {
+                            // We've got a result, stop the loop.
+                            break;
+                        }
                     }
                 } else {
                     res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected);
@@ -1490,10 +339,11 @@ where
                 }
             }
 
-            let (desc, result, exec_time, stdout) = res.unwrap();
-            running_tests.remove(&desc);
+            let completed_test = res.unwrap();
+            running_tests.remove(&completed_test.desc);
 
-            callback(TeResult(desc, result, exec_time, stdout))?;
+            let event = TestEvent::TeResult(completed_test);
+            notify_about_test_event(event)?;
             pending -= 1;
         }
     }
@@ -1501,160 +351,16 @@ where
     if opts.bench_benchmarks {
         // All benchmarks run at the end, in serial.
         for b in filtered_benchs {
-            callback(TeWait(b.desc.clone()))?;
+            let event = TestEvent::TeWait(b.desc.clone());
+            notify_about_test_event(event)?;
             run_test(opts, false, b, run_strategy, tx.clone(), Concurrent::No);
-            let (test, result, exec_time, stdout) = rx.recv().unwrap();
-            callback(TeResult(test, result, exec_time, stdout))?;
-        }
-    }
-    Ok(())
-}
-
-#[allow(deprecated)]
-fn get_concurrency() -> usize {
-    return match env::var("RUST_TEST_THREADS") {
-        Ok(s) => {
-            let opt_n: Option<usize> = s.parse().ok();
-            match opt_n {
-                Some(n) if n > 0 => n,
-                _ => panic!(
-                    "RUST_TEST_THREADS is `{}`, should be a positive integer.",
-                    s
-                ),
-            }
-        }
-        Err(..) => num_cpus(),
-    };
-
-    #[cfg(windows)]
-    #[allow(nonstandard_style)]
-    fn num_cpus() -> usize {
-        #[repr(C)]
-        struct SYSTEM_INFO {
-            wProcessorArchitecture: u16,
-            wReserved: u16,
-            dwPageSize: u32,
-            lpMinimumApplicationAddress: *mut u8,
-            lpMaximumApplicationAddress: *mut u8,
-            dwActiveProcessorMask: *mut u8,
-            dwNumberOfProcessors: u32,
-            dwProcessorType: u32,
-            dwAllocationGranularity: u32,
-            wProcessorLevel: u16,
-            wProcessorRevision: u16,
-        }
-        extern "system" {
-            fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
-        }
-        unsafe {
-            let mut sysinfo = std::mem::zeroed();
-            GetSystemInfo(&mut sysinfo);
-            sysinfo.dwNumberOfProcessors as usize
-        }
-    }
-
-    #[cfg(target_os = "vxworks")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on vxWorks
-        1
-    }
-
-    #[cfg(target_os = "redox")]
-    fn num_cpus() -> usize {
-        // FIXME: Implement num_cpus on Redox
-        1
-    }
-
-    #[cfg(any(
-        all(target_arch = "wasm32", not(target_os = "emscripten")),
-        all(target_vendor = "fortanix", target_env = "sgx")
-    ))]
-    fn num_cpus() -> usize {
-        1
-    }
-
-    #[cfg(any(
-        target_os = "android",
-        target_os = "cloudabi",
-        target_os = "emscripten",
-        target_os = "fuchsia",
-        target_os = "ios",
-        target_os = "linux",
-        target_os = "macos",
-        target_os = "solaris",
-    ))]
-    fn num_cpus() -> usize {
-        unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
-    }
-
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "netbsd"
-    ))]
-    fn num_cpus() -> usize {
-        use std::ptr;
-
-        let mut cpus: libc::c_uint = 0;
-        let mut cpus_size = std::mem::size_of_val(&cpus);
-
-        unsafe {
-            cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
-        }
-        if cpus < 1 {
-            let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-            unsafe {
-                libc::sysctl(
-                    mib.as_mut_ptr(),
-                    2,
-                    &mut cpus as *mut _ as *mut _,
-                    &mut cpus_size as *mut _ as *mut _,
-                    ptr::null_mut(),
-                    0,
-                );
-            }
-            if cpus < 1 {
-                cpus = 1;
-            }
-        }
-        cpus as usize
-    }
+            let completed_test = rx.recv().unwrap();
 
-    #[cfg(target_os = "openbsd")]
-    fn num_cpus() -> usize {
-        use std::ptr;
-
-        let mut cpus: libc::c_uint = 0;
-        let mut cpus_size = std::mem::size_of_val(&cpus);
-        let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
-
-        unsafe {
-            libc::sysctl(
-                mib.as_mut_ptr(),
-                2,
-                &mut cpus as *mut _ as *mut _,
-                &mut cpus_size as *mut _ as *mut _,
-                ptr::null_mut(),
-                0,
-            );
-        }
-        if cpus < 1 {
-            cpus = 1;
+            let event = TestEvent::TeResult(completed_test);
+            notify_about_test_event(event)?;
         }
-        cpus as usize
-    }
-
-    #[cfg(target_os = "haiku")]
-    fn num_cpus() -> usize {
-        // FIXME: implement
-        1
-    }
-
-    #[cfg(target_os = "l4re")]
-    fn num_cpus() -> usize {
-        // FIXME: implement
-        1
     }
+    Ok(())
 }
 
 pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
@@ -1730,17 +436,18 @@ pub fn run_test(
     force_ignore: bool,
     test: TestDescAndFn,
     strategy: RunStrategy,
-    monitor_ch: Sender<MonitorMsg>,
+    monitor_ch: Sender<CompletedTest>,
     concurrency: Concurrent,
 ) {
     let TestDescAndFn { desc, testfn } = test;
 
-    let ignore_because_no_process_support = cfg!(target_arch = "wasm32")
-        && !cfg!(target_os = "emscripten")
-        && desc.should_panic != ShouldPanic::No;
+    // FIXME: Re-enable emscripten once it can catch panics again
+    let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No
+        && (cfg!(target_arch = "wasm32") || cfg!(target_os = "emscripten"));
 
     if force_ignore || desc.ignore || ignore_because_no_process_support {
-        monitor_ch.send((desc, TrIgnored, None, Vec::new())).unwrap();
+        let message = CompletedTest::new(desc, TrIgnored, None, Vec::new());
+        monitor_ch.send(message).unwrap();
         return;
     }
 
@@ -1748,12 +455,12 @@ pub fn run_test(
         pub strategy: RunStrategy,
         pub nocapture: bool,
         pub concurrency: Concurrent,
-        pub time: Option<TestTimeOptions>,
+        pub time: Option<time::TestTimeOptions>,
     }
 
     fn run_test_inner(
         desc: TestDesc,
-        monitor_ch: Sender<MonitorMsg>,
+        monitor_ch: Sender<CompletedTest>,
         testfn: Box<dyn FnOnce() + Send>,
         opts: TestRunOpts,
     ) {
@@ -1835,94 +542,21 @@ fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
     f()
 }
 
-fn calc_result<'a>(
-    desc: &TestDesc,
-    task_result: Result<(), &'a (dyn Any + 'static + Send)>,
-    time_opts: &Option<TestTimeOptions>,
-    exec_time: &Option<TestExecTime>
-) -> TestResult {
-    let result = match (&desc.should_panic, task_result) {
-        (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,
-        (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
-            if err
-                .downcast_ref::<String>()
-                .map(|e| &**e)
-                .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
-                .map(|e| e.contains(msg))
-                .unwrap_or(false)
-            {
-                TrOk
-            } else {
-                if desc.allow_fail {
-                    TrAllowedFail
-                } else {
-                    TrFailedMsg(format!("panic did not include expected string '{}'", msg))
-                }
-            }
-        }
-        (&ShouldPanic::Yes, Ok(())) => TrFailedMsg("test did not panic as expected".to_string()),
-        _ if desc.allow_fail => TrAllowedFail,
-        _ => TrFailed,
-    };
-
-    // If test is already failed (or allowed to fail), do not change the result.
-    if result != TrOk {
-        return result;
-    }
-
-    // Check if test is failed due to timeout.
-    if let (Some(opts), Some(time)) = (time_opts, exec_time) {
-        if opts.error_on_excess && opts.is_critical(desc, time) {
-            return TrTimedFail;
-        }
-    }
-
-    result
-}
-
-fn get_result_from_exit_code(
-    desc: &TestDesc,
-    code: i32,
-    time_opts: &Option<TestTimeOptions>,
-    exec_time: &Option<TestExecTime>,
-) -> TestResult {
-    let result = match (desc.allow_fail, code) {
-        (_, TR_OK) => TrOk,
-        (true, TR_FAILED) => TrAllowedFail,
-        (false, TR_FAILED) => TrFailed,
-        (_, _) => TrFailedMsg(format!("got unexpected return code {}", code)),
-    };
-
-    // If test is already failed (or allowed to fail), do not change the result.
-    if result != TrOk {
-        return result;
-    }
-
-    // Check if test is failed due to timeout.
-    if let (Some(opts), Some(time)) = (time_opts, exec_time) {
-        if opts.error_on_excess && opts.is_critical(desc, time) {
-            return TrTimedFail;
-        }
-    }
-
-    result
-}
-
 fn run_test_in_process(
     desc: TestDesc,
     nocapture: bool,
     report_time: bool,
     testfn: Box<dyn FnOnce() + Send>,
-    monitor_ch: Sender<MonitorMsg>,
-    time_opts: Option<TestTimeOptions>,
+    monitor_ch: Sender<CompletedTest>,
+    time_opts: Option<time::TestTimeOptions>,
 ) {
     // Buffer for capturing standard I/O
     let data = Arc::new(Mutex::new(Vec::new()));
 
     let oldio = if !nocapture {
         Some((
-            io::set_print(Some(Box::new(Sink(data.clone())))),
-            io::set_panic(Some(Box::new(Sink(data.clone())))),
+            io::set_print(Some(Sink::new_boxed(&data))),
+            io::set_panic(Some(Sink::new_boxed(&data))),
         ))
     } else {
         None
@@ -1949,14 +583,15 @@ fn run_test_in_process(
         Err(e) => calc_result(&desc, Err(e.as_ref()), &time_opts, &exec_time),
     };
     let stdout = data.lock().unwrap().to_vec();
-    monitor_ch.send((desc.clone(), test_result, exec_time, stdout)).unwrap();
+    let message = CompletedTest::new(desc.clone(), test_result, exec_time, stdout);
+    monitor_ch.send(message).unwrap();
 }
 
 fn spawn_test_subprocess(
     desc: TestDesc,
     report_time: bool,
-    monitor_ch: Sender<MonitorMsg>,
-    time_opts: Option<TestTimeOptions>,
+    monitor_ch: Sender<CompletedTest>,
+    time_opts: Option<time::TestTimeOptions>,
 ) {
     let (result, test_output, exec_time) = (|| {
         let args = env::args().collect::<Vec<_>>();
@@ -2000,7 +635,8 @@ fn spawn_test_subprocess(
         (result, test_output, exec_time)
     })();
 
-    monitor_ch.send((desc.clone(), result, exec_time, test_output)).unwrap();
+    let message = CompletedTest::new(desc.clone(), result, exec_time, test_output);
+    monitor_ch.send(message).unwrap();
 }
 
 fn run_test_in_spawned_subprocess(
@@ -2025,9 +661,9 @@ fn run_test_in_spawned_subprocess(
         }
 
         if let TrOk = test_result {
-            process::exit(TR_OK);
+            process::exit(test_result::TR_OK);
         } else {
-            process::exit(TR_FAILED);
+            process::exit(test_result::TR_FAILED);
         }
     });
     let record_result2 = record_result.clone();
@@ -2036,246 +672,3 @@ fn run_test_in_spawned_subprocess(
     record_result(None);
     unreachable!("panic=abort callback should have exited the process")
 }
-
-#[cfg(not(unix))]
-fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
-    status.code().ok_or("received no exit code from child process".into())
-}
-
-#[cfg(unix)]
-fn get_exit_code(status: ExitStatus) -> Result<i32, String> {
-    use std::os::unix::process::ExitStatusExt;
-    match status.code() {
-        Some(code) => Ok(code),
-        None => match status.signal() {
-            Some(signal) => Err(format!("child process exited with signal {}", signal)),
-            None => Err("child process exited with unknown signal".into()),
-        }
-    }
-}
-
-#[derive(Clone, PartialEq)]
-pub struct MetricMap(BTreeMap<String, Metric>);
-
-impl MetricMap {
-    pub fn new() -> MetricMap {
-        MetricMap(BTreeMap::new())
-    }
-
-    /// Insert a named `value` (+/- `noise`) metric into the map. The value
-    /// must be non-negative. The `noise` indicates the uncertainty of the
-    /// metric, which doubles as the "noise range" of acceptable
-    /// pairwise-regressions on this named value, when comparing from one
-    /// metric to the next using `compare_to_old`.
-    ///
-    /// If `noise` is positive, then it means this metric is of a value
-    /// you want to see grow smaller, so a change larger than `noise` in the
-    /// positive direction represents a regression.
-    ///
-    /// If `noise` is negative, then it means this metric is of a value
-    /// you want to see grow larger, so a change larger than `noise` in the
-    /// negative direction represents a regression.
-    pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) {
-        let m = Metric { value, noise };
-        self.0.insert(name.to_owned(), m);
-    }
-
-    pub fn fmt_metrics(&self) -> String {
-        let v = self
-            .0
-            .iter()
-            .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise))
-            .collect::<Vec<_>>();
-        v.join(", ")
-    }
-}
-
-// Benchmarking
-
-pub use std::hint::black_box;
-
-impl Bencher {
-    /// Callback for benchmark functions to run in their body.
-    pub fn iter<T, F>(&mut self, mut inner: F)
-    where
-        F: FnMut() -> T,
-    {
-        if self.mode == BenchMode::Single {
-            ns_iter_inner(&mut inner, 1);
-            return;
-        }
-
-        self.summary = Some(iter(&mut inner));
-    }
-
-    pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary>
-    where
-        F: FnMut(&mut Bencher),
-    {
-        f(self);
-        return self.summary;
-    }
-}
-
-fn ns_from_dur(dur: Duration) -> u64 {
-    dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64)
-}
-
-fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64
-where
-    F: FnMut() -> T,
-{
-    let start = Instant::now();
-    for _ in 0..k {
-        black_box(inner());
-    }
-    return ns_from_dur(start.elapsed());
-}
-
-pub fn iter<T, F>(inner: &mut F) -> stats::Summary
-where
-    F: FnMut() -> T,
-{
-    // Initial bench run to get ballpark figure.
-    let ns_single = ns_iter_inner(inner, 1);
-
-    // Try to estimate iter count for 1ms falling back to 1m
-    // iterations if first run took < 1ns.
-    let ns_target_total = 1_000_000; // 1ms
-    let mut n = ns_target_total / cmp::max(1, ns_single);
-
-    // if the first run took more than 1ms we don't want to just
-    // be left doing 0 iterations on every loop. The unfortunate
-    // side effect of not being able to do as many runs is
-    // automatically handled by the statistical analysis below
-    // (i.e., larger error bars).
-    n = cmp::max(1, n);
-
-    let mut total_run = Duration::new(0, 0);
-    let samples: &mut [f64] = &mut [0.0_f64; 50];
-    loop {
-        let loop_start = Instant::now();
-
-        for p in &mut *samples {
-            *p = ns_iter_inner(inner, n) as f64 / n as f64;
-        }
-
-        stats::winsorize(samples, 5.0);
-        let summ = stats::Summary::new(samples);
-
-        for p in &mut *samples {
-            let ns = ns_iter_inner(inner, 5 * n);
-            *p = ns as f64 / (5 * n) as f64;
-        }
-
-        stats::winsorize(samples, 5.0);
-        let summ5 = stats::Summary::new(samples);
-
-        let loop_run = loop_start.elapsed();
-
-        // If we've run for 100ms and seem to have converged to a
-        // stable median.
-        if loop_run > Duration::from_millis(100)
-            && summ.median_abs_dev_pct < 1.0
-            && summ.median - summ5.median < summ5.median_abs_dev
-        {
-            return summ5;
-        }
-
-        total_run = total_run + loop_run;
-        // Longest we ever run for is 3s.
-        if total_run > Duration::from_secs(3) {
-            return summ5;
-        }
-
-        // If we overflow here just return the results so far. We check a
-        // multiplier of 10 because we're about to multiply by 2 and the
-        // next iteration of the loop will also multiply by 5 (to calculate
-        // the summ5 result)
-        n = match n.checked_mul(10) {
-            Some(_) => n * 2,
-            None => {
-                return summ5;
-            }
-        };
-    }
-}
-
-pub mod bench {
-    use super::{
-        BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult
-    };
-    use crate::stats;
-    use std::cmp;
-    use std::io;
-    use std::panic::{catch_unwind, AssertUnwindSafe};
-    use std::sync::{Arc, Mutex};
-
-    pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: bool, f: F)
-    where
-        F: FnMut(&mut Bencher),
-    {
-        let mut bs = Bencher {
-            mode: BenchMode::Auto,
-            summary: None,
-            bytes: 0,
-        };
-
-        let data = Arc::new(Mutex::new(Vec::new()));
-        let oldio = if !nocapture {
-            Some((
-                io::set_print(Some(Box::new(Sink(data.clone())))),
-                io::set_panic(Some(Box::new(Sink(data.clone())))),
-            ))
-        } else {
-            None
-        };
-
-        let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f)));
-
-        if let Some((printio, panicio)) = oldio {
-            io::set_print(printio);
-            io::set_panic(panicio);
-        }
-
-        let test_result = match result {
-            //bs.bench(f) {
-            Ok(Some(ns_iter_summ)) => {
-                let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
-                let mb_s = bs.bytes * 1000 / ns_iter;
-
-                let bs = BenchSamples {
-                    ns_iter_summ,
-                    mb_s: mb_s as usize,
-                };
-                TestResult::TrBench(bs)
-            }
-            Ok(None) => {
-                // iter not called, so no data.
-                // FIXME: error in this case?
-                let samples: &mut [f64] = &mut [0.0_f64; 1];
-                let bs = BenchSamples {
-                    ns_iter_summ: stats::Summary::new(samples),
-                    mb_s: 0,
-                };
-                TestResult::TrBench(bs)
-            }
-            Err(_) => TestResult::TrFailed,
-        };
-
-        let stdout = data.lock().unwrap().to_vec();
-        monitor_ch.send((desc, test_result, None, stdout)).unwrap();
-    }
-
-    pub fn run_once<F>(f: F)
-    where
-        F: FnMut(&mut Bencher),
-    {
-        let mut bs = Bencher {
-            mode: BenchMode::Single,
-            summary: None,
-            bytes: 0,
-        };
-        bs.bench(f);
-    }
-}
diff --git a/src/libtest/options.rs b/src/libtest/options.rs
new file mode 100644
index 00000000000..ec87b0fcd46
--- /dev/null
+++ b/src/libtest/options.rs
@@ -0,0 +1,90 @@
+//! Enums denoting options for test execution.
+
+/// Whether to execute tests concurrently or not
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Concurrent {
+    Yes,
+    No,
+}
+
+/// Number of times to run a benchmarked function
+#[derive(Clone, PartialEq, Eq)]
+pub enum BenchMode {
+    Auto,
+    Single,
+}
+
+/// Whether test is expected to panic or not
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum ShouldPanic {
+    No,
+    Yes,
+    YesWithMessage(&'static str),
+}
+
+/// Whether should console output be colored or not
+#[derive(Copy, Clone, Debug)]
+pub enum ColorConfig {
+    AutoColor,
+    AlwaysColor,
+    NeverColor,
+}
+
+/// Format of the test results output
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum OutputFormat {
+    /// Verbose output
+    Pretty,
+    /// Quiet output
+    Terse,
+    /// JSON output
+    Json,
+}
+
+/// Whether ignored test should be runned or not
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum RunIgnored {
+    Yes,
+    No,
+    /// Run only ignored tests
+    Only,
+}
+
+#[derive(Clone, Copy)]
+pub enum RunStrategy {
+    /// Runs the test in the current process, and sends the result back over the
+    /// supplied channel.
+    InProcess,
+
+    /// Spawns a subprocess to run the test, and sends the result back over the
+    /// supplied channel. Requires `argv[0]` to exist and point to the binary
+    /// that's currently running.
+    SpawnPrimary,
+}
+
+/// Options for the test run defined by the caller (instead of CLI arguments).
+/// In case we want to add other options as well, just add them in this struct.
+#[derive(Copy, Clone, Debug)]
+pub struct Options {
+    pub display_output: bool,
+    pub panic_abort: bool,
+}
+
+impl Options {
+    pub fn new() -> Options {
+        Options {
+            display_output: false,
+            panic_abort: false,
+        }
+    }
+
+    pub fn display_output(mut self, display_output: bool) -> Options {
+        self.display_output = display_output;
+        self
+    }
+
+    pub fn panic_abort(mut self, panic_abort: bool) -> Options {
+        self.panic_abort = panic_abort;
+        self
+    }
+}
diff --git a/src/libtest/stats/tests.rs b/src/libtest/stats/tests.rs
index 7d1d635186f..eaf41bc9e22 100644
--- a/src/libtest/stats/tests.rs
+++ b/src/libtest/stats/tests.rs
@@ -4,7 +4,7 @@ extern crate test;
 use std::f64;
 use std::io::prelude::*;
 use std::io;
-use self::test::Bencher;
+use self::test::test::Bencher;
 
 // Test vectors generated from R, using the script src/etc/stat-test-vectors.r.
 
diff --git a/src/libtest/test_result.rs b/src/libtest/test_result.rs
new file mode 100644
index 00000000000..80ca9dea18f
--- /dev/null
+++ b/src/libtest/test_result.rs
@@ -0,0 +1,107 @@
+use std::any::Any;
+
+use super::bench::BenchSamples;
+use super::time;
+use super::types::TestDesc;
+use super::options::ShouldPanic;
+
+pub use self::TestResult::*;
+
+// Return codes for secondary process.
+// Start somewhere other than 0 so we know the return code means what we think
+// it means.
+pub const TR_OK: i32 = 50;
+pub const TR_FAILED: i32 = 51;
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum TestResult {
+    TrOk,
+    TrFailed,
+    TrFailedMsg(String),
+    TrIgnored,
+    TrAllowedFail,
+    TrBench(BenchSamples),
+    TrTimedFail,
+}
+
+unsafe impl Send for TestResult {}
+
+/// Creates a `TestResult` depending on the raw result of test execution
+/// and assotiated data.
+pub fn calc_result<'a>(
+    desc: &TestDesc,
+    task_result: Result<(), &'a (dyn Any + 'static + Send)>,
+    time_opts: &Option<time::TestTimeOptions>,
+    exec_time: &Option<time::TestExecTime>
+) -> TestResult {
+    let result = match (&desc.should_panic, task_result) {
+        (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk,
+        (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => {
+            if err
+                .downcast_ref::<String>()
+                .map(|e| &**e)
+                .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e))
+                .map(|e| e.contains(msg))
+                .unwrap_or(false)
+            {
+                TestResult::TrOk
+            } else {
+                if desc.allow_fail {
+                    TestResult::TrAllowedFail
+                } else {
+                    TestResult::TrFailedMsg(
+                        format!("panic did not include expected string '{}'", msg)
+                    )
+                }
+            }
+        }
+        (&ShouldPanic::Yes, Ok(())) => {
+            TestResult::TrFailedMsg("test did not panic as expected".to_string())
+        }
+        _ if desc.allow_fail => TestResult::TrAllowedFail,
+        _ => TestResult::TrFailed,
+    };
+
+    // If test is already failed (or allowed to fail), do not change the result.
+    if result != TestResult::TrOk {
+        return result;
+    }
+
+    // Check if test is failed due to timeout.
+    if let (Some(opts), Some(time)) = (time_opts, exec_time) {
+        if opts.error_on_excess && opts.is_critical(desc, time) {
+            return TestResult::TrTimedFail;
+        }
+    }
+
+    result
+}
+
+/// Creates a `TestResult` depending on the exit code of test subprocess.
+pub fn get_result_from_exit_code(
+    desc: &TestDesc,
+    code: i32,
+    time_opts: &Option<time::TestTimeOptions>,
+    exec_time: &Option<time::TestExecTime>,
+) -> TestResult {
+    let result = match (desc.allow_fail, code) {
+        (_, TR_OK) => TestResult::TrOk,
+        (true, TR_FAILED) => TestResult::TrAllowedFail,
+        (false, TR_FAILED) => TestResult::TrFailed,
+        (_, _) => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+    };
+
+    // If test is already failed (or allowed to fail), do not change the result.
+    if result != TestResult::TrOk {
+        return result;
+    }
+
+    // Check if test is failed due to timeout.
+    if let (Some(opts), Some(time)) = (time_opts, exec_time) {
+        if opts.error_on_excess && opts.is_critical(desc, time) {
+            return TestResult::TrTimedFail;
+        }
+    }
+
+    result
+}
diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs
index 880d02a28ff..9de774555e9 100644
--- a/src/libtest/tests.rs
+++ b/src/libtest/tests.rs
@@ -1,9 +1,19 @@
 use super::*;
 
-use crate::test::{
-    filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, RunStrategy,
-    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions,
-    TestType, TrFailedMsg, TrIgnored, TrOk,
+use crate::{
+    bench::Bencher,
+    console::OutputLocation,
+    options::OutputFormat,
+    time::{TimeThreshold, TestTimeOptions},
+    formatters::PrettyFormatter,
+    test::{
+        filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap,
+        RunIgnored, RunStrategy, ShouldPanic, StaticTestName, TestDesc,
+        TestDescAndFn, TestOpts, TrIgnored, TrOk,
+        // FIXME (introduced by #65251)
+        // ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TestTimeOptions,
+        // TestType, TrFailedMsg, TrIgnored, TrOk,
+    },
 };
 use std::sync::mpsc::channel;
 use std::time::Duration;
@@ -72,8 +82,8 @@ pub fn do_not_run_ignored_tests() {
     };
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res != TrOk);
+    let result = rx.recv().unwrap().result;
+    assert!(result != TrOk);
 }
 
 #[test]
@@ -91,11 +101,13 @@ pub fn ignored_tests_result_in_ignored() {
     };
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res == TrIgnored);
+    let result = rx.recv().unwrap().result;
+    assert!(result == TrIgnored);
 }
 
+// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
 #[test]
+#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic() {
     fn f() {
         panic!();
@@ -112,11 +124,13 @@ fn test_should_panic() {
     };
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res == TrOk);
+    let result = rx.recv().unwrap().result;
+    assert!(result == TrOk);
 }
 
+// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
 #[test]
+#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_good_message() {
     fn f() {
         panic!("an error message");
@@ -133,12 +147,15 @@ fn test_should_panic_good_message() {
     };
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res == TrOk);
+    let result = rx.recv().unwrap().result;
+    assert!(result == TrOk);
 }
 
+// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
 #[test]
+#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_bad_message() {
+    use crate::tests::TrFailedMsg;
     fn f() {
         panic!("an error message");
     }
@@ -156,11 +173,13 @@ fn test_should_panic_bad_message() {
     };
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
+    let result = rx.recv().unwrap().result;
+    assert!(result == TrFailedMsg(format!("{} '{}'", failed_msg, expected)));
 }
 
+// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
 #[test]
+#[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_but_succeeds() {
     fn f() {}
     let desc = TestDescAndFn {
@@ -175,8 +194,8 @@ fn test_should_panic_but_succeeds() {
     };
     let (tx, rx) = channel();
     run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, res, _, _) = rx.recv().unwrap();
-    assert!(res == TrFailedMsg("test did not panic as expected".to_string()));
+    let result = rx.recv().unwrap().result;
+    assert!(result == TrFailedMsg("test did not panic as expected".to_string()));
 }
 
 fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
@@ -203,7 +222,7 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
     };
     let (tx, rx) = channel();
     run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, _, exec_time, _) = rx.recv().unwrap();
+    let exec_time = rx.recv().unwrap().exec_time;
     exec_time
 }
 
@@ -241,7 +260,7 @@ fn time_test_failure_template(test_type: TestType) -> TestResult {
     };
     let (tx, rx) = channel();
     run_test(&test_opts, false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let (_, result, _, _) = rx.recv().unwrap();
+    let result = rx.recv().unwrap().result;
 
     result
 }
@@ -647,9 +666,9 @@ fn should_sort_failures_before_printing_them() {
         test_type: TestType::Unknown,
     };
 
-    let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false, None);
+    let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None);
 
-    let st = ConsoleTestState {
+    let st = console::ConsoleTestState {
         log_out: None,
         total: 0,
         passed: 0,
@@ -667,8 +686,8 @@ fn should_sort_failures_before_printing_them() {
 
     out.write_failures(&st).unwrap();
     let s = match out.output_location() {
-        &Raw(ref m) => String::from_utf8_lossy(&m[..]),
-        &Pretty(_) => unreachable!(),
+        &OutputLocation::Raw(ref m) => String::from_utf8_lossy(&m[..]),
+        &OutputLocation::Pretty(_) => unreachable!(),
     };
 
     let apos = s.find("a").unwrap();
diff --git a/src/libtest/time.rs b/src/libtest/time.rs
new file mode 100644
index 00000000000..f4d4b17b620
--- /dev/null
+++ b/src/libtest/time.rs
@@ -0,0 +1,206 @@
+//! Module `time` contains everything related to the time measurement of unit tests
+//! execution.
+//! Two main purposes of this module:
+//! - Check whether test is timed out.
+//! - Provide helpers for `report-time` and `measure-time` options.
+
+use std::time::{Duration, Instant};
+use std::str::FromStr;
+use std::fmt;
+use std::env;
+
+use super::types::{TestDesc, TestType};
+
+pub const TEST_WARN_TIMEOUT_S: u64 = 60;
+
+/// This small module contains constants used by `report-time` option.
+/// Those constants values will be used if corresponding environment variables are not set.
+///
+/// To override values for unit-tests, use a constant `RUST_TEST_TIME_UNIT`,
+/// To override values for integration tests, use a constant `RUST_TEST_TIME_INTEGRATION`,
+/// To override values for doctests, use a constant `RUST_TEST_TIME_DOCTEST`.
+///
+/// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means
+/// warn time, and 200 means critical time.
+pub mod time_constants {
+    use std::time::Duration;
+    use super::TEST_WARN_TIMEOUT_S;
+
+    /// Environment variable for overriding default threshold for unit-tests.
+    pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT";
+
+    // Unit tests are supposed to be really quick.
+    pub const UNIT_WARN: Duration = Duration::from_millis(50);
+    pub const UNIT_CRITICAL: Duration = Duration::from_millis(100);
+
+    /// Environment variable for overriding default threshold for unit-tests.
+    pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION";
+
+    // Integration tests may have a lot of work, so they can take longer to execute.
+    pub const INTEGRATION_WARN: Duration = Duration::from_millis(500);
+    pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000);
+
+    /// Environment variable for overriding default threshold for unit-tests.
+    pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST";
+
+    // Doctests are similar to integration tests, because they can include a lot of
+    // initialization code.
+    pub const DOCTEST_WARN: Duration = INTEGRATION_WARN;
+    pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL;
+
+    // Do not suppose anything about unknown tests, base limits on the
+    // `TEST_WARN_TIMEOUT_S` constant.
+    pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S);
+    pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2);
+}
+
+/// Returns an `Instance` object denoting when the test should be considered
+/// timed out.
+pub fn get_default_test_timeout() -> Instant {
+    Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S)
+}
+
+/// The meassured execution time of a unit test.
+#[derive(Debug, Clone, PartialEq)]
+pub struct TestExecTime(pub Duration);
+
+impl fmt::Display for TestExecTime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:.3}s", self.0.as_secs_f64())
+    }
+}
+
+/// Structure denoting time limits for test execution.
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub struct TimeThreshold {
+    pub warn: Duration,
+    pub critical: Duration,
+}
+
+impl TimeThreshold {
+    /// Creates a new `TimeThreshold` instance with provided durations.
+    pub fn new(warn: Duration, critical: Duration) -> Self {
+        Self {
+            warn,
+            critical,
+        }
+    }
+
+    /// Attempts to create a `TimeThreshold` instance with values obtained
+    /// from the environment variable, and returns `None` if the variable
+    /// is not set.
+    /// Environment variable format is expected to match `\d+,\d+`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if variable with provided name is set but contains inappropriate
+    /// value.
+    pub fn from_env_var(env_var_name: &str) -> Option<Self> {
+        let durations_str = env::var(env_var_name).ok()?;
+
+        // Split string into 2 substrings by comma and try to parse numbers.
+        let mut durations = durations_str
+            .splitn(2, ',')
+            .map(|v| {
+                u64::from_str(v).unwrap_or_else(|_| {
+                    panic!(
+                        "Duration value in variable {} is expected to be a number, but got {}",
+                        env_var_name, v
+                    )
+                })
+            });
+
+        // Callback to be called if the environment variable has unexpected structure.
+        let panic_on_incorrect_value = || {
+            panic!(
+                "Duration variable {} expected to have 2 numbers separated by comma, but got {}",
+                env_var_name, durations_str
+            );
+        };
+
+        let (warn, critical) = (
+            durations.next().unwrap_or_else(panic_on_incorrect_value),
+            durations.next().unwrap_or_else(panic_on_incorrect_value)
+        );
+
+        if warn > critical {
+            panic!("Test execution warn time should be less or equal to the critical time");
+        }
+
+        Some(Self::new(Duration::from_millis(warn), Duration::from_millis(critical)))
+    }
+}
+
+/// Structure with parameters for calculating test execution time.
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub struct TestTimeOptions {
+    /// Denotes if the test critical execution time limit excess should be considered
+    /// a test failure.
+    pub error_on_excess: bool,
+    pub colored: bool,
+    pub unit_threshold: TimeThreshold,
+    pub integration_threshold: TimeThreshold,
+    pub doctest_threshold: TimeThreshold,
+}
+
+impl TestTimeOptions {
+    pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self {
+        let unit_threshold =
+            TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME)
+                .unwrap_or_else(Self::default_unit);
+
+        let integration_threshold =
+            TimeThreshold::from_env_var(time_constants::INTEGRATION_ENV_NAME)
+                .unwrap_or_else(Self::default_integration);
+
+        let doctest_threshold =
+            TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME)
+                .unwrap_or_else(Self::default_doctest);
+
+        Self {
+            error_on_excess,
+            colored,
+            unit_threshold,
+            integration_threshold,
+            doctest_threshold,
+        }
+    }
+
+    pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool {
+        exec_time.0 >= self.warn_time(test)
+    }
+
+    pub fn is_critical(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool {
+        exec_time.0 >= self.critical_time(test)
+    }
+
+    fn warn_time(&self, test: &TestDesc) -> Duration {
+        match test.test_type {
+            TestType::UnitTest => self.unit_threshold.warn,
+            TestType::IntegrationTest => self.integration_threshold.warn,
+            TestType::DocTest => self.doctest_threshold.warn,
+            TestType::Unknown => time_constants::UNKNOWN_WARN,
+        }
+    }
+
+    fn critical_time(&self, test: &TestDesc) -> Duration {
+        match test.test_type {
+            TestType::UnitTest => self.unit_threshold.critical,
+            TestType::IntegrationTest => self.integration_threshold.critical,
+            TestType::DocTest => self.doctest_threshold.critical,
+            TestType::Unknown => time_constants::UNKNOWN_CRITICAL,
+        }
+    }
+
+    fn default_unit() -> TimeThreshold {
+        TimeThreshold::new(time_constants::UNIT_WARN, time_constants::UNIT_CRITICAL)
+    }
+
+    fn default_integration() -> TimeThreshold {
+        TimeThreshold::new(time_constants::INTEGRATION_WARN, time_constants::INTEGRATION_CRITICAL)
+    }
+
+    fn default_doctest() -> TimeThreshold {
+        TimeThreshold::new(time_constants::DOCTEST_WARN, time_constants::DOCTEST_CRITICAL)
+    }
+}
diff --git a/src/libtest/types.rs b/src/libtest/types.rs
new file mode 100644
index 00000000000..89bcf2cf285
--- /dev/null
+++ b/src/libtest/types.rs
@@ -0,0 +1,145 @@
+//! Common types used by `libtest`.
+
+use std::fmt;
+use std::borrow::Cow;
+
+use super::options;
+use super::bench::Bencher;
+
+pub use NamePadding::*;
+pub use TestName::*;
+pub use TestFn::*;
+
+/// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html)
+/// conventions.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub enum TestType {
+    /// Unit-tests are expected to be in the `src` folder of the crate.
+    UnitTest,
+    /// Integration-style tests are expected to be in the `tests` folder of the crate.
+    IntegrationTest,
+    /// Doctests are created by the `librustdoc` manually, so it's a different type of test.
+    DocTest,
+    /// Tests for the sources that don't follow the project layout convention
+    /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly).
+    Unknown,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub enum NamePadding {
+    PadNone,
+    PadOnRight,
+}
+
+// The name of a test. By convention this follows the rules for rust
+// paths; i.e., it should be a series of identifiers separated by double
+// colons. This way if some test runner wants to arrange the tests
+// hierarchically it may.
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum TestName {
+    StaticTestName(&'static str),
+    DynTestName(String),
+    AlignedTestName(Cow<'static, str>, NamePadding),
+}
+
+impl TestName {
+    pub fn as_slice(&self) -> &str {
+        match *self {
+            StaticTestName(s) => s,
+            DynTestName(ref s) => s,
+            AlignedTestName(ref s, _) => &*s,
+        }
+    }
+
+    pub fn padding(&self) -> NamePadding {
+        match self {
+            &AlignedTestName(_, p) => p,
+            _ => PadNone,
+        }
+    }
+
+    pub fn with_padding(&self, padding: NamePadding) -> TestName {
+        let name = match self {
+            &TestName::StaticTestName(name) => Cow::Borrowed(name),
+            &TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
+            &TestName::AlignedTestName(ref name, _) => name.clone(),
+        };
+
+        TestName::AlignedTestName(name, padding)
+    }
+}
+impl fmt::Display for TestName {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self.as_slice(), f)
+    }
+}
+
+/// Represents a benchmark function.
+pub trait TDynBenchFn: Send {
+    fn run(&self, harness: &mut Bencher);
+}
+
+// A function that runs a test. If the function returns successfully,
+// the test succeeds; if the function panics then the test fails. We
+// may need to come up with a more clever definition of test in order
+// to support isolation of tests into threads.
+pub enum TestFn {
+    StaticTestFn(fn()),
+    StaticBenchFn(fn(&mut Bencher)),
+    DynTestFn(Box<dyn FnOnce() + Send>),
+    DynBenchFn(Box<dyn TDynBenchFn + 'static>),
+}
+
+impl TestFn {
+    pub fn padding(&self) -> NamePadding {
+        match *self {
+            StaticTestFn(..) => PadNone,
+            StaticBenchFn(..) => PadOnRight,
+            DynTestFn(..) => PadNone,
+            DynBenchFn(..) => PadOnRight,
+        }
+    }
+}
+
+impl fmt::Debug for TestFn {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match *self {
+            StaticTestFn(..) => "StaticTestFn(..)",
+            StaticBenchFn(..) => "StaticBenchFn(..)",
+            DynTestFn(..) => "DynTestFn(..)",
+            DynBenchFn(..) => "DynBenchFn(..)",
+        })
+    }
+}
+
+// The definition of a single test. A test runner will run a list of
+// these.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct TestDesc {
+    pub name: TestName,
+    pub ignore: bool,
+    pub should_panic: options::ShouldPanic,
+    pub allow_fail: bool,
+    pub test_type: TestType,
+}
+
+impl TestDesc {
+    pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
+        let mut name = String::from(self.name.as_slice());
+        let fill = column_count.saturating_sub(name.len());
+        let pad = " ".repeat(fill);
+        match align {
+            PadNone => name,
+            PadOnRight => {
+                name.push_str(&pad);
+                name
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct TestDescAndFn {
+    pub desc: TestDesc,
+    pub testfn: TestFn,
+}
diff --git a/src/llvm-emscripten b/src/llvm-emscripten
deleted file mode 160000
-Subproject 7f23313edff8beccb3fe44b815714269c5124c1
diff --git a/src/test/codegen/c-variadic.rs b/src/test/codegen/c-variadic.rs
index 2acf95de97e..7fa61d15f77 100644
--- a/src/test/codegen/c-variadic.rs
+++ b/src/test/codegen/c-variadic.rs
@@ -1,3 +1,4 @@
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C no-prepopulate-passes
 // ignore-tidy-linelength
 
diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs
index 307c4e2c1e2..49e40d5f243 100644
--- a/src/test/codegen/drop.rs
+++ b/src/test/codegen/drop.rs
@@ -1,3 +1,4 @@
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/external-no-mangle-statics.rs b/src/test/codegen/external-no-mangle-statics.rs
index e44373926b7..ee61814678c 100644
--- a/src/test/codegen/external-no-mangle-statics.rs
+++ b/src/test/codegen/external-no-mangle-statics.rs
@@ -1,3 +1,4 @@
+// ignore-emscripten default visibility is hidden
 // compile-flags: -O
 // `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
 // definitions
diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs
index 86c1365fdb7..88b8692b0ac 100644
--- a/src/test/codegen/link_section.rs
+++ b/src/test/codegen/link_section.rs
@@ -1,3 +1,4 @@
+// ignore-emscripten default visibility is hidden
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/no-output-asm-is-volatile.rs b/src/test/codegen/no-output-asm-is-volatile.rs
index ad497b25a9e..47b38d29417 100644
--- a/src/test/codegen/no-output-asm-is-volatile.rs
+++ b/src/test/codegen/no-output-asm-is-volatile.rs
@@ -1,7 +1,5 @@
 // compile-flags: -O
 
-// ignore-asmjs
-
 #![feature(asm)]
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs
index 05888c0e733..c82ae476b1b 100644
--- a/src/test/codegen/personality_lifetimes.rs
+++ b/src/test/codegen/personality_lifetimes.rs
@@ -1,4 +1,5 @@
 // ignore-msvc
+// ignore-emscripten compiled with panic=abort by default
 
 // compile-flags: -O -C no-prepopulate-passes
 
diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs
index 5521c3c849f..afefb9c9f71 100644
--- a/src/test/codegen/repr-transparent-aggregates-2.rs
+++ b/src/test/codegen/repr-transparent-aggregates-2.rs
@@ -1,7 +1,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 // ignore-aarch64
-// ignore-asmjs
+// ignore-emscripten
 // ignore-mips64
 // ignore-powerpc
 // ignore-powerpc64
@@ -9,7 +9,6 @@
 // ignore-s390x
 // ignore-sparc
 // ignore-sparc64
-// ignore-wasm
 // ignore-x86
 // ignore-x86_64
 // See repr-transparent.rs
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs
index acb993d51fb..0a687078cd8 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-abs.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs
index 58667af7e50..9d47339d163 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-ceil.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs
index affbe17d334..770b2a73037 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-cos.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs
index 43472d9dece..33c86050666 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs
index 471d49b7841..f7a8986242d 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-exp2.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs
index bd8ba8b6cd7..a4070317a62 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-floor.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs
index 8ad9e9004c2..0800a498cb7 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fma.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
index ecffca960da..adc44ffd811 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-fsqrt.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log.rs
index 79e6ed54690..9c236f19636 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs
index db92a94fca8..a922161affa 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log10.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs
index 90d9ec3cedd..9624acb383f 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-log2.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs
index 2761392e6a9..7b9b1aec6c8 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-minmax.rs
@@ -1,4 +1,3 @@
-// ignore-emscripten
 // min-llvm-version 7.0
 
 // compile-flags: -C no-prepopulate-passes
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs
index 1dd2c2ccb83..6639e5d652b 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-pow.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs
index 09f31bdd6bb..5e82ea023d8 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-powi.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs
index dc87651c2aa..8ca2ca86076 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-float-sin.rs
@@ -1,5 +1,3 @@
-// ignore-emscripten
-
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
index adee796d247..237d15a5c68 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-arithmetic-saturating.rs
@@ -119,140 +119,140 @@ extern "platform-intrinsic" {
 // CHECK-LABEL: @sadd_i8x2
 #[no_mangle]
 pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x4
 #[no_mangle]
 pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x8
 #[no_mangle]
 pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x16
 #[no_mangle]
 pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x32
 #[no_mangle]
 pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i8x64
 #[no_mangle]
 pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x2
 #[no_mangle]
 pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x4
 #[no_mangle]
 pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x8
 #[no_mangle]
 pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x16
 #[no_mangle]
 pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i16x32
 #[no_mangle]
 pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x2
 #[no_mangle]
 pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x4
 #[no_mangle]
 pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x8
 #[no_mangle]
 pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i32x16
 #[no_mangle]
 pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i64x2
 #[no_mangle]
 pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i64x4
 #[no_mangle]
 pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i64x8
 #[no_mangle]
 pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i128x2
 #[no_mangle]
 pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @sadd_i128x4
 #[no_mangle]
 pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
@@ -261,140 +261,140 @@ pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
 // CHECK-LABEL: @uadd_u8x2
 #[no_mangle]
 pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x4
 #[no_mangle]
 pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x8
 #[no_mangle]
 pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x16
 #[no_mangle]
 pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x32
 #[no_mangle]
 pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u8x64
 #[no_mangle]
 pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x2
 #[no_mangle]
 pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x4
 #[no_mangle]
 pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x8
 #[no_mangle]
 pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x16
 #[no_mangle]
 pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u16x32
 #[no_mangle]
 pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x2
 #[no_mangle]
 pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x4
 #[no_mangle]
 pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x8
 #[no_mangle]
 pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u32x16
 #[no_mangle]
 pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u64x2
 #[no_mangle]
 pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u64x4
 #[no_mangle]
 pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u64x8
 #[no_mangle]
 pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u128x2
 #[no_mangle]
 pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
 // CHECK-LABEL: @uadd_u128x4
 #[no_mangle]
 pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
     simd_saturating_add(x, y)
 }
 
@@ -405,140 +405,140 @@ pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
 // CHECK-LABEL: @ssub_i8x2
 #[no_mangle]
 pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x4
 #[no_mangle]
 pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x8
 #[no_mangle]
 pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x16
 #[no_mangle]
 pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x32
 #[no_mangle]
 pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i8x64
 #[no_mangle]
 pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x2
 #[no_mangle]
 pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x4
 #[no_mangle]
 pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x8
 #[no_mangle]
 pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x16
 #[no_mangle]
 pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i16x32
 #[no_mangle]
 pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x2
 #[no_mangle]
 pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x4
 #[no_mangle]
 pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x8
 #[no_mangle]
 pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i32x16
 #[no_mangle]
 pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i64x2
 #[no_mangle]
 pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i64x4
 #[no_mangle]
 pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i64x8
 #[no_mangle]
 pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i128x2
 #[no_mangle]
 pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @ssub_i128x4
 #[no_mangle]
 pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
@@ -547,139 +547,139 @@ pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
 // CHECK-LABEL: @usub_u8x2
 #[no_mangle]
 pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{[0-9]+}}, <2 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x4
 #[no_mangle]
 pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{[0-9]+}}, <4 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x8
 #[no_mangle]
 pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{[0-9]+}}, <8 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x16
 #[no_mangle]
 pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{[0-9]+}}, <16 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x32
 #[no_mangle]
 pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{[0-9]+}}, <32 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u8x64
 #[no_mangle]
 pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 {
-    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{[0-9]+}}, <64 x i8> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x2
 #[no_mangle]
 pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{[0-9]+}}, <2 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x4
 #[no_mangle]
 pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{[0-9]+}}, <4 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x8
 #[no_mangle]
 pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{[0-9]+}}, <8 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x16
 #[no_mangle]
 pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{[0-9]+}}, <16 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u16x32
 #[no_mangle]
 pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 {
-    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{[0-9]+}}, <32 x i16> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x2
 #[no_mangle]
 pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{[0-9]+}}, <2 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x4
 #[no_mangle]
 pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{[0-9]+}}, <4 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x8
 #[no_mangle]
 pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{[0-9]+}}, <8 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u32x16
 #[no_mangle]
 pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 {
-    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{[0-9]+}}, <16 x i32> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u64x2
 #[no_mangle]
 pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u64x4
 #[no_mangle]
 pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{[0-9]+}}, <4 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u64x8
 #[no_mangle]
 pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 {
-    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{[0-9]+}}, <8 x i64> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u128x2
 #[no_mangle]
 pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 {
-    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{[0-9]+}}, <2 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
 
 // CHECK-LABEL: @usub_u128x4
 #[no_mangle]
 pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 {
-    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{[0-9]+}}, <4 x i128> %{{[0-9]+}})
+    // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
     simd_saturating_sub(x, y)
 }
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
index cd8130f9231..54366401486 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-bitmask.rs
@@ -29,7 +29,7 @@ extern "platform-intrinsic" {
 // CHECK-LABEL: @bitmask_int
 #[no_mangle]
 pub unsafe fn bitmask_int(x: i32x2) -> u8 {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9]+}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
     // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@@ -39,7 +39,7 @@ pub unsafe fn bitmask_int(x: i32x2) -> u8 {
 // CHECK-LABEL: @bitmask_uint
 #[no_mangle]
 pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9]+}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
     // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
@@ -49,7 +49,7 @@ pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
 // CHECK-LABEL: @bitmask_int16
 #[no_mangle]
 pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
-    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9a-z]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
     // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
     // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
     // CHECK-NOT: zext
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
index 3389104219d..3b1f4398f90 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -1,4 +1,3 @@
-// ignore-emscripten
 // ignore-tidy-linelength
 
 // compile-flags: -C no-prepopulate-passes
diff --git a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
index dd0a9801bc5..9fce849e523 100644
--- a/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
+++ b/src/test/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -1,4 +1,3 @@
-// ignore-emscripten
 // ignore-tidy-linelength
 
 // compile-flags: -C no-prepopulate-passes
diff --git a/src/test/codegen/union-abi.rs b/src/test/codegen/union-abi.rs
index 7339df17b05..98a9ff9cbe4 100644
--- a/src/test/codegen/union-abi.rs
+++ b/src/test/codegen/union-abi.rs
@@ -1,3 +1,4 @@
+// ignore-emscripten vectors passed directly
 // compile-flags: -C no-prepopulate-passes
 
 // This test that using union forward the abi of the inner type, as
diff --git a/src/test/codegen/unwind-extern-exports.rs b/src/test/codegen/unwind-extern-exports.rs
index ddb3a4f6b4d..d924a3b75dd 100644
--- a/src/test/codegen/unwind-extern-exports.rs
+++ b/src/test/codegen/unwind-extern-exports.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C opt-level=0
+// ignore-emscripten compiled with panic=abort by default
 
 #![crate_type = "lib"]
 #![feature(unwind_attributes)]
diff --git a/src/test/codegen/unwind-extern-imports.rs b/src/test/codegen/unwind-extern-imports.rs
index 485e8bbcd42..d88a4987756 100644
--- a/src/test/codegen/unwind-extern-imports.rs
+++ b/src/test/codegen/unwind-extern-imports.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C no-prepopulate-passes
+// ignore-emscripten compiled with panic=abort by default
 
 #![crate_type = "lib"]
 #![feature(unwind_attributes)]
diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs
index fc10824f0c0..add4eef13c7 100644
--- a/src/test/compile-fail/consts/const-err3.rs
+++ b/src/test/compile-fail/consts/const-err3.rs
@@ -14,6 +14,7 @@ fn main() {
     //~^ ERROR const_err
     let _e = [5u8][1];
     //~^ ERROR const_err
+    //~| ERROR this expression will panic at runtime
     black_box(b);
     black_box(c);
     black_box(d);
diff --git a/src/test/compile-fail/weak-lang-item.rs b/src/test/compile-fail/weak-lang-item.rs
index 768b936dc27..3fa3822831b 100644
--- a/src/test/compile-fail/weak-lang-item.rs
+++ b/src/test/compile-fail/weak-lang-item.rs
@@ -1,7 +1,7 @@
 // aux-build:weak-lang-items.rs
 // error-pattern: `#[panic_handler]` function required, but not found
 // error-pattern: language item required, but not found: `eh_personality`
-// ignore-wasm32-bare compiled with panic=abort, personality not required
+// ignore-emscripten compiled with panic=abort, personality not required
 
 #![no_std]
 
diff --git a/src/test/incremental/change_crate_dep_kind.rs b/src/test/incremental/change_crate_dep_kind.rs
index f5d1acb621b..2bcb06d6eb8 100644
--- a/src/test/incremental/change_crate_dep_kind.rs
+++ b/src/test/incremental/change_crate_dep_kind.rs
@@ -1,6 +1,7 @@
 // Test that we detect changes to the `dep_kind` query. If the change is not
 // detected then -Zincremental-verify-ich will trigger an assertion.
 
+// ignore-emscripten compiled with panic=abort by default
 // revisions:cfail1 cfail2
 // compile-flags: -Z query-dep-graph -Cpanic=unwind
 // build-pass (FIXME(62277): could be check-pass?)
diff --git a/src/test/incremental/commandline-args.rs b/src/test/incremental/commandline-args.rs
index e5b84267b29..08a0232f661 100644
--- a/src/test/incremental/commandline-args.rs
+++ b/src/test/incremental/commandline-args.rs
@@ -1,6 +1,7 @@
 // Test that changing a tracked commandline argument invalidates
 // the cache while changing an untracked one doesn't.
 
+// ignore-asmjs wasm2js does not support source maps yet
 // revisions:rpass1 rpass2 rpass3
 // compile-flags: -Z query-dep-graph
 
diff --git a/src/test/incremental/const-generics/issue-61338.rs b/src/test/incremental/const-generics/issue-61338.rs
new file mode 100644
index 00000000000..00b3b29698b
--- /dev/null
+++ b/src/test/incremental/const-generics/issue-61338.rs
@@ -0,0 +1,14 @@
+// revisions:rpass1
+
+#![feature(const_generics)]
+
+struct Struct<T>(T);
+
+impl<T, const N: usize> Struct<[T; N]> {
+    fn f() {}
+    fn g() { Self::f(); }
+}
+
+fn main() {
+    Struct::<[u32; 3]>::g();
+}
diff --git a/src/test/incremental/const-generics/issue-61516.rs b/src/test/incremental/const-generics/issue-61516.rs
new file mode 100644
index 00000000000..a7465b77267
--- /dev/null
+++ b/src/test/incremental/const-generics/issue-61516.rs
@@ -0,0 +1,16 @@
+// revisions:rpass1
+
+#![feature(const_generics)]
+
+struct FakeArray<T, const N: usize>(T);
+
+impl<T, const N: usize> FakeArray<T, { N }> {
+    fn len(&self) -> usize {
+        N
+    }
+}
+
+fn main() {
+    let fa = FakeArray::<u32, { 32 }>(1);
+    assert_eq!(fa.len(), 32);
+}
diff --git a/src/test/incremental/const-generics/issue-62536.rs b/src/test/incremental/const-generics/issue-62536.rs
new file mode 100644
index 00000000000..90e279bfc74
--- /dev/null
+++ b/src/test/incremental/const-generics/issue-62536.rs
@@ -0,0 +1,12 @@
+// revisions:cfail1
+#![feature(const_generics)]
+//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct S<T, const N: usize>([T; N]);
+
+fn f<T, const N: usize>(x: T) -> S<T, {N}> { panic!() }
+
+fn main() {
+    f(0u8);
+    //[cfail1]~^ ERROR type annotations needed
+}
diff --git a/src/test/incremental/const-generics/issue-64087.rs b/src/test/incremental/const-generics/issue-64087.rs
new file mode 100644
index 00000000000..b3c12fbb6e8
--- /dev/null
+++ b/src/test/incremental/const-generics/issue-64087.rs
@@ -0,0 +1,11 @@
+// revisions:cfail1
+#![feature(const_generics)]
+//[cfail1]~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn combinator<T, const S: usize>() -> [T; S] {}
+//[cfail1]~^ ERROR mismatched types
+
+fn main() {
+    combinator().into_iter();
+    //[cfail1]~^ ERROR type annotations needed
+}
diff --git a/src/test/incremental/const-generics/issue-65623.rs b/src/test/incremental/const-generics/issue-65623.rs
new file mode 100644
index 00000000000..353e323e67b
--- /dev/null
+++ b/src/test/incremental/const-generics/issue-65623.rs
@@ -0,0 +1,14 @@
+// revisions:rpass1
+#![feature(const_generics)]
+
+pub struct Foo<T, const N: usize>([T; 0]);
+
+impl<T, const N: usize> Foo<T, {N}> {
+    pub fn new() -> Self {
+        Foo([])
+    }
+}
+
+fn main() {
+    let _: Foo<u32, 0> = Foo::new();
+}
diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs
index 70820dfaea4..8e134ad14fc 100644
--- a/src/test/incremental/hashes/for_loops.rs
+++ b/src/test/incremental/hashes/for_loops.rs
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 68545b7daaa..4e8ba5a209d 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -22,7 +22,7 @@ pub fn change_name() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,mir_built,optimized_mir")]
+    except="HirBody,mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_name() {
     let _y = 2u64;
@@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,typeck_tables_of,mir_built,optimized_mir")]
+    except="HirBody,typeck_tables_of,mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_slot() {
     let _x: u64 = 0;
@@ -182,7 +182,7 @@ pub fn add_initializer() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,typeck_tables_of,mir_built,optimized_mir")]
+    except="HirBody,typeck_tables_of,mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_initializer() {
     let _x: i16 = 3i16;
@@ -198,7 +198,7 @@ pub fn change_initializer() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,mir_built,optimized_mir")]
+    except="HirBody,mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_initializer() {
     let _x = 5u16;
diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs
index a2222db4c59..ca85ee39e36 100644
--- a/src/test/incremental/hashes/loop_expressions.rs
+++ b/src/test/incremental/hashes/loop_expressions.rs
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs
index da3c957741f..1e628d01919 100644
--- a/src/test/incremental/hashes/while_let_loops.rs
+++ b/src/test/incremental/hashes/while_let_loops.rs
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs
index 3be42e7a4ee..295c2244879 100644
--- a/src/test/incremental/hashes/while_loops.rs
+++ b/src/test/incremental/hashes/while_loops.rs
@@ -25,7 +25,7 @@ pub fn change_loop_body() {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")]
+#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/src/test/incremental/remapped_paths_cc/main.rs b/src/test/incremental/remapped_paths_cc/main.rs
index 12411a92879..b01f02444ea 100644
--- a/src/test/incremental/remapped_paths_cc/main.rs
+++ b/src/test/incremental/remapped_paths_cc/main.rs
@@ -2,6 +2,7 @@
 // compile-flags: -Z query-dep-graph -g
 // aux-build:extern_crate.rs
 
+// ignore-asmjs wasm2js does not support source maps yet
 // This test case makes sure that we detect if paths emitted into debuginfo
 // are changed, even when the change happens in an external crate.
 
diff --git a/src/test/incremental/span_hash_stable/main.rs b/src/test/incremental/span_hash_stable/main.rs
index f1d7de14559..367416430f8 100644
--- a/src/test/incremental/span_hash_stable/main.rs
+++ b/src/test/incremental/span_hash_stable/main.rs
@@ -3,6 +3,7 @@
 // the spans and this test makes sure that we handle them correctly by hashing
 // file:line:column instead of raw byte offset.
 
+// ignore-asmjs wasm2js does not support source maps yet
 // revisions:rpass1 rpass2
 // compile-flags: -g -Z query-dep-graph
 
diff --git a/src/test/incremental/spans_in_type_debuginfo.rs b/src/test/incremental/spans_in_type_debuginfo.rs
index 8ed469db6e6..f5cae15a4bc 100644
--- a/src/test/incremental/spans_in_type_debuginfo.rs
+++ b/src/test/incremental/spans_in_type_debuginfo.rs
@@ -1,6 +1,7 @@
 // Test that moving a type definition within a source file does not affect
 // re-compilation.
 
+// ignore-asmjs wasm2js does not support source maps yet
 // revisions:rpass1 rpass2
 // compile-flags: -Z query-dep-graph -g
 
diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs
index 87c97ba06c4..e6fdc7cb3a0 100644
--- a/src/test/incremental/spans_significant_w_debuginfo.rs
+++ b/src/test/incremental/spans_significant_w_debuginfo.rs
@@ -3,6 +3,7 @@
 
 // revisions:rpass1 rpass2
 
+// ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g -Z query-dep-graph
 
 #![feature(rustc_attrs)]
diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs
index 8dc6b73edf6..4b66c07b093 100644
--- a/src/test/mir-opt/box_expr.rs
+++ b/src/test/mir-opt/box_expr.rs
@@ -1,4 +1,4 @@
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(box_syntax)]
 
diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs
new file mode 100644
index 00000000000..0937d37be6b
--- /dev/null
+++ b/src/test/mir-opt/const_prop/aggregate.rs
@@ -0,0 +1,25 @@
+// compile-flags: -O
+
+fn main() {
+    let x = (0, 1, 2).1 + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = (const 0i32, const 1i32, const 2i32);
+//      _2 = (_3.1: i32);
+//      _1 = Add(move _2, const 0i32);
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = (const 0i32, const 1i32, const 2i32);
+//      _2 = const 1i32;
+//      _1 = Add(move _2, const 0i32);
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs
new file mode 100644
index 00000000000..cf134dadf27
--- /dev/null
+++ b/src/test/mir-opt/const_prop/boxes.rs
@@ -0,0 +1,56 @@
+// compile-flags: -O
+// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32
+// ignore-wasm64
+
+#![feature(box_syntax)]
+
+// Note: this test verifies that we, in fact, do not const prop `box`
+
+fn main() {
+    let x = *(box 42) + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _4 = Box(i32);
+//      (*_4) = const 42i32;
+//      _3 = move _4;
+//      ...
+//      _2 = (*_3);
+//      _1 = Add(move _2, const 0i32);
+//      ...
+//      drop(_3) -> [return: bb2, unwind: bb1];
+//  }
+//  bb1 (cleanup): {
+//      resume;
+//  }
+//  bb2: {
+//      ...
+//      _0 = ();
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _4 = Box(i32);
+//      (*_4) = const 42i32;
+//      _3 = move _4;
+//      ...
+//      _2 = (*_3);
+//      _1 = Add(move _2, const 0i32);
+//      ...
+//      drop(_3) -> [return: bb2, unwind: bb1];
+//  }
+//  bb1 (cleanup): {
+//      resume;
+//  }
+//  bb2: {
+//      ...
+//      _0 = ();
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs
new file mode 100644
index 00000000000..07bbd9202b9
--- /dev/null
+++ b/src/test/mir-opt/const_prop/discriminant.rs
@@ -0,0 +1,53 @@
+// compile-flags: -O
+
+fn main() {
+    let x = (if let Some(true) = Some(true) { 42 } else { 10 }) + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = std::option::Option::<bool>::Some(const true,);
+//      _4 = discriminant(_3);
+//      switchInt(move _4) -> [1isize: bb3, otherwise: bb2];
+//  }
+//  bb1: {
+//      _2 = const 42i32;
+//      goto -> bb4;
+//  }
+//  bb2: {
+//      _2 = const 10i32;
+//      goto -> bb4;
+//  }
+//  bb3: {
+//      switchInt(((_3 as Some).0: bool)) -> [false: bb2, otherwise: bb1];
+//  }
+//  bb4: {
+//      _1 = Add(move _2, const 0i32);
+//      ...
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = const Scalar(0x01) : std::option::Option<bool>;
+//      _4 = const 1isize;
+//      switchInt(const 1isize) -> [1isize: bb3, otherwise: bb2];
+//  }
+//  bb1: {
+//      _2 = const 42i32;
+//      goto -> bb4;
+//  }
+//  bb2: {
+//      _2 = const 10i32;
+//      goto -> bb4;
+//  }
+//  bb3: {
+//      switchInt(const true) -> [false: bb2, otherwise: bb1];
+//  }
+//  bb4: {
+//      _1 = Add(move _2, const 0i32);
+//      ...
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/repeat.rs b/src/test/mir-opt/const_prop/repeat.rs
new file mode 100644
index 00000000000..fb091ad2a3d
--- /dev/null
+++ b/src/test/mir-opt/const_prop/repeat.rs
@@ -0,0 +1,37 @@
+// compile-flags: -O
+
+fn main() {
+    let x: u32 = [42; 8][2] + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = [const 42u32; 8];
+//      ...
+//      _4 = const 2usize;
+//      _5 = const 8usize;
+//      _6 = Lt(_4, _5);
+//      assert(move _6, "index out of bounds: the len is move _5 but the index is _4") -> bb1;
+//  }
+//  bb1: {
+//      _2 = _3[_4];
+//      _1 = Add(move _2, const 0u32);
+//      ...
+//      return;
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _6 = const true;
+//      assert(const true, "index out of bounds: the len is move _5 but the index is _4") -> bb1;
+//  }
+//  bb1: {
+//      _2 = const 42u32;
+//      _1 = Add(move _2, const 0u32);
+//      ...
+//      return;
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs
index 109304d6d22..b595c100039 100644
--- a/src/test/mir-opt/generator-storage-dead-unwind.rs
+++ b/src/test/mir-opt/generator-storage-dead-unwind.rs
@@ -1,4 +1,4 @@
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 // Test that we generate StorageDead on unwind paths for generators.
 //
diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs
index e73390f52b5..8824496fdb0 100644
--- a/src/test/mir-opt/issue-41110.rs
+++ b/src/test/mir-opt/issue-41110.rs
@@ -1,4 +1,4 @@
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 // check that we don't emit multiple drop flags when they are not needed.
 
diff --git a/src/test/mir-opt/issue-62289.rs b/src/test/mir-opt/issue-62289.rs
index a3b517e9bca..93250fd48d8 100644
--- a/src/test/mir-opt/issue-62289.rs
+++ b/src/test/mir-opt/issue-62289.rs
@@ -1,7 +1,7 @@
 // check that we don't forget to drop the Box if we early return before
 // initializing it
 // ignore-tidy-linelength
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(box_syntax)]
 
diff --git a/src/test/mir-opt/no-spurious-drop-after-call.rs b/src/test/mir-opt/no-spurious-drop-after-call.rs
index 782bc31186c..370cd593b02 100644
--- a/src/test/mir-opt/no-spurious-drop-after-call.rs
+++ b/src/test/mir-opt/no-spurious-drop-after-call.rs
@@ -1,4 +1,4 @@
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 // Test that after the call to `std::mem::drop` we do not generate a
 // MIR drop of the argument. (We used to have a `DROP(_2)` in the code
diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs
index da73cc96348..eaa1fbd69ec 100644
--- a/src/test/mir-opt/packed-struct-drop-aligned.rs
+++ b/src/test/mir-opt/packed-struct-drop-aligned.rs
@@ -1,4 +1,4 @@
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 fn main() {
     let mut x = Packed(Aligned(Droppy(0)));
diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs
index 3245d38b258..71beaa73663 100644
--- a/src/test/mir-opt/remove_fake_borrows.rs
+++ b/src/test/mir-opt/remove_fake_borrows.rs
@@ -1,6 +1,6 @@
 // Test that the fake borrows for matches are removed after borrow checking.
 
-// ignore-wasm32-bare
+// ignore-emscripten compiled with panic=abort by default
 
 fn match_guard(x: Option<&&i32>, c: bool) -> i32 {
     match x {
diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs
index db36a1fab5f..a0bdfb3ab8b 100644
--- a/src/test/mir-opt/retag.rs
+++ b/src/test/mir-opt/retag.rs
@@ -1,4 +1,4 @@
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // ignore-tidy-linelength
 // compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats
 
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs
new file mode 100644
index 00000000000..6f03438ff72
--- /dev/null
+++ b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs
@@ -0,0 +1,89 @@
+// compile-flags: -C overflow-checks=no
+
+fn use_zst(_: ((), ())) { }
+
+struct Temp {
+    x: u8
+}
+
+fn use_u8(_: u8) { }
+
+fn main() {
+    let ((), ()) = ((), ());
+    use_zst(((), ()));
+
+    use_u8((Temp { x : 40 }).x + 2);
+}
+
+// END RUST SOURCE
+
+// START rustc.main.SimplifyLocals.before.mir
+// let mut _0: ();
+// let mut _1: ((), ());
+// let mut _2: ();
+// let mut _3: ();
+// let _4: ();
+// let mut _5: ((), ());
+// let mut _6: ();
+// let mut _7: ();
+// let _8: ();
+// let mut _9: u8;
+// let mut _10: u8;
+// let mut _11: Temp;
+// scope 1 {
+// }
+// bb0: {
+//   StorageLive(_1);
+//   StorageLive(_2);
+//   _2 = const Scalar(<ZST>) : ();
+//   StorageLive(_3);
+//   _3 = const Scalar(<ZST>) : ();
+//   _1 = const Scalar(<ZST>) : ((), ());
+//   StorageDead(_3);
+//   StorageDead(_2);
+//   StorageDead(_1);
+//   StorageLive(_4);
+//   StorageLive(_6);
+//   _6 = const Scalar(<ZST>) : ();
+//   StorageLive(_7);
+//   _7 = const Scalar(<ZST>) : ();
+//   StorageDead(_7);
+//   StorageDead(_6);
+//   _4 = const use_zst(const Scalar(<ZST>) : ((), ())) -> bb1;
+// }
+// bb1: {
+//   StorageDead(_4);
+//   StorageLive(_8);
+//   StorageLive(_10);
+//   StorageLive(_11);
+//   _11 = const Scalar(0x28) : Temp;
+//   _10 = const 40u8;
+//   StorageDead(_10);
+//   _8 = const use_u8(const 42u8) -> bb2;
+// }
+// bb2: {
+//   StorageDead(_11);
+//   StorageDead(_8);
+//   return;
+// }
+// END rustc.main.SimplifyLocals.before.mir
+// START rustc.main.SimplifyLocals.after.mir
+// let mut _0: ();
+// let _1: ();
+// let _2: ();
+// scope 1 {
+// }
+// bb0: {
+//   StorageLive(_1);
+//   _1 = const use_zst(const Scalar(<ZST>) : ((), ())) -> bb1;
+// }
+// bb1: {
+//   StorageDead(_1);
+//   StorageLive(_2);
+//   _2 = const use_u8(const 42u8) -> bb2;
+// }
+// bb2: {
+//   StorageDead(_2);
+//   return;
+// }
+// END rustc.main.SimplifyLocals.after.mir
diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs
index 754fad51b21..f270dec5fe2 100644
--- a/src/test/mir-opt/slice-drop-shim.rs
+++ b/src/test/mir-opt/slice-drop-shim.rs
@@ -1,5 +1,7 @@
+// compile-flags: -Zmir-opt-level=0
+
 fn main() {
-    std::ptr::drop_in_place::<[String]> as unsafe fn(_);
+    let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_);
 }
 
 // END RUST SOURCE
diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs
index 793f495240d..58dfc5710ae 100644
--- a/src/test/run-fail/overflowing-rsh-5.rs
+++ b/src/test/run-fail/overflowing-rsh-5.rs
@@ -2,6 +2,7 @@
 // compile-flags: -C debug-assertions
 
 #![warn(exceeding_bitshifts)]
+#![warn(const_err)]
 
 fn main() {
     let _n = 1i64 >> [64][0];
diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs
index d6b2f8dc9f9..c2fec5e4860 100644
--- a/src/test/run-fail/overflowing-rsh-6.rs
+++ b/src/test/run-fail/overflowing-rsh-6.rs
@@ -2,6 +2,7 @@
 // compile-flags: -C debug-assertions
 
 #![warn(exceeding_bitshifts)]
+#![warn(const_err)]
 #![feature(const_indexing)]
 
 fn main() {
diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
index 200dc1be4de..f56475b441f 100644
--- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
+++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile
@@ -4,12 +4,18 @@
 
 -include ../tools.mk
 
-# This test builds a staticlib, then an executable that links to it.
-# The staticlib and executable both  are compiled with address sanitizer,
-# and we assert that a fault in the staticlib is correctly detected.
+# This test first builds a staticlib with AddressSanitizer and checks that
+# linking it to an executable fails due to the missing sanitizer runtime.
+# It then builds an executable linking to the staticlib and checks that
+# the fault in the staticlib is detected correctly.
+
+# Note that checking for the link failure actually checks two things at once:
+#   1) That the library has the sanitizer intrumentation
+#   2) and that library does not have the sanitizer runtime
 
 all:
 	$(RUSTC) -g -Z sanitizer=address --crate-type staticlib --target $(TARGET) library.rs
-	$(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
+	! $(CC) program.c $(call STATICLIB,library) $(call OUT_EXE,program) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
+	$(RUSTC) -g -Z sanitizer=address --crate-type bin --target $(TARGET) -L . program.rs
 	LD_LIBRARY_PATH=$(TMPDIR) $(TMPDIR)/program 2>&1 | $(CGREP) stack-buffer-overflow
 
diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs b/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs
new file mode 100644
index 00000000000..21e1ade2cd5
--- /dev/null
+++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/program.rs
@@ -0,0 +1,10 @@
+#[link(name = "library")]
+extern {
+    fn overflow();
+}
+
+fn main() {
+    unsafe {
+        overflow();
+    }
+}
diff --git a/src/test/run-make/wasm-custom-section/Makefile b/src/test/run-make/wasm-custom-section/Makefile
index 7c64dc58bf7..2f48b852566 100644
--- a/src/test/run-make/wasm-custom-section/Makefile
+++ b/src/test/run-make/wasm-custom-section/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32
+# only-wasm32-bare
 
 all:
 	$(RUSTC) foo.rs --target wasm32-unknown-unknown
diff --git a/src/test/run-make/wasm-custom-sections-opt/Makefile b/src/test/run-make/wasm-custom-sections-opt/Makefile
index fec7643d20c..76698c0aae3 100644
--- a/src/test/run-make/wasm-custom-sections-opt/Makefile
+++ b/src/test/run-make/wasm-custom-sections-opt/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32
+# only-wasm32-bare
 
 all:
 	$(RUSTC) foo.rs -O --target wasm32-unknown-unknown
diff --git a/src/test/run-make/wasm-export-all-symbols/Makefile b/src/test/run-make/wasm-export-all-symbols/Makefile
index 15403d8d410..7e47ba4850e 100644
--- a/src/test/run-make/wasm-export-all-symbols/Makefile
+++ b/src/test/run-make/wasm-export-all-symbols/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32
+# only-wasm32-bare
 
 all:
 	$(RUSTC) bar.rs --target wasm32-unknown-unknown
diff --git a/src/test/run-make/wasm-import-module/Makefile b/src/test/run-make/wasm-import-module/Makefile
index 255d8f1ef0e..fe63e66f242 100644
--- a/src/test/run-make/wasm-import-module/Makefile
+++ b/src/test/run-make/wasm-import-module/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
- # only-wasm32
+ # only-wasm32-bare
 
 all:
 	$(RUSTC) foo.rs --target wasm32-unknown-unknown
diff --git a/src/test/run-make/wasm-panic-small/Makefile b/src/test/run-make/wasm-panic-small/Makefile
index b9141f93d53..68397e4bc6e 100644
--- a/src/test/run-make/wasm-panic-small/Makefile
+++ b/src/test/run-make/wasm-panic-small/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32
+# only-wasm32-bare
 
 all:
 	$(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg a
diff --git a/src/test/run-make/wasm-symbols-not-exported/Makefile b/src/test/run-make/wasm-symbols-not-exported/Makefile
index b17e04b7717..62bd0f0872e 100644
--- a/src/test/run-make/wasm-symbols-not-exported/Makefile
+++ b/src/test/run-make/wasm-symbols-not-exported/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32
+# only-wasm32-bare
 
 all:
 	$(RUSTC) foo.rs --target wasm32-unknown-unknown
diff --git a/src/test/run-make/wasm-symbols-not-imported/Makefile b/src/test/run-make/wasm-symbols-not-imported/Makefile
index b8f64e06f31..7a923375c18 100644
--- a/src/test/run-make/wasm-symbols-not-imported/Makefile
+++ b/src/test/run-make/wasm-symbols-not-imported/Makefile
@@ -1,6 +1,6 @@
 -include ../../run-make-fulldeps/tools.mk
 
-# only-wasm32
+# only-wasm32-bare
 
 all:
 	$(RUSTC) foo.rs --target wasm32-unknown-unknown
diff --git a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
index d206b721765..a8753d14de2 100644
--- a/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
@@ -6,13 +6,13 @@ failures:
 
 ---- $DIR/failed-doctest-missing-codes.rs - Foo (line 8) stdout ----
 error[E0308]: mismatched types
- --> $DIR/failed-doctest-missing-codes.rs:9:13
-  |
-3 | let x: () = 5i32;
-  |             ^^^^ expected (), found i32
-  |
-  = note: expected type `()`
-             found type `i32`
+  --> $DIR/failed-doctest-missing-codes.rs:9:13
+   |
+LL | let x: () = 5i32;
+   |             ^^^^ expected (), found i32
+   |
+   = note: expected type `()`
+              found type `i32`
 
 error: aborting due to previous error
 
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index ef1b419f528..9887d07a3eb 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -7,10 +7,10 @@ failures:
 
 ---- $DIR/failed-doctest-output.rs - OtherStruct (line 21) stdout ----
 error[E0425]: cannot find value `no` in this scope
- --> $DIR/failed-doctest-output.rs:22:1
-  |
-3 | no
-  | ^^ not found in this scope
+  --> $DIR/failed-doctest-output.rs:22:1
+   |
+LL | no
+   | ^^ not found in this scope
 
 error: aborting due to previous error
 
diff --git a/src/test/rustdoc-ui/unparseable-doc-test.stdout b/src/test/rustdoc-ui/unparseable-doc-test.stdout
index 0350c016436..4ea6455d3aa 100644
--- a/src/test/rustdoc-ui/unparseable-doc-test.stdout
+++ b/src/test/rustdoc-ui/unparseable-doc-test.stdout
@@ -6,10 +6,10 @@ failures:
 
 ---- $DIR/unparseable-doc-test.rs - foo (line 6) stdout ----
 error: unterminated double quote string
- --> $DIR/unparseable-doc-test.rs:8:1
-  |
-2 | "unterminated
-  | ^^^^^^^^^^^^^
+  --> $DIR/unparseable-doc-test.rs:8:1
+   |
+LL | "unterminated
+   | ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs
new file mode 100644
index 00000000000..298ff601de8
--- /dev/null
+++ b/src/test/rustdoc/macro-in-closure.rs
@@ -0,0 +1,9 @@
+// Regression issue for rustdoc ICE encountered in PR #65252.
+
+#![feature(decl_macro)]
+
+fn main() {
+    || {
+        macro m() {}
+    };
+}
diff --git a/src/test/rustdoc/sanitizer-option.rs b/src/test/rustdoc/sanitizer-option.rs
new file mode 100644
index 00000000000..6af9ed3e33f
--- /dev/null
+++ b/src/test/rustdoc/sanitizer-option.rs
@@ -0,0 +1,17 @@
+// needs-sanitizer-support
+// compile-flags: --test -Z sanitizer=address
+//
+// #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern
+// function that is provided by the sanitizer runtime, if flag is not passed
+// correctly, then linking will fail.
+
+/// ```
+/// extern {
+///     fn __sanitizer_print_stack_trace();
+/// }
+///
+/// fn main() {
+///     unsafe { __sanitizer_print_stack_trace() };
+/// }
+/// ```
+pub fn z_flag_is_passed_to_rustc() {}
diff --git a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs
index 6c5f539b871..927e2c0820e 100644
--- a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs
+++ b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs
@@ -10,14 +10,15 @@ extern crate syntax;
 use syntax::ast::*;
 use syntax::attr::*;
 use syntax::ast;
+use syntax::sess::ParseSess;
 use syntax::source_map::{FilePathMapping, FileName};
 use syntax::parse;
-use syntax::parse::{ParseSess, PResult};
+use syntax::parse::PResult;
 use syntax::parse::new_parser_from_source_str;
 use syntax::parse::parser::Parser;
 use syntax::parse::token;
 use syntax::ptr::P;
-use syntax::parse::attr::*;
+use syntax::parse::parser::attr::*;
 use syntax::print::pprust;
 use std::fmt;
 
diff --git a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs
index c053c715248..3d08c1c9eee 100644
--- a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs
@@ -5,9 +5,10 @@
 
 extern crate rustc_driver;
 extern crate syntax;
+extern crate syntax_expand;
 
 use rustc_driver::plugin::Registry;
-use syntax::ext::base::SyntaxExtension;
+use syntax_expand::base::SyntaxExtension;
 use syntax::feature_gate::AttributeType;
 use syntax::symbol::Symbol;
 
diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
index 6fb99b2c983..bb0ebf693d0 100644
--- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
+++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
@@ -5,10 +5,11 @@
 extern crate rustc;
 extern crate rustc_driver;
 extern crate syntax;
+extern crate syntax_expand;
 
 use rustc_driver::plugin::Registry;
 use syntax::attr;
-use syntax::ext::base::*;
+use syntax_expand::base::*;
 use syntax::feature_gate::AttributeType::Whitelisted;
 use syntax::symbol::Symbol;
 
diff --git a/src/test/ui-fulldeps/auxiliary/plugin-args.rs b/src/test/ui-fulldeps/auxiliary/plugin-args.rs
index 5ff24cff23c..cccdfea2083 100644
--- a/src/test/ui-fulldeps/auxiliary/plugin-args.rs
+++ b/src/test/ui-fulldeps/auxiliary/plugin-args.rs
@@ -4,14 +4,15 @@
 #![feature(box_syntax, rustc_private)]
 
 extern crate syntax;
+extern crate syntax_expand;
 extern crate syntax_pos;
 extern crate rustc;
 extern crate rustc_driver;
 
 use std::borrow::ToOwned;
 use syntax::ast;
-use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
-use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager};
+use syntax_expand::base::{SyntaxExtension, SyntaxExtensionKind};
+use syntax_expand::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager};
 use syntax::print::pprust;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
diff --git a/src/test/ui-fulldeps/auxiliary/roman-numerals.rs b/src/test/ui-fulldeps/auxiliary/roman-numerals.rs
index 2b57e9289b5..3524f449c74 100644
--- a/src/test/ui-fulldeps/auxiliary/roman-numerals.rs
+++ b/src/test/ui-fulldeps/auxiliary/roman-numerals.rs
@@ -10,13 +10,14 @@
 #![feature(plugin_registrar, rustc_private)]
 
 extern crate syntax;
+extern crate syntax_expand;
 extern crate syntax_pos;
 extern crate rustc;
 extern crate rustc_driver;
 
 use syntax::parse::token::{self, Token};
 use syntax::tokenstream::{TokenTree, TokenStream};
-use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
+use syntax_expand::base::{ExtCtxt, MacResult, DummyResult, MacEager};
 use syntax_pos::Span;
 use rustc_driver::plugin::Registry;
 
diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr
index aa031fb7a63..aec1325844f 100644
--- a/src/test/ui-fulldeps/gated-plugin.stderr
+++ b/src/test/ui-fulldeps/gated-plugin.stderr
@@ -7,11 +7,11 @@ LL | #![plugin(attr_plugin_test)]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29597
    = help: add `#![feature(plugin)]` to the crate attributes to enable
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/gated-plugin.rs:3:1
    |
 LL | #![plugin(attr_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/issue-15778-fail.stderr b/src/test/ui-fulldeps/issue-15778-fail.stderr
index 3afdb1fbf80..e76044c56ef 100644
--- a/src/test/ui-fulldeps/issue-15778-fail.stderr
+++ b/src/test/ui-fulldeps/issue-15778-fail.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-15778-fail.rs:6:1
    |
 LL | #![plugin(lint_for_crate)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/issue-15778-pass.stderr b/src/test/ui-fulldeps/issue-15778-pass.stderr
index f81c314c23a..0c30d2cdcbf 100644
--- a/src/test/ui-fulldeps/issue-15778-pass.stderr
+++ b/src/test/ui-fulldeps/issue-15778-pass.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-15778-pass.rs:8:1
    |
 LL | #![plugin(lint_for_crate_rpass)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/issue-40001.stderr b/src/test/ui-fulldeps/issue-40001.stderr
index 186721e2bb9..d0ad0275ed1 100644
--- a/src/test/ui-fulldeps/issue-40001.stderr
+++ b/src/test/ui-fulldeps/issue-40001.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-40001.rs:6:1
    |
 LL | #![plugin(issue_40001_plugin)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr
index 28065bf3946..f8a4f271da5 100644
--- a/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr
+++ b/src/test/ui-fulldeps/lint-group-plugin-deny-cmdline.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-group-plugin-deny-cmdline.rs:7:1
    |
 LL | #![plugin(lint_group_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-group-plugin.stderr b/src/test/ui-fulldeps/lint-group-plugin.stderr
index a93cae1a2b1..58dc78b06d3 100644
--- a/src/test/ui-fulldeps/lint-group-plugin.stderr
+++ b/src/test/ui-fulldeps/lint-group-plugin.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-group-plugin.rs:6:1
    |
 LL | #![plugin(lint_group_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr
index 2185929e893..c6d198dc458 100644
--- a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr
+++ b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-cmdline-allow.rs:8:1
    |
 LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr
index a0cd9687f5b..c611023e549 100644
--- a/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr
+++ b/src/test/ui-fulldeps/lint-plugin-deny-attr.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-deny-attr.rs:5:1
    |
 LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr
index 3c64025e5eb..03668fbfe66 100644
--- a/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr
+++ b/src/test/ui-fulldeps/lint-plugin-deny-cmdline.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-deny-cmdline.rs:6:1
    |
 LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr
index c0c43855c92..c0de1feee7d 100644
--- a/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr
+++ b/src/test/ui-fulldeps/lint-plugin-forbid-attrs.stderr
@@ -7,11 +7,11 @@ LL | #![forbid(test_lint)]
 LL | #[allow(test_lint)]
    |         ^^^^^^^^^ overruled by previous forbid
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-forbid-attrs.rs:5:1
    |
 LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr
index 99d01392191..f189efbf61d 100644
--- a/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr
+++ b/src/test/ui-fulldeps/lint-plugin-forbid-cmdline.stderr
@@ -6,11 +6,11 @@ LL | #[allow(test_lint)]
    |
    = note: `forbid` lint level was set on command line
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin-forbid-cmdline.rs:6:1
    |
 LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-plugin.stderr b/src/test/ui-fulldeps/lint-plugin.stderr
index 2ca5eefe437..e95650090dd 100644
--- a/src/test/ui-fulldeps/lint-plugin.stderr
+++ b/src/test/ui-fulldeps/lint-plugin.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-plugin.rs:5:1
    |
 LL | #![plugin(lint_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr
index 71c3dc929b2..239732521d5 100644
--- a/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr
+++ b/src/test/ui-fulldeps/lint-tool-cmdline-allow.stderr
@@ -2,11 +2,11 @@ warning: lint name `test_lint` is deprecated and does not have an effect anymore
    |
    = note: requested on the command line with `-A test_lint`
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-tool-cmdline-allow.rs:8:1
    |
 LL | #![plugin(lint_tool_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lint-tool-test.stderr b/src/test/ui-fulldeps/lint-tool-test.stderr
index c727cfc7015..d4031a780c3 100644
--- a/src/test/ui-fulldeps/lint-tool-test.stderr
+++ b/src/test/ui-fulldeps/lint-tool-test.stderr
@@ -32,11 +32,11 @@ warning: lint name `test_lint` is deprecated and may not have an effect in the f
 LL | #![cfg_attr(foo, warn(test_lint))]
    |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lint-tool-test.rs:6:1
    |
 LL | #![plugin(lint_tool_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/llvm-pass-plugin.stderr b/src/test/ui-fulldeps/llvm-pass-plugin.stderr
index ebc092671a7..61b53bb2b7c 100644
--- a/src/test/ui-fulldeps/llvm-pass-plugin.stderr
+++ b/src/test/ui-fulldeps/llvm-pass-plugin.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/llvm-pass-plugin.rs:6:1
    |
 LL | #![plugin(llvm_pass_plugin)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/lto-syntax-extension.stderr b/src/test/ui-fulldeps/lto-syntax-extension.stderr
index 509331ceb21..529da32e10e 100644
--- a/src/test/ui-fulldeps/lto-syntax-extension.stderr
+++ b/src/test/ui-fulldeps/lto-syntax-extension.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/lto-syntax-extension.rs:9:1
    |
 LL | #![plugin(lto_syntax_extension_plugin)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/macro-crate-rlib.stderr b/src/test/ui-fulldeps/macro-crate-rlib.stderr
index 47d5ecb3742..b5bd761f1b5 100644
--- a/src/test/ui-fulldeps/macro-crate-rlib.stderr
+++ b/src/test/ui-fulldeps/macro-crate-rlib.stderr
@@ -4,11 +4,11 @@ error[E0457]: plugin `rlib_crate_test` only found in rlib format, but must be av
 LL | #![plugin(rlib_crate_test)]
    |           ^^^^^^^^^^^^^^^
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/macro-crate-rlib.rs:6:1
    |
 LL | #![plugin(rlib_crate_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
index 8631bcca6d2..ac97ec70be2 100644
--- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
+++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs
@@ -7,8 +7,9 @@
 extern crate syntax;
 
 use std::path::Path;
+use syntax::sess::ParseSess;
 use syntax::source_map::FilePathMapping;
-use syntax::parse::{self, ParseSess};
+use syntax::parse;
 
 #[path = "mod_dir_simple/test.rs"]
 mod gravy;
diff --git a/src/test/ui-fulldeps/outlive-expansion-phase.stderr b/src/test/ui-fulldeps/outlive-expansion-phase.stderr
index 68e143d86ee..d06fc480fb5 100644
--- a/src/test/ui-fulldeps/outlive-expansion-phase.stderr
+++ b/src/test/ui-fulldeps/outlive-expansion-phase.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/outlive-expansion-phase.rs:6:1
    |
 LL | #![plugin(outlive_expansion_phase)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/plugin-args-1.stderr b/src/test/ui-fulldeps/plugin-args-1.stderr
index 0d01a859df8..ca3e27069ed 100644
--- a/src/test/ui-fulldeps/plugin-args-1.stderr
+++ b/src/test/ui-fulldeps/plugin-args-1.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/plugin-args-1.rs:6:1
    |
 LL | #![plugin(plugin_args)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/plugin-args-2.stderr b/src/test/ui-fulldeps/plugin-args-2.stderr
index 2bbabd20138..57c06513d5c 100644
--- a/src/test/ui-fulldeps/plugin-args-2.stderr
+++ b/src/test/ui-fulldeps/plugin-args-2.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/plugin-args-2.rs:6:1
    |
 LL | #![plugin(plugin_args())]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/plugin-args-3.stderr b/src/test/ui-fulldeps/plugin-args-3.stderr
index bf4108bd7f8..179f1abc8c4 100644
--- a/src/test/ui-fulldeps/plugin-args-3.stderr
+++ b/src/test/ui-fulldeps/plugin-args-3.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/plugin-args-3.rs:6:1
    |
 LL | #![plugin(plugin_args(hello(there), how(are="you")))]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/plugin-attr-register-deny.stderr b/src/test/ui-fulldeps/plugin-attr-register-deny.stderr
index a045782a95f..8d95d6ff2d8 100644
--- a/src/test/ui-fulldeps/plugin-attr-register-deny.stderr
+++ b/src/test/ui-fulldeps/plugin-attr-register-deny.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/plugin-attr-register-deny.rs:5:1
    |
 LL | #![plugin(attr_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/plugin-reexport.stderr b/src/test/ui-fulldeps/plugin-reexport.stderr
index 52d27c32897..365b26d131e 100644
--- a/src/test/ui-fulldeps/plugin-reexport.stderr
+++ b/src/test/ui-fulldeps/plugin-reexport.stderr
@@ -10,11 +10,11 @@ note: consider marking `mac` as `pub` in the imported module
 LL | pub use mac as reexport;
    |         ^^^^^^^^^^^^^^^
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/plugin-reexport.rs:6:1
    |
 LL | #![plugin(attr_plugin_test)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index d4aff735907..932a173bc67 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -24,14 +24,14 @@ extern crate syntax;
 
 use rustc_data_structures::thin_vec::ThinVec;
 use syntax::ast::*;
+use syntax::sess::ParseSess;
 use syntax::source_map::{Spanned, DUMMY_SP, FileName};
 use syntax::source_map::FilePathMapping;
 use syntax::mut_visit::{self, MutVisitor, visit_clobber};
-use syntax::parse::{self, ParseSess};
+use syntax::parse;
 use syntax::print::pprust;
 use syntax::ptr::P;
 
-
 fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
     let src_as_string = src.to_string();
 
diff --git a/src/test/ui-fulldeps/roman-numerals-macro.stderr b/src/test/ui-fulldeps/roman-numerals-macro.stderr
index 7ac619185a1..8f3f558e91d 100644
--- a/src/test/ui-fulldeps/roman-numerals-macro.stderr
+++ b/src/test/ui-fulldeps/roman-numerals-macro.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/roman-numerals-macro.rs:6:1
    |
 LL | #![plugin(roman_numerals)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/abi/statics/static-mut-foreign.rs b/src/test/ui/abi/statics/static-mut-foreign.rs
index 5d6fa416b98..b30e8f00e40 100644
--- a/src/test/ui/abi/statics/static-mut-foreign.rs
+++ b/src/test/ui/abi/statics/static-mut-foreign.rs
@@ -5,6 +5,10 @@
 
 // ignore-wasm32-bare no libc to test ffi with
 
+// FIXME: This will work on emscripten once libc is updated to include
+// rust-lang/libc/#1478
+// ignore-emscripten libc type mismatch
+
 #![feature(rustc_private)]
 
 extern crate libc;
diff --git a/src/test/ui/asm/issue-51431.rs b/src/test/ui/asm/issue-51431.rs
new file mode 100644
index 00000000000..d29c31fafc2
--- /dev/null
+++ b/src/test/ui/asm/issue-51431.rs
@@ -0,0 +1,10 @@
+// ignore-emscripten no asm! support
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)}
+        //~^ ERROR: invalid value for constraint in inline assembly
+    }
+}
diff --git a/src/test/ui/asm/issue-51431.stderr b/src/test/ui/asm/issue-51431.stderr
new file mode 100644
index 00000000000..132eea126d6
--- /dev/null
+++ b/src/test/ui/asm/issue-51431.stderr
@@ -0,0 +1,8 @@
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/issue-51431.rs:7:32
+   |
+LL |         asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)}
+   |                                ^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr b/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr
index c213cfeeafa..2ceab394e95 100644
--- a/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr
+++ b/src/test/ui/associated-const/associated-const-impl-wrong-lifetime.stderr
@@ -6,7 +6,7 @@ LL |     const NAME: &'a str = "unit";
    |
    = note: expected type `&'static str`
               found type `&'a str`
-note: the lifetime 'a as defined on the impl at 6:6...
+note: the lifetime `'a` as defined on the impl at 6:6...
   --> $DIR/associated-const-impl-wrong-lifetime.rs:6:6
    |
 LL | impl<'a> Foo for &'a () {
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
index 30b6b4f3909..c258892057b 100644
--- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
+++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: Foo` is not satisfied
 LL |     const Y: usize;
    |     --------------- required by `Foo::Y`
 ...
+LL | pub fn test<A: Foo, B: Foo>() {
+   |             -- help: consider further restricting this bound: `A: Foo +`
 LL |     let _array = [4; <A as Foo>::Y];
    |                      ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
-   |
-   = help: consider adding a `where A: Foo` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
index 30fa9891a13..f6c8e99e27a 100644
--- a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
+++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: Foo` is not satisfied
 LL |     const Y: usize;
    |     --------------- required by `Foo::Y`
 ...
+LL | pub fn test<A: Foo, B: Foo>() {
+   |             -- help: consider further restricting this bound: `A: Foo +`
 LL |     let _array: [u32; <A as Foo>::Y];
    |                       ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
-   |
-   = help: consider adding a `where A: Foo` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-const/issue-63496.rs b/src/test/ui/associated-const/issue-63496.rs
new file mode 100644
index 00000000000..311c48b5e48
--- /dev/null
+++ b/src/test/ui/associated-const/issue-63496.rs
@@ -0,0 +1,9 @@
+trait A {
+    const C: usize;
+
+    fn f() -> ([u8; A::C], [u8; A::C]);
+    //~^ ERROR: type annotations needed: cannot resolve
+    //~| ERROR: type annotations needed: cannot resolve
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-const/issue-63496.stderr
new file mode 100644
index 00000000000..70bb12de1fb
--- /dev/null
+++ b/src/test/ui/associated-const/issue-63496.stderr
@@ -0,0 +1,21 @@
+error[E0283]: type annotations needed: cannot resolve `_: A`
+  --> $DIR/issue-63496.rs:4:21
+   |
+LL |     const C: usize;
+   |     --------------- required by `A::C`
+LL | 
+LL |     fn f() -> ([u8; A::C], [u8; A::C]);
+   |                     ^^^^
+
+error[E0283]: type annotations needed: cannot resolve `_: A`
+  --> $DIR/issue-63496.rs:4:33
+   |
+LL |     const C: usize;
+   |     --------------- required by `A::C`
+LL | 
+LL |     fn f() -> ([u8; A::C], [u8; A::C]);
+   |                                 ^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/src/test/ui/associated-item/issue-48027.rs b/src/test/ui/associated-item/issue-48027.rs
new file mode 100644
index 00000000000..c9b4ccd3e8a
--- /dev/null
+++ b/src/test/ui/associated-item/issue-48027.rs
@@ -0,0 +1,8 @@
+trait Bar {
+    const X: usize;
+    fn return_n(&self) -> [u8; Bar::X]; //~ ERROR: type annotations needed
+}
+
+impl dyn Bar {} //~ ERROR: the trait `Bar` cannot be made into an object
+
+fn main() {}
diff --git a/src/test/ui/associated-item/issue-48027.stderr b/src/test/ui/associated-item/issue-48027.stderr
new file mode 100644
index 00000000000..562146a426d
--- /dev/null
+++ b/src/test/ui/associated-item/issue-48027.stderr
@@ -0,0 +1,21 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/issue-48027.rs:6:6
+   |
+LL |     const X: usize;
+   |           - the trait cannot contain associated consts like `X`
+...
+LL | impl dyn Bar {}
+   |      ^^^^^^^ the trait `Bar` cannot be made into an object
+
+error[E0283]: type annotations needed: cannot resolve `_: Bar`
+  --> $DIR/issue-48027.rs:3:32
+   |
+LL |     const X: usize;
+   |     --------------- required by `Bar::X`
+LL |     fn return_n(&self) -> [u8; Bar::X];
+   |                                ^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0038, E0283.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
index 06e8230aa15..9f6a73cfe39 100644
--- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
+++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
@@ -9,7 +9,10 @@ LL | impl Case1 for S1 {
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
    |
-LL | / fn assume_case1<T: Case1>() {
+LL |   fn assume_case1<T: Case1>() {
+   |   ^                          - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator`
+   |  _|
+   | |
 LL | |
 LL | |
 LL | |
@@ -19,7 +22,6 @@ LL | | }
    | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
-   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::iter::Iterator` bound
 
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
@@ -27,7 +29,10 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent be
 LL |   trait Case1 {
    |   ----------- required by `Case1`
 ...
-LL | / fn assume_case1<T: Case1>() {
+LL |   fn assume_case1<T: Case1>() {
+   |   ^                          - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send`
+   |  _|
+   | |
 LL | |
 LL | |
 LL | |
@@ -37,7 +42,6 @@ LL | | }
    | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
-   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Send` bound
 
 error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
@@ -45,7 +49,10 @@ error[E0277]: `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared
 LL |   trait Case1 {
    |   ----------- required by `Case1`
 ...
-LL | / fn assume_case1<T: Case1>() {
+LL |   fn assume_case1<T: Case1>() {
+   |   ^                          - help: consider further restricting the associated type: `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync`
+   |  _|
+   | |
 LL | |
 LL | |
 LL | |
@@ -55,7 +62,6 @@ LL | | }
    | |_^ `<<T as Case1>::C as std::iter::Iterator>::Item` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `<<T as Case1>::C as std::iter::Iterator>::Item`
-   = help: consider adding a `where <<T as Case1>::C as std::iter::Iterator>::Item: std::marker::Sync` bound
 
 error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug`
   --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1
diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs
index ce482fff401..97c5acf1f72 100644
--- a/src/test/ui/associated-type-bounds/union-bounds.rs
+++ b/src/test/ui/associated-type-bounds/union-bounds.rs
@@ -3,13 +3,13 @@
 #![feature(associated_type_bounds)]
 #![feature(untagged_unions)]
 
-#![allow(unions_with_drop_fields, unused_assignments)]
+#![allow(unused_assignments)]
 
-trait Tr1 { type As1; }
-trait Tr2 { type As2; }
-trait Tr3 { type As3; }
-trait Tr4<'a> { type As4; }
-trait Tr5 { type As5; }
+trait Tr1: Copy { type As1: Copy; }
+trait Tr2: Copy { type As2: Copy; }
+trait Tr3: Copy { type As3: Copy; }
+trait Tr4<'a>: Copy { type As4: Copy; }
+trait Tr5: Copy { type As5: Copy; }
 
 impl Tr1 for &str { type As1 = bool; }
 impl Tr2 for bool { type As2 = u8; }
@@ -71,7 +71,8 @@ where
     let _: &'a T = &x.f0;
 }
 
-union UnSelf<T> where Self: Tr1<As1: Tr2> {
+#[derive(Copy, Clone)]
+union UnSelf<T> where Self: Tr1<As1: Tr2>, T: Copy {
     f0: T,
     f1: <Self as Tr1>::As1,
     f2: <<Self as Tr1>::As1 as Tr2>::As2,
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.fixed b/src/test/ui/associated-types/associated-types-bound-failure.fixed
new file mode 100644
index 00000000000..cc47f31d004
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-bound-failure.fixed
@@ -0,0 +1,29 @@
+// run-rustfix
+// Test equality constraints on associated types in a where clause.
+#![allow(dead_code)]
+
+pub trait ToInt {
+    fn to_int(&self) -> isize;
+}
+
+pub trait GetToInt
+{
+    type R;
+
+    fn get(&self) -> <Self as GetToInt>::R;
+}
+
+fn foo<G>(g: G) -> isize
+    where G : GetToInt, <G as GetToInt>::R: ToInt 
+{
+    ToInt::to_int(&g.get()) //~ ERROR E0277
+}
+
+fn bar<G : GetToInt>(g: G) -> isize
+    where G::R : ToInt
+{
+    ToInt::to_int(&g.get()) // OK
+}
+
+pub fn main() {
+}
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.rs b/src/test/ui/associated-types/associated-types-bound-failure.rs
index 883ac363b44..31e073cc7a8 100644
--- a/src/test/ui/associated-types/associated-types-bound-failure.rs
+++ b/src/test/ui/associated-types/associated-types-bound-failure.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 // Test equality constraints on associated types in a where clause.
+#![allow(dead_code)]
 
 pub trait ToInt {
     fn to_int(&self) -> isize;
diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr
index 85acf134d51..c420c86a275 100644
--- a/src/test/ui/associated-types/associated-types-bound-failure.stderr
+++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr
@@ -1,13 +1,14 @@
 error[E0277]: the trait bound `<G as GetToInt>::R: ToInt` is not satisfied
-  --> $DIR/associated-types-bound-failure.rs:17:19
+  --> $DIR/associated-types-bound-failure.rs:19:19
    |
 LL |     fn to_int(&self) -> isize;
    |     -------------------------- required by `ToInt::to_int`
 ...
+LL |     where G : GetToInt
+   |                       - help: consider further restricting the associated type: `, <G as GetToInt>::R: ToInt`
+LL | {
 LL |     ToInt::to_int(&g.get())
    |                   ^^^^^^^^ the trait `ToInt` is not implemented for `<G as GetToInt>::R`
-   |
-   = help: consider adding a `where <G as GetToInt>::R: ToInt` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed
new file mode 100644
index 00000000000..aa23326506f
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused_variables)]
+
+trait Get {
+    type Value;
+    fn get(&self) -> <Self as Get>::Value;
+}
+
+trait Other {
+    fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get  {}
+    //~^ ERROR the trait bound `Self: Get` is not satisfied
+}
+
+fn main() {
+}
diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs b/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs
index 5b10d1dc2fd..0f6cea8e69f 100644
--- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs
+++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.rs
@@ -1,3 +1,6 @@
+// run-rustfix
+#![allow(unused_variables)]
+
 trait Get {
     type Value;
     fn get(&self) -> <Self as Get>::Value;
diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
index 9f033687a00..83d5390417e 100644
--- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
+++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
@@ -1,10 +1,11 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-for-unimpl-trait.rs:7:5
+  --> $DIR/associated-types-for-unimpl-trait.rs:10:5
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: Get` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   |     |                                                       |
+   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
+   |     the trait `Get` is not implemented for `Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr
index 01f66a18d25..0b8b7fab135 100644
--- a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr
+++ b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr
@@ -1,10 +1,10 @@
 error[E0277]: the trait bound `T: Foo<usize>` is not satisfied
   --> $DIR/associated-types-invalid-trait-ref-issue-18865.rs:10:12
    |
+LL | fn f<T:Foo<isize>>(t: &T) {
+   |      -- help: consider further restricting this bound: `T: Foo<usize> +`
 LL |     let u: <T as Foo<usize>>::Bar = t.get_bar();
    |            ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo<usize>` is not implemented for `T`
-   |
-   = help: consider adding a `where T: Foo<usize>` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
index ada9cacbee5..78198322913 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
@@ -2,9 +2,10 @@ error[E0277]: the trait bound `T: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-bound.rs:11:5
    |
 LL |     fn uhoh<T>(foo: <T as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
-   |
-   = help: consider adding a `where T: Get` bound
+   |     ^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |       |
+   |     |       help: consider restricting this bound: `T: Get`
+   |     the trait `Get` is not implemented for `T`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
index 56cd6d09cad..6aa0403088d 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
@@ -2,9 +2,10 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: Get` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   |     |                                                       |
+   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
+   |     the trait `Get` is not implemented for `Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
index 71175d36f64..8c242be9796 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
@@ -2,9 +2,10 @@ error[E0277]: the trait bound `Self: Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait.rs:17:5
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: Get` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
+   |     |                                                       |
+   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
+   |     the trait `Get` is not implemented for `Self`
 
 error[E0277]: the trait bound `(T, U): Get` is not satisfied
   --> $DIR/associated-types-no-suitable-supertrait.rs:22:5
diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
new file mode 100644
index 00000000000..f357045a456
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+// Check that we get an error when you use `<Self as Get>::Value` in
+// the trait definition even if there is no default method.
+
+trait Get {
+    type Value;
+}
+
+trait Other {
+    fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get ;
+    //~^ ERROR E0277
+}
+
+impl Get for () {
+    type Value = f32;
+}
+
+impl Get for f64 {
+    type Value = u32;
+}
+
+impl Other for () {
+    fn okay<U:Get>(&self, _foo: U, _bar: <Self as Get>::Value) { }
+}
+
+impl Other for f64 {
+    fn okay<U:Get>(&self, _foo: U, _bar: <Self as Get>::Value) { }
+}
+
+fn main() { }
diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs
index fc38b26f50b..549fc8fc618 100644
--- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs
+++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 // Check that we get an error when you use `<Self as Get>::Value` in
 // the trait definition even if there is no default method.
 
diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
index a260e379182..cb01488fa34 100644
--- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
+++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
@@ -1,10 +1,11 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:9:5
+  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
    |
 LL |     fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: Get` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |                                                       |
+   |     |                                                       help: consider further restricting `Self`: `where Self: Get`
+   |     the trait `Get` is not implemented for `Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed
new file mode 100644
index 00000000000..f780d171fee
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-unsized.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+trait Get {
+    type Value: ?Sized;
+    fn get(&self) -> <Self as Get>::Value;
+}
+
+fn foo<T:Get>(t: T) where <T as Get>::Value: std::marker::Sized  {
+    let x = t.get(); //~ ERROR the size for values of type
+}
+
+fn main() {
+}
diff --git a/src/test/ui/associated-types/associated-types-unsized.rs b/src/test/ui/associated-types/associated-types-unsized.rs
index a9bc24e44d1..bdba4c7ff16 100644
--- a/src/test/ui/associated-types/associated-types-unsized.rs
+++ b/src/test/ui/associated-types/associated-types-unsized.rs
@@ -1,3 +1,6 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
 trait Get {
     type Value: ?Sized;
     fn get(&self) -> <Self as Get>::Value;
diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr
index b5db9743932..2352ac4ad38 100644
--- a/src/test/ui/associated-types/associated-types-unsized.stderr
+++ b/src/test/ui/associated-types/associated-types-unsized.stderr
@@ -1,12 +1,13 @@
 error[E0277]: the size for values of type `<T as Get>::Value` cannot be known at compilation time
-  --> $DIR/associated-types-unsized.rs:7:9
+  --> $DIR/associated-types-unsized.rs:10:9
    |
+LL | fn foo<T:Get>(t: T) {
+   |                    - help: consider further restricting the associated type: `where <T as Get>::Value: std::marker::Sized`
 LL |     let x = t.get();
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<T as Get>::Value`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where <T as Get>::Value: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
index 4309373f123..5ea98dcd4a9 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |    bar(foo, x)
    |        ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 37:8...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 37:8...
   --> $DIR/project-fn-ret-contravariant.rs:37:8
    |
 LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index b8b1a979c36..627609c4a9c 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |    bar(foo, x)
    |        ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 44:8...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
   --> $DIR/project-fn-ret-invariant.rs:44:8
    |
 LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
diff --git a/src/test/ui/associated-types/issue-44153.rs b/src/test/ui/associated-types/issue-44153.rs
new file mode 100644
index 00000000000..2101cb61a94
--- /dev/null
+++ b/src/test/ui/associated-types/issue-44153.rs
@@ -0,0 +1,19 @@
+pub trait Array {
+    type Element;
+}
+
+pub trait Visit {
+    fn visit() {}
+}
+
+impl Array for () {
+    type Element = ();
+}
+
+impl<'a> Visit for () where
+    (): Array<Element=&'a ()>,
+{}
+
+fn main() {
+    <() as Visit>::visit(); //~ ERROR: type mismatch resolving
+}
diff --git a/src/test/ui/associated-types/issue-44153.stderr b/src/test/ui/associated-types/issue-44153.stderr
new file mode 100644
index 00000000000..b62a866a20b
--- /dev/null
+++ b/src/test/ui/associated-types/issue-44153.stderr
@@ -0,0 +1,16 @@
+error[E0271]: type mismatch resolving `<() as Array>::Element == &()`
+  --> $DIR/issue-44153.rs:18:5
+   |
+LL |     fn visit() {}
+   |     ---------- required by `Visit::visit`
+...
+LL |     <() as Visit>::visit();
+   |     ^^^^^^^^^^^^^^^^^^^^ expected (), found &()
+   |
+   = note: expected type `()`
+              found type `&()`
+   = note: required because of the requirements on the impl of `Visit` for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/issue-48010.rs b/src/test/ui/associated-types/issue-48010.rs
new file mode 100644
index 00000000000..70e30c132d0
--- /dev/null
+++ b/src/test/ui/associated-types/issue-48010.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![crate_type = "lib"]
+
+pub struct Foo;
+
+pub struct Path<T: Bar> {
+    _inner: T::Slice,
+}
+
+pub trait Bar: Sized {
+    type Slice: ?Sized;
+
+    fn open(_: &Path<Self>);
+}
+
+impl Bar for Foo {
+    type Slice = [u8];
+
+    fn open(_: &Path<Self>) {
+        unimplemented!()
+    }
+}
diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs
index c266644fd70..4a413381aa3 100644
--- a/src/test/ui/async-await/async-fn-size-moved-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs
@@ -7,7 +7,7 @@
 //
 // See issue #59123 for a full explanation.
 
-// ignore-wasm32-bare (sizes don't match)
+// ignore-emscripten (sizes don't match)
 // run-pass
 
 // edition:2018
diff --git a/src/test/ui/async-await/async-fn-size-uninit-locals.rs b/src/test/ui/async-await/async-fn-size-uninit-locals.rs
index ad20237981c..0558084f4f8 100644
--- a/src/test/ui/async-await/async-fn-size-uninit-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-uninit-locals.rs
@@ -4,7 +4,7 @@
 // What we don't want to see is the wrong multiple of 1024 (the size of `Big`)
 // being reflected in the size.
 
-// ignore-wasm32-bare (sizes don't match)
+// ignore-emscripten (sizes don't match)
 // run-pass
 
 // edition:2018
diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
index 7caa9f26bc2..4b5e2d59e38 100644
--- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
+++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr
@@ -244,4 +244,5 @@ LL |     let _ = await bar()?;
 
 error: aborting due to 35 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0728.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issue-60709.rs b/src/test/ui/async-await/issue-60709.rs
index 9ee419c4a56..61f6ed1b7b2 100644
--- a/src/test/ui/async-await/issue-60709.rs
+++ b/src/test/ui/async-await/issue-60709.rs
@@ -3,6 +3,7 @@
 // compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018
 
 // run-pass
+// ignore-asmjs wasm2js does not support source maps yet
 
 use std::future::Future;
 use std::task::Poll;
diff --git a/src/test/ui/async-await/issues/issue-51719.stderr b/src/test/ui/async-await/issues/issue-51719.stderr
index 6c3c8889da7..5b9adb253d9 100644
--- a/src/test/ui/async-await/issues/issue-51719.stderr
+++ b/src/test/ui/async-await/issues/issue-51719.stderr
@@ -8,3 +8,4 @@ LL |     let _gen = || foo().await;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0728`.
diff --git a/src/test/ui/async-await/issues/issue-51751.stderr b/src/test/ui/async-await/issues/issue-51751.stderr
index e50c78534f8..f120bd119c5 100644
--- a/src/test/ui/async-await/issues/issue-51751.stderr
+++ b/src/test/ui/async-await/issues/issue-51751.stderr
@@ -9,3 +9,4 @@ LL |     let finished = result.await;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0728`.
diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr
index f63eaa4c48a..538430290d2 100644
--- a/src/test/ui/async-await/issues/issue-62009-1.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-1.stderr
@@ -40,4 +40,5 @@ LL |     F: Future
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0728.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/async-await/issues/issue-62009-2.stderr b/src/test/ui/async-await/issues/issue-62009-2.stderr
index 79b6803263e..47b74b5574f 100644
--- a/src/test/ui/async-await/issues/issue-62009-2.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-2.stderr
@@ -8,3 +8,4 @@ LL |     (async || 2333)().await;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0728`.
diff --git a/src/test/ui/async-await/issues/issue-63388-2.stderr b/src/test/ui/async-await/issues/issue-63388-2.stderr
index 5099297fbeb..efec160588f 100644
--- a/src/test/ui/async-await/issues/issue-63388-2.stderr
+++ b/src/test/ui/async-await/issues/issue-63388-2.stderr
@@ -15,12 +15,12 @@ LL |         foo: &dyn Foo, bar: &'a dyn Foo
 LL |         foo
    |         --- this return type evaluates to the `'static` lifetime...
    |
-note: ...can't outlive the lifetime '_ as defined on the method body at 11:14
+note: ...can't outlive the lifetime `'_` as defined on the method body at 11:14
   --> $DIR/issue-63388-2.rs:11:14
    |
 LL |         foo: &dyn Foo, bar: &'a dyn Foo
    |              ^
-help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 11:14
+help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'_` as defined on the method body at 11:14
    |
 LL |         foo + '_
    |
diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs
new file mode 100644
index 00000000000..b5fee061f27
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-65159.rs
@@ -0,0 +1,10 @@
+// Regression test for #65159. We used to ICE.
+//
+// edition:2018
+
+async fn copy() -> Result<()> //~ ERROR wrong number of type arguments
+{
+    Ok(())
+}
+
+fn main() { }
diff --git a/src/test/ui/async-await/issues/issue-65159.stderr b/src/test/ui/async-await/issues/issue-65159.stderr
new file mode 100644
index 00000000000..56d2c38b302
--- /dev/null
+++ b/src/test/ui/async-await/issues/issue-65159.stderr
@@ -0,0 +1,9 @@
+error[E0107]: wrong number of type arguments: expected 2, found 1
+  --> $DIR/issue-65159.rs:5:20
+   |
+LL | async fn copy() -> Result<()>
+   |                    ^^^^^^^^^^ expected 2 type arguments
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr
index 49ebf414c55..f826a86f089 100644
--- a/src/test/ui/async-await/issues/non-async-enclosing-span.stderr
+++ b/src/test/ui/async-await/issues/non-async-enclosing-span.stderr
@@ -9,3 +9,4 @@ LL |     let y = do_the_thing().await;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0728`.
diff --git a/src/test/ui/async-await/unused-lifetime.rs b/src/test/ui/async-await/unused-lifetime.rs
new file mode 100644
index 00000000000..1cf546bcb42
--- /dev/null
+++ b/src/test/ui/async-await/unused-lifetime.rs
@@ -0,0 +1,42 @@
+// edition:2018
+
+// Avoid spurious warnings of unused lifetime. The below async functions
+// are desugered to have an unused lifetime
+// but we don't want to warn about that as there's nothing they can do about it.
+
+#![deny(unused_lifetimes)]
+#![allow(dead_code)]
+
+pub async fn october(s: &str) {
+    println!("{}", s);
+}
+
+pub async fn async_fn(&mut ref s: &mut[i32]) {
+    println!("{:?}", s);
+}
+
+macro_rules! foo_macro {
+    () => {
+        pub async fn async_fn_in_macro(&mut ref _s: &mut[i32]) {}
+    };
+}
+
+foo_macro!();
+
+pub async fn func_with_unused_lifetime<'a>(s: &'a str) {
+    //~^ ERROR lifetime parameter `'a` never used
+    println!("{}", s);
+}
+
+pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
+    //~^ ERROR lifetime parameter `'a` never used
+    //~^^ ERROR lifetime parameter `'b` never used
+    println!("{}", s);
+}
+
+pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) {
+    //~^ ERROR lifetime parameter `'c` never used
+    println!("{}", s);
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/unused-lifetime.stderr b/src/test/ui/async-await/unused-lifetime.stderr
new file mode 100644
index 00000000000..885cdc04cfa
--- /dev/null
+++ b/src/test/ui/async-await/unused-lifetime.stderr
@@ -0,0 +1,32 @@
+error: lifetime parameter `'a` never used
+  --> $DIR/unused-lifetime.rs:26:40
+   |
+LL | pub async fn func_with_unused_lifetime<'a>(s: &'a str) {
+   |                                        ^^
+   |
+note: lint level defined here
+  --> $DIR/unused-lifetime.rs:7:9
+   |
+LL | #![deny(unused_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` never used
+  --> $DIR/unused-lifetime.rs:31:44
+   |
+LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
+   |                                            ^^
+
+error: lifetime parameter `'b` never used
+  --> $DIR/unused-lifetime.rs:31:48
+   |
+LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) {
+   |                                                ^^
+
+error: lifetime parameter `'c` never used
+  --> $DIR/unused-lifetime.rs:37:54
+   |
+LL | pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) {
+   |                                                      ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr
index c72b9652360..740667f1466 100644
--- a/src/test/ui/bad/bad-method-typaram-kind.stderr
+++ b/src/test/ui/bad/bad-method-typaram-kind.stderr
@@ -1,11 +1,12 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/bad-method-typaram-kind.rs:2:7
    |
+LL | fn foo<T:'static>() {
+   |        -- help: consider further restricting this bound: `T: std::marker::Send +`
 LL |     1.bar::<T>();
    |       ^^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs b/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
index ea4a9e5afa5..4e0a238c5d4 100644
--- a/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
+++ b/src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
@@ -2,7 +2,7 @@
 // Check that partially moved from function parameters are dropped after the
 // named bindings that move from them.
 
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 use std::{panic, cell::RefCell};
 
diff --git a/src/test/ui/binding/match-arm-statics.rs b/src/test/ui/binding/match-arm-statics.rs
index 5f7e357eeb2..e6d17def147 100644
--- a/src/test/ui/binding/match-arm-statics.rs
+++ b/src/test/ui/binding/match-arm-statics.rs
@@ -1,6 +1,7 @@
 // run-pass
 #![allow(dead_code)]
 // compile-flags: -g
+// ignore-asmjs wasm2js does not support source maps yet
 
 #[derive(PartialEq, Eq)]
 struct NewBool(bool);
diff --git a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
index 4c7c0d1a0df..52d43eae658 100644
--- a/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
+++ b/src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
@@ -24,12 +24,12 @@ LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d
    |
    = note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
               found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
-note: the lifetime 'c as defined on the method body at 27:24...
+note: the lifetime `'c` as defined on the method body at 27:24...
   --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
    |
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
    |                        ^^
-note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 27:24
+note: ...does not necessarily outlive the lifetime `'c` as defined on the method body at 27:24
   --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24
    |
 LL |     fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
diff --git a/src/test/ui/builtin-clone-unwind.rs b/src/test/ui/builtin-clone-unwind.rs
index 339bcfa1060..1fd91440a78 100644
--- a/src/test/ui/builtin-clone-unwind.rs
+++ b/src/test/ui/builtin-clone-unwind.rs
@@ -2,7 +2,7 @@
 
 #![allow(unused_variables)]
 #![allow(unused_imports)]
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 // Test that builtin implementations of `Clone` cleanup everything
 // in case of unwinding.
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
index 9771436d167..5be6ab05d66 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr
@@ -2,20 +2,22 @@ error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/builtin-superkinds-double-superkind.rs:6:24
    |
 LL | impl <T: Sync+'static> Foo for (T,) { }
-   |                        ^^^ `T` cannot be sent between threads safely
+   |       --               ^^^ `T` cannot be sent between threads safely
+   |       |
+   |       help: consider further restricting this bound: `T: std::marker::Send +`
    |
    = help: within `(T,)`, the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because it appears within the type `(T,)`
 
 error[E0277]: `T` cannot be shared between threads safely
   --> $DIR/builtin-superkinds-double-superkind.rs:9:16
    |
 LL | impl <T: Send> Foo for (T,T) { }
-   |                ^^^ `T` cannot be shared between threads safely
+   |       --       ^^^ `T` cannot be shared between threads safely
+   |       |
+   |       help: consider further restricting this bound: `T: std::marker::Sync +`
    |
    = help: within `(T, T)`, the trait `std::marker::Sync` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Sync` bound
    = note: required because it appears within the type `(T, T)`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
index 61c18a24fb0..8cce9bfdf52 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr
@@ -2,10 +2,11 @@ error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/builtin-superkinds-in-metadata.rs:13:23
    |
 LL | impl <T:Sync+'static> RequiresRequiresShareAndSend for X<T> { }
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely
+   |       --              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `T` cannot be sent between threads safely
+   |       |
+   |       help: consider further restricting this bound: `T: std::marker::Send +`
    |
    = help: within `X<T>`, the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because it appears within the type `X<T>`
 
 error: aborting due to previous error
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
index dc5479e5e2d..4381a5b8682 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr
@@ -2,10 +2,11 @@ error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/builtin-superkinds-typaram-not-send.rs:5:24
    |
 LL | impl <T: Sync+'static> Foo for T { }
-   |                        ^^^ `T` cannot be sent between threads safely
+   |       --               ^^^ `T` cannot be sent between threads safely
+   |       |
+   |       help: consider further restricting this bound: `T: std::marker::Send +`
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index 3d552f88ba6..05535659161 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -14,7 +14,7 @@ LL |   pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<
 LL | |     ap
 LL | | }
    | |_^
-note: ...does not necessarily outlive the lifetime 'f as defined on the function body at 7:37
+note: ...does not necessarily outlive the lifetime `'f` as defined on the function body at 7:37
   --> $DIR/variadic-ffi-4.rs:7:37
    |
 LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> {
diff --git a/src/test/ui/catch-unwind-bang.rs b/src/test/ui/catch-unwind-bang.rs
index f181991713b..c2c21bca7ef 100644
--- a/src/test/ui/catch-unwind-bang.rs
+++ b/src/test/ui/catch-unwind-bang.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 fn worker() -> ! {
     panic!()
diff --git a/src/test/ui/check_match/issue-43253.rs b/src/test/ui/check_match/issue-43253.rs
index a4d6e9b777f..5c6834459f0 100644
--- a/src/test/ui/check_match/issue-43253.rs
+++ b/src/test/ui/check_match/issue-43253.rs
@@ -1,7 +1,7 @@
-// build-pass (FIXME(62277): could be check-pass?)
-
+// check-pass
 #![feature(exclusive_range_pattern)]
 #![warn(unreachable_patterns)]
+#![warn(overlapping_patterns)]
 
 fn main() {
     // These cases should generate no warning.
@@ -13,7 +13,7 @@ fn main() {
 
     match 10 {
         1..10 => {},
-        9..=10 => {},
+        9..=10 => {}, //~ WARNING multiple patterns covering the same range
         _ => {},
     }
 
@@ -23,22 +23,25 @@ fn main() {
         _ => {},
     }
 
-    // These cases should generate an "unreachable pattern" warning.
+    // These cases should generate "unreachable pattern" warnings.
     match 10 {
         1..10 => {},
-        9 => {},
+        9 => {}, //~ WARNING unreachable pattern
         _ => {},
     }
 
     match 10 {
         1..10 => {},
-        8..=9 => {},
+        8..=9 => {}, //~ WARNING multiple patterns covering the same range
         _ => {},
     }
 
     match 10 {
-        1..10 => {},
-        9..=9 => {},
+        5..7 => {},
+        6 => {}, //~ WARNING unreachable pattern
+        1..10 => {}, //~ WARNING multiple patterns covering the same range
+        9..=9 => {}, //~ WARNING unreachable pattern
+        6 => {}, //~ WARNING unreachable pattern
         _ => {},
     }
 }
diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr
index d961f623e1f..cb4a0486eef 100644
--- a/src/test/ui/check_match/issue-43253.stderr
+++ b/src/test/ui/check_match/issue-43253.stderr
@@ -1,3 +1,17 @@
+warning: multiple patterns covering the same range
+  --> $DIR/issue-43253.rs:16:9
+   |
+LL |         1..10 => {},
+   |         ----- this range overlaps on `9i32`
+LL |         9..=10 => {},
+   |         ^^^^^^ overlapping patterns
+   |
+note: lint level defined here
+  --> $DIR/issue-43253.rs:4:9
+   |
+LL | #![warn(overlapping_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
 warning: unreachable pattern
   --> $DIR/issue-43253.rs:29:9
    |
@@ -5,7 +19,7 @@ LL |         9 => {},
    |         ^
    |
 note: lint level defined here
-  --> $DIR/issue-43253.rs:4:9
+  --> $DIR/issue-43253.rs:3:9
    |
 LL | #![warn(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -19,6 +33,18 @@ LL |         8..=9 => {},
 warning: unreachable pattern
   --> $DIR/issue-43253.rs:41:9
    |
+LL |         6 => {},
+   |         ^
+
+warning: unreachable pattern
+  --> $DIR/issue-43253.rs:43:9
+   |
 LL |         9..=9 => {},
    |         ^^^^^
 
+warning: unreachable pattern
+  --> $DIR/issue-43253.rs:44:9
+   |
+LL |         6 => {},
+   |         ^
+
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
index ac4666fe36d..8af7f882cc2 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
@@ -11,7 +11,7 @@ note: the anonymous lifetime #2 defined on the body at 14:48...
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 11:36
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36
   --> $DIR/expect-fn-supply-fn.rs:11:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
@@ -25,7 +25,7 @@ LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |
    = note: expected type `fn(&u32)`
               found type `fn(&'x u32)`
-note: the lifetime 'x as defined on the function body at 11:36...
+note: the lifetime `'x` as defined on the function body at 11:36...
   --> $DIR/expect-fn-supply-fn.rs:11:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
index 51077b1b292..3c8f637e133 100644
--- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
+++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr
@@ -4,14 +4,16 @@ error[E0277]: `F` cannot be sent between threads safely
 LL |   struct X<F> where F: FnOnce() + 'static + Send {
    |   ---------------------------------------------- required by `X`
 ...
-LL | / fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static {
+LL |   fn foo<F>(blk: F) -> X<F> where F: FnOnce() + 'static {
+   |   ^                                                    - help: consider further restricting type parameter `F`: `, F: std::marker::Send`
+   |  _|
+   | |
 LL | |
 LL | |     return X { field: blk };
 LL | | }
    | |_^ `F` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `F`
-   = help: consider adding a `where F: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr
index 4b703eded69..05d5bb1e8d5 100644
--- a/src/test/ui/closures/closure-bounds-subtype.stderr
+++ b/src/test/ui/closures/closure-bounds-subtype.stderr
@@ -4,11 +4,13 @@ error[E0277]: `F` cannot be shared between threads safely
 LL | fn take_const_owned<F>(_: F) where F: FnOnce() + Sync + Send {
    |    ----------------                              ---- required by this bound in `take_const_owned`
 ...
+LL | fn give_owned<F>(f: F) where F: FnOnce() + Send {
+   |                                                - help: consider further restricting type parameter `F`: `, F: std::marker::Sync`
+LL |     take_any(f);
 LL |     take_const_owned(f);
    |                      ^ `F` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `F`
-   = help: consider adding a `where F: std::marker::Sync` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr
index e3b623d5524..9f74738315a 100644
--- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr
@@ -38,7 +38,7 @@ LL | |
 LL | |
 LL | |     });
    | |_____^
-note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 32:30
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 32:30
   --> $DIR/expect-region-supply-region.rs:32:30
    |
 LL | fn expect_bound_supply_named<'x>() {
@@ -52,7 +52,7 @@ LL |     closure_expecting_bound(|x: &'x u32| {
    |
    = note: expected type `&u32`
               found type `&'x u32`
-note: the lifetime 'x as defined on the function body at 32:30...
+note: the lifetime `'x` as defined on the function body at 32:30...
   --> $DIR/expect-region-supply-region.rs:32:30
    |
 LL | fn expect_bound_supply_named<'x>() {
diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs
new file mode 100644
index 00000000000..5cae0e76d1a
--- /dev/null
+++ b/src/test/ui/closures/issue-41366.rs
@@ -0,0 +1,13 @@
+trait T<'x> {
+    type V;
+}
+
+impl<'g> T<'g> for u32 {
+    type V = u16;
+}
+
+fn main() {
+    (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+    //~^ ERROR: type mismatch in closure arguments
+    //~| ERROR: type mismatch resolving
+}
diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr
new file mode 100644
index 00000000000..91d26efbc4f
--- /dev/null
+++ b/src/test/ui/closures/issue-41366.stderr
@@ -0,0 +1,22 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/issue-41366.rs:10:5
+   |
+LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |     ^^-----^
+   |     | |
+   |     | found signature of `fn(_) -> _`
+   |     expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
+   |
+   = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
+
+error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()`
+  --> $DIR/issue-41366.rs:10:5
+   |
+LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |     ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |
+   = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs
new file mode 100644
index 00000000000..6ac5380a5aa
--- /dev/null
+++ b/src/test/ui/closures/issue-52437.rs
@@ -0,0 +1,5 @@
+fn main() {
+    [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
+    //~^ ERROR: invalid label name `'static`
+    //~| ERROR: type annotations needed
+}
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
new file mode 100644
index 00000000000..e76f942e9ba
--- /dev/null
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -0,0 +1,15 @@
+error: invalid label name `'static`
+  --> $DIR/issue-52437.rs:2:13
+   |
+LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
+   |             ^^^^^^^
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-52437.rs:2:30
+   |
+LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
+   |                              ^ consider giving this closure parameter a type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
index f005245e6dc..5038eb3ebf4 100644
--- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs
+++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(never_type)]
 #![allow(unreachable_code)]
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.rs b/src/test/ui/coherence/impl-foreign-for-foreign.rs
new file mode 100644
index 00000000000..de0b66a35eb
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign.rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for i32 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.stderr b/src/test/ui/coherence/impl-foreign-for-foreign.stderr
new file mode 100644
index 00000000000..b03a75a77c3
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign.stderr
@@ -0,0 +1,12 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign-for-foreign.rs:12:1
+   |
+LL | impl Remote for i32 {
+   | ^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs
new file mode 100644
index 00000000000..5146263d991
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs
@@ -0,0 +1,25 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote1<Rc<i32>> for i32 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+impl Remote1<Rc<Local>> for f64 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+impl<T> Remote1<Rc<T>> for f32 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr
new file mode 100644
index 00000000000..bfaec790b20
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr
@@ -0,0 +1,30 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign-for-foreign[foreign].rs:12:1
+   |
+LL | impl Remote1<Rc<i32>> for i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign-for-foreign[foreign].rs:16:1
+   |
+LL | impl Remote1<Rc<Local>> for f64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign-for-foreign[foreign].rs:20:1
+   |
+LL | impl<T> Remote1<Rc<T>> for f32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[local].rs b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs
new file mode 100644
index 00000000000..050769dcf4c
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs
@@ -0,0 +1,16 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local<T>(Rc<T>);
+
+impl Remote1<Local<i32>> for i32 {}
+impl<T> Remote1<Local<T>> for f32 {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs
new file mode 100644
index 00000000000..03b11edf98b
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs
@@ -0,0 +1,21 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for Box<i32> {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+impl<T> Remote for Box<Rc<T>> {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr
new file mode 100644
index 00000000000..2ce4921cf93
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr
@@ -0,0 +1,21 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign-for-fundamental[foreign].rs:12:1
+   |
+LL | impl Remote for Box<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign-for-fundamental[foreign].rs:16:1
+   |
+LL | impl<T> Remote for Box<Rc<T>> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs
new file mode 100644
index 00000000000..ae03ce6a440
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1<T>(Rc<T>);
+
+impl Remote for Box<Local> {}
+impl<T> Remote for Box<Local1<T>> {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-local.rs b/src/test/ui/coherence/impl-foreign-for-local.rs
new file mode 100644
index 00000000000..c9dddeba18d
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-local.rs
@@ -0,0 +1,15 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for Local {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs
new file mode 100644
index 00000000000..06efb6c2ad7
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs
@@ -0,0 +1,26 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1<T>(Rc<T>);
+
+impl Remote1<Box<String>> for i32 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+impl Remote1<Box<Rc<i32>>> for f64 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+impl<T> Remote1<Box<Rc<T>>> for f32 {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr
new file mode 100644
index 00000000000..bf2361a1718
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr
@@ -0,0 +1,30 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:13:1
+   |
+LL | impl Remote1<Box<String>> for i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:17:1
+   |
+LL | impl Remote1<Box<Rc<i32>>> for f64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:21:1
+   |
+LL | impl<T> Remote1<Box<Rc<T>>> for f32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs
new file mode 100644
index 00000000000..d47e0a36a56
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs
@@ -0,0 +1,18 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1<T>(Rc<T>);
+
+impl Remote1<Box<Local>> for i32 {}
+impl Remote1<Box<Local1<i32>>> for f64 {}
+impl<T> Remote1<Box<Local1<T>>> for f32 {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs
new file mode 100644
index 00000000000..db7a2ae8076
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs
@@ -0,0 +1,23 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+use std::sync::Arc;
+
+struct Local;
+
+impl Remote for Rc<Local> {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+
+impl<T> Remote for Arc<T> {
+    //~^ ERROR only traits defined in the current crate
+    // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr
new file mode 100644
index 00000000000..d7ffcaf76f9
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr
@@ -0,0 +1,21 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl[t]-foreign-for-foreign[t].rs:13:1
+   |
+LL | impl Remote for Rc<Local> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/impl[t]-foreign-for-foreign[t].rs:18:1
+   |
+LL | impl<T> Remote for Arc<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+   |
+   = note: the impl does not reference only types defined in this crate
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs
new file mode 100644
index 00000000000..4cc19e1a526
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl<T> Remote for Box<T> {
+    //~^ ERROR type parameter `T` must be used as the type parameter for
+    // | some local type (e.g., `MyStruct<T>`)
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr
new file mode 100644
index 00000000000..20ce11ef975
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr
@@ -0,0 +1,11 @@
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+  --> $DIR/impl[t]-foreign-for-fundamental[t].rs:12:1
+   |
+LL | impl<T> Remote for Box<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
+   |
+   = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0210`.
diff --git a/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs
new file mode 100644
index 00000000000..914680f191a
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1<S>(Rc<S>);
+
+impl<T> Remote1<Box<Local>> for Rc<T> {}
+impl<S, T> Remote1<Box<Local1<S>>> for Rc<T> {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs
new file mode 100644
index 00000000000..1e84ff40c62
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1<S>(Rc<S>);
+
+impl<T> Remote1<Local> for Rc<T> {}
+impl<T, S> Remote1<Local1<S>> for Rc<T> {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs
new file mode 100644
index 00000000000..ea6aa101d20
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs
@@ -0,0 +1,19 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1<S>(Rc<S>);
+
+impl<T> Remote1<Local> for Box<Rc<T>> {}
+impl<T, S> Remote1<Local1<S>> for Box<Rc<T>> {}
+impl<T> Remote1<Box<Local>> for Box<Rc<T>> {}
+impl<T, S> Remote1<Box<Local1<S>>> for Box<Rc<T>> {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs
new file mode 100644
index 00000000000..901fb5dd054
--- /dev/null
+++ b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs
@@ -0,0 +1,9 @@
+#![feature(const_generics)]
+
+pub struct Struct<const N: usize>(pub [u8; N]);
+
+pub type Alias = Struct<2>;
+
+pub fn function(value: Struct<3>) -> u8 {
+    value.0[0]
+}
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs
new file mode 100644
index 00000000000..d863d097d5c
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs
@@ -0,0 +1,10 @@
+// aux-build:const_generic_lib.rs
+
+extern crate const_generic_lib;
+
+fn main() {
+    let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
+    //~^ ERROR mismatched types
+    let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
new file mode 100644
index 00000000000..7090cb880fd
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/const-argument-cross-crate-mismatch.rs:6:67
+   |
+LL |     let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
+   |                                                                   ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
+   |
+   = note: expected type `[u8; 3]`
+              found type `[u8; 2]`
+
+error[E0308]: mismatched types
+  --> $DIR/const-argument-cross-crate-mismatch.rs:8:65
+   |
+LL |     let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
+   |                                                                 ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
+   |
+   = note: expected type `[u8; 2]`
+              found type `[u8; 3]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs
new file mode 100644
index 00000000000..98cf39a7ee1
--- /dev/null
+++ b/src/test/ui/const-generics/const-argument-cross-crate.rs
@@ -0,0 +1,12 @@
+// run-pass
+// aux-build:const_generic_lib.rs
+
+extern crate const_generic_lib;
+
+struct Container(const_generic_lib::Alias);
+
+fn main() {
+    let res = const_generic_lib::function(const_generic_lib::Struct([14u8, 1u8, 2u8]));
+    assert_eq!(res, 14u8);
+    let _ = Container(const_generic_lib::Struct([0u8, 1u8]));
+}
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
index fddb06981bc..32cf8d8a01a 100644
--- a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
@@ -10,7 +10,7 @@ error: const parameter `x` should have an upper case name
   --> $DIR/const-parameter-uppercase-lint.rs:6:15
    |
 LL | fn noop<const x: u32>() {
-   |               ^ help: convert the identifier to upper case: `X`
+   |               ^ help: convert the identifier to upper case (notice the capitalization): `X`
    |
 note: lint level defined here
   --> $DIR/const-parameter-uppercase-lint.rs:4:9
diff --git a/src/test/ui/const-generics/struct-with-invalid-const-param.stderr b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr
index dfa2557e9f6..b3aa35e079a 100644
--- a/src/test/ui/const-generics/struct-with-invalid-const-param.stderr
+++ b/src/test/ui/const-generics/struct-with-invalid-const-param.stderr
@@ -14,3 +14,4 @@ LL | #![feature(const_generics)]
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs
index ecbcc2a4b49..e5ee90fc9f1 100644
--- a/src/test/ui/consts/const-err2.rs
+++ b/src/test/ui/consts/const-err2.rs
@@ -23,6 +23,7 @@ fn main() {
     //~^ ERROR const_err
     let _e = [5u8][1];
     //~^ ERROR index out of bounds
+    //~| ERROR this expression will panic at runtime
     black_box(a);
     black_box(b);
     black_box(c);
diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr
index 1d84d44dc27..0a09a7213da 100644
--- a/src/test/ui/consts/const-err2.stderr
+++ b/src/test/ui/consts/const-err2.stderr
@@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1
 LL |     let _e = [5u8][1];
    |              ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: this expression will panic at runtime
+  --> $DIR/const-err2.rs:24:14
+   |
+LL |     let _e = [5u8][1];
+   |              ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
+error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs
index a9cf04cda7a..89373f99f75 100644
--- a/src/test/ui/consts/const-err3.rs
+++ b/src/test/ui/consts/const-err3.rs
@@ -23,6 +23,7 @@ fn main() {
     //~^ ERROR const_err
     let _e = [5u8][1];
     //~^ ERROR const_err
+    //~| ERROR this expression will panic at runtime
     black_box(a);
     black_box(b);
     black_box(c);
diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr
index 0602707be70..42de247c8f7 100644
--- a/src/test/ui/consts/const-err3.stderr
+++ b/src/test/ui/consts/const-err3.stderr
@@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1
 LL |     let _e = [5u8][1];
    |              ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: this expression will panic at runtime
+  --> $DIR/const-err3.rs:24:14
+   |
+LL |     let _e = [5u8][1];
+   |              ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
+error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/consts/const-eval/issue-65394.rs b/src/test/ui/consts/const-eval/issue-65394.rs
new file mode 100644
index 00000000000..8cf527f0429
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-65394.rs
@@ -0,0 +1,10 @@
+// Test for absence of validation mismatch ICE in #65394
+
+const _: Vec<i32> = {
+    let mut x = Vec::<i32>::new();
+    let r = &mut x; //~ ERROR references in constants may only refer to immutable values
+    let y = x;
+    y
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
new file mode 100644
index 00000000000..15df813836e
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -0,0 +1,11 @@
+error[E0017]: references in constants may only refer to immutable values
+  --> $DIR/issue-65394.rs:5:13
+   |
+LL |     let r = &mut x;
+   |             ^^^^^^ constants require immutable values
+
+[ERROR rustc_mir::transform::qualify_consts] old validator: [($DIR/issue-65394.rs:5:13: 5:19, "MutBorrow(Mut { allow_two_phase_borrow: false })")]
+[ERROR rustc_mir::transform::qualify_consts] new validator: [($DIR/issue-65394.rs:5:13: 5:19, "MutBorrow(Mut { allow_two_phase_borrow: false })"), ($DIR/issue-65394.rs:4:9: 4:14, "LiveDrop")]
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0017`.
diff --git a/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
new file mode 100644
index 00000000000..cccb7879fc0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+#![allow(dead_code)]
+
+enum Empty { }
+enum Test1 {
+    A(u8),
+    B(Empty),
+}
+enum Test2 {
+    A(u8),
+    B(Empty),
+    C,
+}
+
+fn bar() -> Option<Empty> {
+    None
+}
+
+fn main() {
+    if let Some(x) = bar() {
+        Test1::B(x);
+    }
+
+    if let Some(x) = bar() {
+        Test2::B(x);
+    }
+}
diff --git a/src/test/ui/consts/const-int-pow-rpass.rs b/src/test/ui/consts/const-int-pow-rpass.rs
new file mode 100644
index 00000000000..8e84a900605
--- /dev/null
+++ b/src/test/ui/consts/const-int-pow-rpass.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two();
+const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two();
+const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two();
+
+fn main() {
+    assert!(!IS_POWER_OF_TWO_A);
+    assert!(IS_POWER_OF_TWO_B);
+    assert!(!IS_POWER_OF_TWO_C);
+}
diff --git a/src/test/ui/consts/const-int-saturating-arith.rs b/src/test/ui/consts/const-int-saturating-arith.rs
index 394d6c17f5a..d0a3eccd177 100644
--- a/src/test/ui/consts/const-int-saturating-arith.rs
+++ b/src/test/ui/consts/const-int-saturating-arith.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-emscripten no i128 support
 #![feature(const_saturating_int_methods)]
 
 const INT_U32_NO: u32 = (42 as u32).saturating_add(2);
diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs
index 13309f978b6..48c4b7da942 100644
--- a/src/test/ui/consts/const-prop-ice.rs
+++ b/src/test/ui/consts/const-prop-ice.rs
@@ -1,3 +1,4 @@
 fn main() {
     [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3
+    //~| ERROR this expression will panic at runtime
 }
diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr
index 4b3880198bf..8ecc6f4bc6b 100644
--- a/src/test/ui/consts/const-prop-ice.stderr
+++ b/src/test/ui/consts/const-prop-ice.stderr
@@ -6,5 +6,11 @@ LL |     [0; 3][3u64 as usize];
    |
    = note: `#[deny(const_err)]` on by default
 
-error: aborting due to previous error
+error: this expression will panic at runtime
+  --> $DIR/const-prop-ice.rs:2:5
+   |
+LL |     [0; 3][3u64 as usize];
+   |     ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/issue-64506.rs b/src/test/ui/consts/issue-64506.rs
new file mode 100644
index 00000000000..db3e85a7bdf
--- /dev/null
+++ b/src/test/ui/consts/issue-64506.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#[derive(Copy, Clone)]
+pub struct ChildStdin {
+    inner: AnonPipe,
+}
+
+#[derive(Copy, Clone)]
+enum AnonPipe {}
+
+const FOO: () = {
+    union Foo {
+        a: ChildStdin,
+        b: (),
+    }
+    let x = unsafe { Foo { b: () }.a };
+    let x = &x.inner;
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-65348.rs b/src/test/ui/consts/issue-65348.rs
new file mode 100644
index 00000000000..5eafa831d63
--- /dev/null
+++ b/src/test/ui/consts/issue-65348.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+struct Generic<T>(T);
+
+impl<T> Generic<T> {
+    const ARRAY: [T; 0] = [];
+    const NEWTYPE_ARRAY: Generic<[T; 0]> = Generic([]);
+    const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, []));
+}
+
+pub const fn array<T>() ->  &'static T {
+    &Generic::<T>::ARRAY[0]
+}
+
+pub const fn newtype_array<T>() ->  &'static T {
+    &Generic::<T>::NEWTYPE_ARRAY.0[0]
+}
+
+pub const fn array_field<T>() ->  &'static T {
+    &(Generic::<T>::ARRAY_FIELD.0).1[0]
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
new file mode 100644
index 00000000000..e1ac4306575
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
@@ -0,0 +1,13 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![warn(const_err)]
+
+// A test demonstrating that we prevent calling non-const fn during CTFE.
+
+fn foo() {}
+
+const C: () = foo(); //~ WARN: skipping const checks
+//~^ WARN any use of this value will cause an error
+
+fn main() {
+    println!("{:?}", C); //~ ERROR: evaluation of constant expression failed
+}
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
new file mode 100644
index 00000000000..7a574b34304
--- /dev/null
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
@@ -0,0 +1,29 @@
+warning: skipping const checks
+  --> $DIR/non_const_fn.rs:8:15
+   |
+LL | const C: () = foo();
+   |               ^^^^^
+
+warning: any use of this value will cause an error
+  --> $DIR/non_const_fn.rs:8:15
+   |
+LL | const C: () = foo();
+   | --------------^^^^^-
+   |               |
+   |               calling non-const function `foo`
+   |
+note: lint level defined here
+  --> $DIR/non_const_fn.rs:2:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
+
+error[E0080]: evaluation of constant expression failed
+  --> $DIR/non_const_fn.rs:12:22
+   |
+LL |     println!("{:?}", C);
+   |                      ^ referenced constant has errors
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr
index 0733a51233e..2fb9977f4d7 100644
--- a/src/test/ui/consts/too_generic_eval_ice.stderr
+++ b/src/test/ui/consts/too_generic_eval_ice.stderr
@@ -16,26 +16,30 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim
    |
 LL | pub struct Foo<A, B>(A, B);
    | --------------------------- required by `Foo`
+LL | 
+LL | impl<A, B> Foo<A, B> {
+   |      - help: consider restricting this bound: `A: std::marker::Sized`
 ...
 LL |         [5; Self::HOST_SIZE] == [6; 0]
    |             ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `A`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where A: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `B` cannot be known at compilation time
   --> $DIR/too_generic_eval_ice.rs:7:13
    |
 LL | pub struct Foo<A, B>(A, B);
    | --------------------------- required by `Foo`
+LL | 
+LL | impl<A, B> Foo<A, B> {
+   |         - help: consider restricting this bound: `B: std::marker::Sized`
 ...
 LL |         [5; Self::HOST_SIZE] == [6; 0]
    |             ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `B`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where B: std::marker::Sized` bound
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/debuginfo-lto.rs b/src/test/ui/debuginfo-lto.rs
index e4beee9e737..43f75b0344b 100644
--- a/src/test/ui/debuginfo-lto.rs
+++ b/src/test/ui/debuginfo-lto.rs
@@ -7,6 +7,7 @@
 // aux-build:debuginfo-lto-aux.rs
 // compile-flags: -C lto -g
 // no-prefer-dynamic
+// ignore-asmjs wasm2js does not support source maps yet
 
 extern crate debuginfo_lto_aux;
 
diff --git a/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr b/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr
index 84235ca4d63..79bc7d2565b 100644
--- a/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr
+++ b/src/test/ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.stderr
@@ -2,7 +2,7 @@ error: `~` cannot be used as a unary operator
   --> $DIR/issue-41679-tilde-bitwise-negation-attempt.rs:2:13
    |
 LL |     let x = ~1;
-   |             ^ help: use `!` to perform bitwise negation
+   |             ^ help: use `!` to perform bitwise not
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
index d8826d4072a..ef68bf52cf3 100644
--- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
+++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
@@ -55,7 +55,7 @@ LL |     let z = ManyVariants::Three();
    |             ^^^^^^^^^^^^^^^^^^^
 LL |     let z = ManyVariants::Four();
    |             ^^^^^^^^^^^^^^^^^^
-and 6 other candidates
+     and 6 other candidates
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
index 8d3a86df023..cb350a1faee 100644
--- a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
+++ b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
@@ -13,7 +13,7 @@ LL | fn setup() -> Determine { Set }
    |               ^^^^^^^^^
 LL | fn setup() -> PutDown { Set }
    |               ^^^^^^^
-and 3 other candidates
+     and 3 other candidates
 
 error[E0425]: cannot find value `Set` in this scope
   --> $DIR/issue-56028-there-is-an-enum-variant.rs:9:21
@@ -30,7 +30,7 @@ LL | use Determine::Set;
    |
 LL | use PutDown::Set;
    |
-and 3 other candidates
+     and 3 other candidates
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs
index 91063edf0f6..bec86d6465a 100644
--- a/src/test/ui/drop/dynamic-drop-async.rs
+++ b/src/test/ui/drop/dynamic-drop-async.rs
@@ -5,7 +5,7 @@
 
 // run-pass
 // edition:2018
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(slice_patterns)]
 #![allow(unused)]
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 8516bc3d964..5a7568fe2cd 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -2,12 +2,13 @@
 #![allow(unused_assignments)]
 #![allow(unused_variables)]
 
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(generators, generator_trait, untagged_unions)]
 #![feature(slice_patterns)]
 
 use std::cell::{Cell, RefCell};
+use std::mem::ManuallyDrop;
 use std::ops::Generator;
 use std::panic;
 use std::pin::Pin;
@@ -152,17 +153,16 @@ fn assignment1(a: &Allocator, c0: bool) {
     _v = _w;
 }
 
-#[allow(unions_with_drop_fields)]
 union Boxy<T> {
-    a: T,
-    b: T,
+    a: ManuallyDrop<T>,
+    b: ManuallyDrop<T>,
 }
 
 fn union1(a: &Allocator) {
     unsafe {
-        let mut u = Boxy { a: a.alloc() };
-        u.b = a.alloc();
-        drop(u.a);
+        let mut u = Boxy { a: ManuallyDrop::new(a.alloc()) };
+        *u.b = a.alloc(); // drops first alloc
+        drop(ManuallyDrop::into_inner(u.a));
     }
 }
 
diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr
index 55ac625fc98..40db575eabd 100644
--- a/src/test/ui/dst/dst-object-from-unsized-type.stderr
+++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr
@@ -1,23 +1,25 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/dst-object-from-unsized-type.rs:8:23
    |
+LL | fn test1<T: ?Sized + Foo>(t: &T) {
+   |          -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     let u: &dyn Foo = t;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/dst-object-from-unsized-type.rs:13:23
    |
+LL | fn test2<T: ?Sized + Foo>(t: &T) {
+   |          -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     let v: &dyn Foo = t as &dyn Foo;
    |                       ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: required for the cast to the object type `dyn Foo`
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
diff --git a/src/test/ui/enum/enum-variant-type-2.stderr b/src/test/ui/enum/enum-variant-type-2.stderr
index 65c45d9bad0..7e8453c61f6 100644
--- a/src/test/ui/enum/enum-variant-type-2.stderr
+++ b/src/test/ui/enum/enum-variant-type-2.stderr
@@ -9,3 +9,4 @@ LL | fn foo(x: Foo::Bar) {}
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr
index ce631ca4bf7..754006bc217 100644
--- a/src/test/ui/error-codes/E0423.stderr
+++ b/src/test/ui/error-codes/E0423.stderr
@@ -34,7 +34,7 @@ LL |     let f = Foo();
    |             ^^^
    |             |
    |             did you mean `Foo { /* fields */ }`?
-   |             help: a function with a similar name exists: `foo`
+   |             help: a function with a similar name exists (notice the capitalization): `foo`
 
 error[E0423]: expected value, found struct `T`
   --> $DIR/E0423.rs:14:8
diff --git a/src/test/ui/error-codes/E0424.stderr b/src/test/ui/error-codes/E0424.stderr
index d67a2660dac..567d1b3cc75 100644
--- a/src/test/ui/error-codes/E0424.stderr
+++ b/src/test/ui/error-codes/E0424.stderr
@@ -1,14 +1,20 @@
 error[E0424]: expected value, found module `self`
   --> $DIR/E0424.rs:7:9
    |
-LL |         self.bar();
-   |         ^^^^ `self` value is a keyword only available in methods with `self` parameter
+LL | /     fn foo() {
+LL | |         self.bar();
+   | |         ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+LL | |     }
+   | |_____- this function doesn't have a `self` parameter
 
 error[E0424]: expected unit struct/variant or constant, found module `self`
   --> $DIR/E0424.rs:12:9
    |
-LL |     let self = "self";
-   |         ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
+LL | / fn main () {
+LL | |     let self = "self";
+   | |         ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
+LL | | }
+   | |_- this function doesn't have a `self` parameter
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0478.stderr b/src/test/ui/error-codes/E0478.stderr
index 587125fdc33..1380840e0db 100644
--- a/src/test/ui/error-codes/E0478.stderr
+++ b/src/test/ui/error-codes/E0478.stderr
@@ -4,12 +4,12 @@ error[E0478]: lifetime bound not satisfied
 LL |     child: Box<dyn Wedding<'kiss> + 'SnowWhite>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: lifetime parameter instantiated with the lifetime 'SnowWhite as defined on the struct at 3:22
+note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined on the struct at 3:22
   --> $DIR/E0478.rs:3:22
    |
 LL | struct Prince<'kiss, 'SnowWhite> {
    |                      ^^^^^^^^^^
-note: but lifetime parameter must outlive the lifetime 'kiss as defined on the struct at 3:15
+note: but lifetime parameter must outlive the lifetime `'kiss` as defined on the struct at 3:15
   --> $DIR/E0478.rs:3:15
    |
 LL | struct Prince<'kiss, 'SnowWhite> {
diff --git a/src/test/ui/exhaustive_integer_patterns.rs b/src/test/ui/exhaustive_integer_patterns.rs
index 2570bc8a560..59f74919897 100644
--- a/src/test/ui/exhaustive_integer_patterns.rs
+++ b/src/test/ui/exhaustive_integer_patterns.rs
@@ -1,7 +1,7 @@
 #![feature(precise_pointer_size_matching)]
 #![feature(exclusive_range_pattern)]
-
 #![deny(unreachable_patterns)]
+#![deny(overlapping_patterns)]
 
 use std::{char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128};
 
@@ -41,7 +41,8 @@ fn main() {
     match x { //~ ERROR non-exhaustive patterns
         -7 => {}
         -5..=120 => {}
-        -2..=20 => {} //~ ERROR unreachable pattern
+        -2..=20 => {}
+        //~^ ERROR unreachable pattern
         125 => {}
     }
 
@@ -135,9 +136,9 @@ fn main() {
         (125 .. 128, false) => {}
     }
 
-    match 0u8 { // ok
+    match 0u8 {
         0 .. 2 => {}
-        1 ..= 2 => {}
+        1 ..= 2 => {} //~ ERROR multiple patterns covering the same range
         _ => {}
     }
 
diff --git a/src/test/ui/exhaustive_integer_patterns.stderr b/src/test/ui/exhaustive_integer_patterns.stderr
index 6c4b7b0cc03..7a3a36a820c 100644
--- a/src/test/ui/exhaustive_integer_patterns.stderr
+++ b/src/test/ui/exhaustive_integer_patterns.stderr
@@ -5,7 +5,7 @@ LL |         200 => {}
    |         ^^^
    |
 note: lint level defined here
-  --> $DIR/exhaustive_integer_patterns.rs:4:9
+  --> $DIR/exhaustive_integer_patterns.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     match x {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `std::i8::MIN` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:82:11
+  --> $DIR/exhaustive_integer_patterns.rs:83:11
    |
 LL |     match 0i8 {
    |           ^^^ pattern `std::i8::MIN` not covered
@@ -49,7 +49,7 @@ LL |     match 0i8 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `0i16` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:90:11
+  --> $DIR/exhaustive_integer_patterns.rs:91:11
    |
 LL |     match 0i16 {
    |           ^^^^ pattern `0i16` not covered
@@ -57,7 +57,7 @@ LL |     match 0i16 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `128u8..=std::u8::MAX` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:108:11
+  --> $DIR/exhaustive_integer_patterns.rs:109:11
    |
 LL |     match 0u8 {
    |           ^^^ pattern `128u8..=std::u8::MAX` not covered
@@ -65,7 +65,7 @@ LL |     match 0u8 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:120:11
+  --> $DIR/exhaustive_integer_patterns.rs:121:11
    |
 LL |     match (0u8, Some(())) {
    |           ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=std::u8::MAX, Some(_))` not covered
@@ -73,15 +73,29 @@ LL |     match (0u8, Some(())) {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:125:11
+  --> $DIR/exhaustive_integer_patterns.rs:126:11
    |
 LL |     match (0u8, true) {
    |           ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
+error: multiple patterns covering the same range
+  --> $DIR/exhaustive_integer_patterns.rs:141:9
+   |
+LL |         0 .. 2 => {}
+   |         ------ this range overlaps on `1u8`
+LL |         1 ..= 2 => {}
+   |         ^^^^^^^ overlapping patterns
+   |
+note: lint level defined here
+  --> $DIR/exhaustive_integer_patterns.rs:4:9
+   |
+LL | #![deny(overlapping_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
 error[E0004]: non-exhaustive patterns: `std::u128::MAX` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:145:11
+  --> $DIR/exhaustive_integer_patterns.rs:146:11
    |
 LL |     match 0u128 {
    |           ^^^^^ pattern `std::u128::MAX` not covered
@@ -89,7 +103,7 @@ LL |     match 0u128 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `5u128..=std::u128::MAX` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:149:11
+  --> $DIR/exhaustive_integer_patterns.rs:150:11
    |
 LL |     match 0u128 {
    |           ^^^^^ pattern `5u128..=std::u128::MAX` not covered
@@ -97,13 +111,13 @@ LL |     match 0u128 {
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered
-  --> $DIR/exhaustive_integer_patterns.rs:153:11
+  --> $DIR/exhaustive_integer_patterns.rs:154:11
    |
 LL |     match 0u128 {
    |           ^^^^^ pattern `0u128..=3u128` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr b/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr
index 4bf2d573d4f..cbd6422e5df 100644
--- a/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr
+++ b/src/test/ui/explicit/explicit-self-lifetime-mismatch.stderr
@@ -6,12 +6,12 @@ LL |            Foo<'b,'a>
    |
    = note: expected type `Foo<'a, 'b>`
               found type `Foo<'b, 'a>`
-note: the lifetime 'b as defined on the impl at 6:9...
+note: the lifetime `'b` as defined on the impl at 6:9...
   --> $DIR/explicit-self-lifetime-mismatch.rs:6:9
    |
 LL | impl<'a,'b> Foo<'a,'b> {
    |         ^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 6:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 6:6
   --> $DIR/explicit-self-lifetime-mismatch.rs:6:6
    |
 LL | impl<'a,'b> Foo<'a,'b> {
@@ -25,12 +25,12 @@ LL |            Foo<'b,'a>
    |
    = note: expected type `Foo<'a, 'b>`
               found type `Foo<'b, 'a>`
-note: the lifetime 'a as defined on the impl at 6:6...
+note: the lifetime `'a` as defined on the impl at 6:6...
   --> $DIR/explicit-self-lifetime-mismatch.rs:6:6
    |
 LL | impl<'a,'b> Foo<'a,'b> {
    |      ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 6:9
+note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 6:9
   --> $DIR/explicit-self-lifetime-mismatch.rs:6:9
    |
 LL | impl<'a,'b> Foo<'a,'b> {
diff --git a/src/test/ui/expr_attr_paren_order.stderr b/src/test/ui/expr_attr_paren_order.stderr
index 89f615f53dd..57a9350c089 100644
--- a/src/test/ui/expr_attr_paren_order.stderr
+++ b/src/test/ui/expr_attr_paren_order.stderr
@@ -2,7 +2,7 @@ error: variable `X` should have a snake case name
   --> $DIR/expr_attr_paren_order.rs:19:17
    |
 LL |             let X = 0;
-   |                 ^ help: convert the identifier to snake case: `x`
+   |                 ^ help: convert the identifier to snake case (notice the capitalization): `x`
    |
 note: lint level defined here
   --> $DIR/expr_attr_paren_order.rs:17:17
diff --git a/src/test/ui/extern/extern-const.fixed b/src/test/ui/extern/extern-const.fixed
index 0eec9fb3ee6..9d96b4f63fb 100644
--- a/src/test/ui/extern/extern-const.fixed
+++ b/src/test/ui/extern/extern-const.fixed
@@ -5,7 +5,8 @@
 // compile. To sidestep this by using one that *is* defined.
 
 // run-rustfix
-// ignore-wasm32 no external library to link to.
+// ignore-wasm32-bare no external library to link to.
+// ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g
 #![feature(rustc_private)]
 extern crate libc;
diff --git a/src/test/ui/extern/extern-const.rs b/src/test/ui/extern/extern-const.rs
index ca5d7ddf27e..7cef5b3497b 100644
--- a/src/test/ui/extern/extern-const.rs
+++ b/src/test/ui/extern/extern-const.rs
@@ -5,7 +5,8 @@
 // compile. To sidestep this by using one that *is* defined.
 
 // run-rustfix
-// ignore-wasm32 no external library to link to.
+// ignore-wasm32-bare no external library to link to.
+// ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g
 #![feature(rustc_private)]
 extern crate libc;
diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr
index 77406be2095..258202b6903 100644
--- a/src/test/ui/extern/extern-const.stderr
+++ b/src/test/ui/extern/extern-const.stderr
@@ -1,5 +1,5 @@
 error: extern items cannot be `const`
-  --> $DIR/extern-const.rs:15:5
+  --> $DIR/extern-const.rs:16:5
    |
 LL |     const rust_dbg_static_mut: libc::c_int;
    |     ^^^^^ help: try using a static value: `static`
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
index 62a6d97dfe8..e78d9840abf 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
@@ -186,43 +186,43 @@ LL |     mod inner { #![macro_escape] }
    |
    = help: consider an outer attribute, `#[macro_use]` mod ...
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17
    |
 LL |     mod inner { #![plugin_registrar] }
-   |                 ^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |                 ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5
    |
 LL |     #[plugin_registrar] struct S;
-   |     ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |     ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5
    |
 LL |     #[plugin_registrar] type T = S;
-   |     ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |     ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:5
    |
 LL |     #[plugin_registrar] impl S { }
-   |     ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |     ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1
    |
 LL | #[plugin_registrar]
-   | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1
    |
 LL | #![plugin_registrar]
-   | ^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 warning: use of deprecated attribute `crate_id`: no longer used.
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:1
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
index 3d75251e156..0faa9090f4e 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -1,7 +1,7 @@
 #![feature(untagged_unions)]
 
-trait Tr1 { type As1; }
-trait Tr2 { type As2; }
+trait Tr1 { type As1: Copy; }
+trait Tr2 { type As2: Copy; }
 
 struct S1;
 #[derive(Copy, Clone)]
@@ -32,7 +32,7 @@ enum _En1<T: Tr1<As1: Tr2>> {
 
 union _Un1<T: Tr1<As1: Tr2>> {
 //~^ ERROR associated type bounds are unstable
-    outest: T,
+    outest: std::mem::ManuallyDrop<T>,
     outer: T::As1,
     inner: <T::As1 as Tr2>::As2,
 }
diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs
index 27ff5ace25d..f0cc9ea7055 100644
--- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs
+++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs
@@ -1,4 +1,5 @@
 #![feature(never_type)]
+
 fn foo() -> Result<u32, !> {
     Ok(123)
 }
diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
index d77fbc1e823..08c36cece4c 100644
--- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
+++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding: `Err(_)` not covered
-  --> $DIR/feature-gate-exhaustive-patterns.rs:7:9
+  --> $DIR/feature-gate-exhaustive-patterns.rs:8:9
    |
 LL |     let Ok(_x) = foo();
    |         ^^^^^^ pattern `Err(_)` not covered
diff --git a/src/test/ui/feature-gates/feature-gate-plugin.stderr b/src/test/ui/feature-gates/feature-gate-plugin.stderr
index d1eee8cc588..f89ddf995c4 100644
--- a/src/test/ui/feature-gates/feature-gate-plugin.stderr
+++ b/src/test/ui/feature-gates/feature-gate-plugin.stderr
@@ -7,11 +7,11 @@ LL | #![plugin(foo)]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29597
    = help: add `#![feature(plugin)]` to the crate attributes to enable
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/feature-gate-plugin.rs:3:1
    |
 LL | #![plugin(foo)]
-   | ^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr
index 1c4ccac1dcf..4856cf7c3f7 100644
--- a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr
+++ b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr
@@ -16,11 +16,11 @@ LL | #[plugin_registrar]
    = note: for more information, see https://github.com/rust-lang/rust/issues/29597
    = help: add `#![feature(plugin_registrar)]` to the crate attributes to enable
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/feature-gate-plugin_registrar.rs:5:1
    |
 LL | #[plugin_registrar]
-   | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
index 3bac3d853e9..9ee0e6f681d 100644
--- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
+++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
@@ -7,11 +7,11 @@ union U2<T: Copy> { // OK
 }
 
 union U3 { //~ ERROR unions with non-`Copy` fields are unstable
-    a: String,
+    a: String, //~ ERROR unions may not contain fields that need dropping
 }
 
 union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable
-    a: T,
+    a: T, //~ ERROR unions may not contain fields that need dropping
 }
 
 union U5 { //~ ERROR unions with `Drop` implementations are unstable
diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
index f59a34e2c81..1885518a458 100644
--- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
@@ -31,6 +31,31 @@ LL | | }
    = note: for more information, see https://github.com/rust-lang/rust/issues/32836
    = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
 
-error: aborting due to 3 previous errors
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/feature-gate-untagged_unions.rs:10:5
+   |
+LL |     a: String,
+   |     ^^^^^^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/feature-gate-untagged_unions.rs:10:5
+   |
+LL |     a: String,
+   |     ^^^^^^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/feature-gate-untagged_unions.rs:14:5
+   |
+LL |     a: T,
+   |     ^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/feature-gate-untagged_unions.rs:14:5
+   |
+LL |     a: T,
+   |     ^^^^
+
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0740.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs
index 6d8ac7e8f29..759fb170f90 100644
--- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs
+++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs
@@ -1,3 +1,4 @@
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals
 
 #![crate_type = "lib"]
diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr
index 10cc4942135..97365c34d01 100644
--- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr
+++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the `#[unwind]` attribute is an experimental feature
-  --> $DIR/feature-gate-unwind-attributes.rs:11:5
+  --> $DIR/feature-gate-unwind-attributes.rs:12:5
    |
 LL |     #[unwind(allowed)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/for-loop-while/loop-break-value.rs b/src/test/ui/for-loop-while/loop-break-value.rs
index e1edbbb929e..d7209fc4de8 100644
--- a/src/test/ui/for-loop-while/loop-break-value.rs
+++ b/src/test/ui/for-loop-while/loop-break-value.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![allow(unreachable_code)]
 #![feature(never_type)]
 
diff --git a/src/test/ui/generator/issue-58888.rs b/src/test/ui/generator/issue-58888.rs
index 43b37a9afc2..d42d09d401e 100644
--- a/src/test/ui/generator/issue-58888.rs
+++ b/src/test/ui/generator/issue-58888.rs
@@ -1,5 +1,6 @@
 // run-pass
 // compile-flags: -g
+// ignore-asmjs wasm2js does not support source maps yet
 
 #![feature(generators, generator_trait)]
 
diff --git a/src/test/ui/generator/panic-drops.rs b/src/test/ui/generator/panic-drops.rs
index 5ac97585f4b..b1a5cc67e86 100644
--- a/src/test/ui/generator/panic-drops.rs
+++ b/src/test/ui/generator/panic-drops.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-// ignore-wasm32-bare compiled as panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(generators, generator_trait)]
 
diff --git a/src/test/ui/generator/panic-safe.rs b/src/test/ui/generator/panic-safe.rs
index 5f6778674dc..06c02618019 100644
--- a/src/test/ui/generator/panic-safe.rs
+++ b/src/test/ui/generator/panic-safe.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(generators, generator_trait)]
 
diff --git a/src/test/ui/generator/resume-after-return.rs b/src/test/ui/generator/resume-after-return.rs
index 71a68ff684a..ab18be58155 100644
--- a/src/test/ui/generator/resume-after-return.rs
+++ b/src/test/ui/generator/resume-after-return.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(generators, generator_trait)]
 
diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs
index 01db971434b..2864fbb2f3c 100644
--- a/src/test/ui/generator/size-moved-locals.rs
+++ b/src/test/ui/generator/size-moved-locals.rs
@@ -11,6 +11,7 @@
 
 // edition:2018
 // ignore-wasm32 issue #62807
+// ignore-asmjs issue #62807
 
 #![feature(generators, generator_trait)]
 
diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
new file mode 100644
index 00000000000..54b483f53d4
--- /dev/null
+++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
@@ -0,0 +1,14 @@
+#![crate_type="lib"]
+
+struct Nested<K>(K);
+
+fn should_error<T>() where T : Into<&u32> {}
+//~^ ERROR `&` without an explicit lifetime name cannot be used here [E0637]
+
+trait X<'a, K: 'a> {
+    fn foo<'b, L: X<&'b Nested<K>>>();
+    //~^ ERROR missing lifetime specifier [E0106]
+}
+
+fn bar<'b, L: X<&'b Nested<i32>>>(){}
+//~^ ERROR missing lifetime specifier [E0106]
diff --git a/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
new file mode 100644
index 00000000000..8720288b53e
--- /dev/null
+++ b/src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
@@ -0,0 +1,21 @@
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:37
+   |
+LL | fn should_error<T>() where T : Into<&u32> {}
+   |                                     ^ explicit lifetime name needed here
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
+   |
+LL |     fn foo<'b, L: X<&'b Nested<K>>>();
+   |                   ^^^^^^^^^^^^^^^^ expected lifetime parameter
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:15
+   |
+LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
+   |               ^^^^^^^^^^^^^^^^^^ expected lifetime parameter
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
index 979f64fcd90..76d97dd2f58 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
@@ -10,7 +10,7 @@ LL | |                                     fn(Inv<'y>)) }
    |
    = note: expected type `std::option::Option<fn(Inv<'y>)>`
               found type `std::option::Option<fn(Inv<'x>)>`
-note: the lifetime 'x as defined on the function body at 32:20...
+note: the lifetime `'x` as defined on the function body at 32:20...
   --> $DIR/hr-subtype.rs:32:20
    |
 LL |           fn subtype<'x,'y:'x,'z:'y>() {
@@ -19,7 +19,7 @@ LL |           fn subtype<'x,'y:'x,'z:'y>() {
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
 LL | |                                     fn(Inv<'y>)) }
    | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime 'y as defined on the function body at 32:23
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23
   --> $DIR/hr-subtype.rs:32:23
    |
 LL |           fn subtype<'x,'y:'x,'z:'y>() {
@@ -41,7 +41,7 @@ LL | |                                     fn(Inv<'y>)) }
    |
    = note: expected type `std::option::Option<fn(Inv<'x>)>`
               found type `std::option::Option<fn(Inv<'y>)>`
-note: the lifetime 'x as defined on the function body at 38:22...
+note: the lifetime `'x` as defined on the function body at 38:22...
   --> $DIR/hr-subtype.rs:38:22
    |
 LL |           fn supertype<'x,'y:'x,'z:'y>() {
@@ -50,7 +50,7 @@ LL |           fn supertype<'x,'y:'x,'z:'y>() {
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
 LL | |                                     fn(Inv<'y>)) }
    | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime 'y as defined on the function body at 38:25
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
   --> $DIR/hr-subtype.rs:38:25
    |
 LL |           fn supertype<'x,'y:'x,'z:'y>() {
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
index 3b6aff52169..74f4212b246 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
@@ -10,7 +10,7 @@ LL | |                             fn(&'y u32)) }
    |
    = note: expected type `std::option::Option<fn(&'x u32)>`
               found type `std::option::Option<fn(&'y u32)>`
-note: the lifetime 'x as defined on the function body at 38:22...
+note: the lifetime `'x` as defined on the function body at 38:22...
   --> $DIR/hr-subtype.rs:38:22
    |
 LL |           fn supertype<'x,'y:'x,'z:'y>() {
@@ -19,7 +19,7 @@ LL |           fn supertype<'x,'y:'x,'z:'y>() {
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
 LL | |                             fn(&'y u32)) }
    | |__________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime 'y as defined on the function body at 38:25
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
   --> $DIR/hr-subtype.rs:38:25
    |
 LL |           fn supertype<'x,'y:'x,'z:'y>() {
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
index c2cc8ebad27..afcb467ad47 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -6,10 +6,11 @@ LL | fn want_bar_for_any_ccx<B>(b: &B)
 LL |     where B : for<'ccx> Bar<'ccx>
    |               ------------------- required by this bound in `want_bar_for_any_ccx`
 ...
+LL |     where B : Qux
+   |                  - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>`
+...
 LL |     want_bar_for_any_ccx(b);
    |                          ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
-   |
-   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
index a93814ad4c2..20913b4f28c 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
    |
+LL |     where F : Foo<'x>
+   |                      - help: consider further restricting type parameter `F`: `, for<'tcx> F: Foo<'tcx>`
+...
 LL |     want_foo_for_any_tcx(f);
    |                          ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
 ...
@@ -8,12 +11,13 @@ LL | fn want_foo_for_any_tcx<F>(f: &F)
    |    --------------------
 LL |     where F : for<'tcx> Foo<'tcx>
    |               ------------------- required by this bound in `want_foo_for_any_tcx`
-   |
-   = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound
 
 error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
    |
+LL |     where B : Bar<'x>
+   |                      - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>`
+...
 LL |     want_bar_for_any_ccx(b);
    |                          ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
 ...
@@ -21,8 +25,6 @@ LL | fn want_bar_for_any_ccx<B>(b: &B)
    |    --------------------
 LL |     where B : for<'ccx> Bar<'ccx>
    |               ------------------- required by this bound in `want_bar_for_any_ccx`
-   |
-   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr
index 7e0f4e4e0b8..7acb266f49c 100644
--- a/src/test/ui/hygiene/globs.stderr
+++ b/src/test/ui/hygiene/globs.stderr
@@ -34,7 +34,7 @@ LL | use foo::test2::test::g;
    |
 LL | use foo::test::g;
    |
-and 2 other candidates
+     and 2 other candidates
 
 error[E0425]: cannot find function `f` in this scope
   --> $DIR/globs.rs:61:12
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index 5eacfdf8dee..45a2efebbb8 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -2,7 +2,7 @@ error[E0425]: cannot find value `Opaque` in this scope
   --> $DIR/rustc-macro-transparency.rs:26:5
    |
 LL |     Opaque;
-   |     ^^^^^^ help: a local variable with a similar name exists: `opaque`
+   |     ^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `opaque`
 
 error[E0423]: expected value, found macro `semitransparent`
   --> $DIR/rustc-macro-transparency.rs:29:5
diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout
index 6971873ba60..acd852103ca 100644
--- a/src/test/ui/hygiene/unpretty-debug.stdout
+++ b/src/test/ui/hygiene/unpretty-debug.stdout
@@ -17,7 +17,7 @@ fn y /* 0#0 */() { }
 /*
 Expansions:
 0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
-1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, foo)
+1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo")
 
 SyntaxContexts:
 #0: parent: #0, outer_mark: (ExpnId(0), Opaque)
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
index af120fa977c..5e80c673258 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |     static_val(x);
    |                ^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 19:26...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26...
   --> $DIR/dyn-trait.rs:19:26
    |
 LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr
index 650161753d1..956ac1f1a11 100644
--- a/src/test/ui/impl-trait/hidden-lifetimes.stderr
+++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr
@@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
    |                                                      ^^^^^^^^^^^^^^
    |
-note: hidden type `&'a mut &'b T` captures the lifetime 'b as defined on the function body at 28:17
+note: hidden type `&'a mut &'b T` captures the lifetime `'b` as defined on the function body at 28:17
   --> $DIR/hidden-lifetimes.rs:28:17
    |
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
@@ -16,7 +16,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
 LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
    |                                                                      ^^^^^^^^^^^^^^
    |
-note: hidden type `std::rc::Rc<std::cell::RefCell<&'b T>>` captures the lifetime 'b as defined on the function body at 45:24
+note: hidden type `std::rc::Rc<std::cell::RefCell<&'b T>>` captures the lifetime `'b` as defined on the function body at 45:24
   --> $DIR/hidden-lifetimes.rs:45:24
    |
 LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr
index d5756c01559..0d8ee61b5ba 100644
--- a/src/test/ui/impl-trait/issue-55872-1.stderr
+++ b/src/test/ui/impl-trait/issue-55872-1.stderr
@@ -1,10 +1,11 @@
 error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)`
   --> $DIR/issue-55872-1.rs:12:5
    |
+LL | impl<S: Default> Bar for S {
+   |      -- help: consider further restricting this bound: `S: std::marker::Copy +`
 LL |     type E = impl Copy;
    |     ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S`
    |
-   = help: consider adding a `where S: std::marker::Copy` bound
    = note: required because it appears within the type `(S, T)`
    = note: the return type of a function must have a statically known size
 
@@ -13,8 +14,10 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)
    |
 LL |     type E = impl Copy;
    |     ^^^^^^^^^^^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T`
+...
+LL |     fn foo<T: Default>() -> Self::E {
+   |            -- help: consider further restricting this bound: `T: std::marker::Copy +`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because it appears within the type `(S, T)`
    = note: the return type of a function must have a statically known size
 
diff --git a/src/test/ui/impl-trait/issues/universal-issue-48703.rs b/src/test/ui/impl-trait/issues/universal-issue-48703.rs
index e434e10bf89..f661c62c9e4 100644
--- a/src/test/ui/impl-trait/issues/universal-issue-48703.rs
+++ b/src/test/ui/impl-trait/issues/universal-issue-48703.rs
@@ -5,5 +5,5 @@ use std::fmt::Debug;
 fn foo<T>(x: impl Debug) { }
 
 fn main() {
-    foo::<String>('a'); //~ ERROR cannot provide explicit type parameters
+    foo::<String>('a'); //~ ERROR cannot provide explicit generic arguments
 }
diff --git a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr
index 527bbd5f30f..a51302dce29 100644
--- a/src/test/ui/impl-trait/issues/universal-issue-48703.stderr
+++ b/src/test/ui/impl-trait/issues/universal-issue-48703.stderr
@@ -1,4 +1,4 @@
-error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position.
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
   --> $DIR/universal-issue-48703.rs:8:5
    |
 LL |     foo::<String>('a');
diff --git a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs
index d3d561621fc..4ac0a694cb1 100644
--- a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs
+++ b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.rs
@@ -12,6 +12,6 @@ struct TestEvent(i32);
 fn main() {
     let mut evt = EventHandler {};
     evt.handle_event::<TestEvent, fn(TestEvent)>(|_evt| {
-        //~^ ERROR cannot provide explicit type parameters
+        //~^ ERROR cannot provide explicit generic arguments
     });
 }
diff --git a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr
index e2e6581fcf9..f09aa166ef5 100644
--- a/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr
+++ b/src/test/ui/impl-trait/issues/universal-turbofish-in-method-issue-50950.stderr
@@ -1,4 +1,4 @@
-error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position.
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
   --> $DIR/universal-turbofish-in-method-issue-50950.rs:14:9
    |
 LL |     evt.handle_event::<TestEvent, fn(TestEvent)>(|_evt| {
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index a6ea7837678..2ffb9434861 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -24,12 +24,12 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |                                |
    |                                this return type evaluates to the `'static` lifetime...
    |
-note: ...can't outlive the lifetime 'a as defined on the function body at 6:13
+note: ...can't outlive the lifetime `'a` as defined on the function body at 6:13
   --> $DIR/must_outlive_least_region_or_bound.rs:6:13
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
    |             ^^
-help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the function body at 6:13
+help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 6:13
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
    |                                ^^^^^^^^^^^^^^
@@ -42,12 +42,12 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                                  |
    |                                  this return type evaluates to the `'static` lifetime...
    |
-note: ...can't outlive the lifetime 'a as defined on the function body at 12:15
+note: ...can't outlive the lifetime `'a` as defined on the function body at 12:15
   --> $DIR/must_outlive_least_region_or_bound.rs:12:15
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
    |               ^^
-help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the function body at 12:15
+help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 12:15
    |
 LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x }
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr
index 5c8e322f712..894a65ff389 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.stderr
+++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr
@@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
 LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
    |                             ^^^^^^^^^^^^^^
    |
-note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 17:7
+note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime `'x` as defined on the function body at 17:7
   --> $DIR/region-escape-via-bound.rs:17:7
    |
 LL | where 'x: 'y
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
index 0bc0180e78a..1d6b5f56aa0 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
@@ -30,12 +30,12 @@ LL |         self.x.iter().map(|a| a.0)
    |         |
    |         ...but this borrow...
    |
-note: ...can't outlive the lifetime 'a as defined on the method body at 10:20
+note: ...can't outlive the lifetime `'a` as defined on the method body at 10:20
   --> $DIR/static-return-lifetime-infered.rs:10:20
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
    |                    ^^
-help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime 'a as defined on the method body at 10:20
+help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the method body at 10:20
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
index a80ebaf8dd2..b5287f32a50 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
@@ -11,7 +11,7 @@ LL | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
 LL | |         x
 LL | |     }
    | |_____^
-note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 9:32...
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the method body at 9:32...
   --> $DIR/mismatched_trait_impl.rs:9:32
    |
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
index 4dee83d6eef..734ca0819e4 100644
--- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
@@ -11,7 +11,7 @@ LL | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
 LL | |         x
 LL | |     }
    | |_____^
-note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 9:32...
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the method body at 9:32...
   --> $DIR/mismatched_trait_impl.rs:9:32
    |
 LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
diff --git a/src/test/ui/intrinsics/intrinsics-integer.rs b/src/test/ui/intrinsics/intrinsics-integer.rs
index 0154f049950..bac6c8d872b 100644
--- a/src/test/ui/intrinsics/intrinsics-integer.rs
+++ b/src/test/ui/intrinsics/intrinsics-integer.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-emscripten no i128 support
 
 #![feature(intrinsics)]
 
diff --git a/src/test/ui/invalid/invalid-plugin-attr.stderr b/src/test/ui/invalid/invalid-plugin-attr.stderr
index d14a7524bf2..0d7315dd887 100644
--- a/src/test/ui/invalid/invalid-plugin-attr.stderr
+++ b/src/test/ui/invalid/invalid-plugin-attr.stderr
@@ -1,8 +1,8 @@
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/invalid-plugin-attr.rs:4:1
    |
 LL | #[plugin(bla)]
-   | ^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/issues/issue-10200.stderr b/src/test/ui/issues/issue-10200.stderr
index 544716e89b3..b1057d45869 100644
--- a/src/test/ui/issues/issue-10200.stderr
+++ b/src/test/ui/issues/issue-10200.stderr
@@ -2,7 +2,7 @@ error[E0532]: expected tuple struct/variant, found function `foo`
   --> $DIR/issue-10200.rs:6:9
    |
 LL |         foo(x)
-   |         ^^^ help: a tuple struct with a similar name exists: `Foo`
+   |         ^^^ help: a tuple struct with a similar name exists (notice the capitalization): `Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-10291.stderr b/src/test/ui/issues/issue-10291.stderr
index a836593e0da..4fff4ee866c 100644
--- a/src/test/ui/issues/issue-10291.stderr
+++ b/src/test/ui/issues/issue-10291.stderr
@@ -12,7 +12,7 @@ LL |       drop::<Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
 LL | |         x
 LL | |     }));
    | |_____^
-note: ...but the borrowed content is only valid for the lifetime 'x as defined on the function body at 1:9
+note: ...but the borrowed content is only valid for the lifetime `'x` as defined on the function body at 1:9
   --> $DIR/issue-10291.rs:1:9
    |
 LL | fn test<'x>(x: &'x isize) {
diff --git a/src/test/ui/issues/issue-13867.rs b/src/test/ui/issues/issue-13867.rs
index e66368f9ba8..9510aae7753 100644
--- a/src/test/ui/issues/issue-13867.rs
+++ b/src/test/ui/issues/issue-13867.rs
@@ -2,7 +2,6 @@
 // Test that codegen works correctly when there are multiple refutable
 // patterns in match expression.
 
-
 enum Foo {
     FooUint(usize),
     FooNullary,
diff --git a/src/test/ui/issues/issue-14875.rs b/src/test/ui/issues/issue-14875.rs
index a2fd7962458..29e974ad83d 100644
--- a/src/test/ui/issues/issue-14875.rs
+++ b/src/test/ui/issues/issue-14875.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare always compiled as panic=abort right now
+// ignore-emscripten compiled with panic=abort by default
 
 // Check that values are not leaked when a dtor panics (#14875)
 
diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr
index a047893a168..b663e213ed0 100644
--- a/src/test/ui/issues/issue-16683.stderr
+++ b/src/test/ui/issues/issue-16683.stderr
@@ -16,7 +16,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |         self.a();
    |         ^^^^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the trait at 1:9...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the trait at 1:9...
   --> $DIR/issue-16683.rs:1:9
    |
 LL | trait T<'a> {
diff --git a/src/test/ui/issues/issue-17001.stderr b/src/test/ui/issues/issue-17001.stderr
index 2374e829556..d7e6069977b 100644
--- a/src/test/ui/issues/issue-17001.stderr
+++ b/src/test/ui/issues/issue-17001.stderr
@@ -6,3 +6,4 @@ LL |     let p = foo { x: () };
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/issues/issue-17405.stderr b/src/test/ui/issues/issue-17405.stderr
index 4b5678a8877..37274e239ba 100644
--- a/src/test/ui/issues/issue-17405.stderr
+++ b/src/test/ui/issues/issue-17405.stderr
@@ -6,3 +6,4 @@ LL |         Foo { i } => ()
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr
index e27f49b4a3f..291086d4f69 100644
--- a/src/test/ui/issues/issue-17546.stderr
+++ b/src/test/ui/issues/issue-17546.stderr
@@ -27,7 +27,7 @@ LL |     use std::prelude::v1::Result;
    |
 LL |     use std::result::Result;
    |
-and 1 other candidates
+     and 1 other candidate
 
 error[E0573]: expected type, found variant `Result`
   --> $DIR/issue-17546.rs:28:13
@@ -44,7 +44,7 @@ LL | use std::prelude::v1::Result;
    |
 LL | use std::result::Result;
    |
-and 1 other candidates
+     and 1 other candidate
 
 error[E0573]: expected type, found variant `NoResult`
   --> $DIR/issue-17546.rs:33:15
@@ -62,3 +62,4 @@ LL | fn newer() -> Result<foo::MyEnum, String> {
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/issues/issue-17718-const-naming.stderr b/src/test/ui/issues/issue-17718-const-naming.stderr
index 1fe1821292c..e320c436f5b 100644
--- a/src/test/ui/issues/issue-17718-const-naming.stderr
+++ b/src/test/ui/issues/issue-17718-const-naming.stderr
@@ -15,7 +15,7 @@ error: constant `foo` should have an upper case name
   --> $DIR/issue-17718-const-naming.rs:4:7
    |
 LL | const foo: isize = 3;
-   |       ^^^ help: convert the identifier to upper case: `FOO`
+   |       ^^^ help: convert the identifier to upper case (notice the capitalization): `FOO`
    |
 note: lint level defined here
   --> $DIR/issue-17718-const-naming.rs:2:9
diff --git a/src/test/ui/issues/issue-17740.stderr b/src/test/ui/issues/issue-17740.stderr
index b8a0a067631..d392ea3c1b8 100644
--- a/src/test/ui/issues/issue-17740.stderr
+++ b/src/test/ui/issues/issue-17740.stderr
@@ -17,7 +17,7 @@ LL | |
 LL | |
 LL | |     }
    | |_____^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 5:7
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 5:7
   --> $DIR/issue-17740.rs:5:7
    |
 LL | impl <'a> Foo<'a>{
@@ -31,7 +31,7 @@ LL |     fn bar(self: &mut Foo) {
    |
    = note: expected type `Foo<'a>`
               found type `Foo<'_>`
-note: the lifetime 'a as defined on the impl at 5:7...
+note: the lifetime `'a` as defined on the impl at 5:7...
   --> $DIR/issue-17740.rs:5:7
    |
 LL | impl <'a> Foo<'a>{
diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr
index 28a1be59840..adcbb62e3d5 100644
--- a/src/test/ui/issues/issue-17758.stderr
+++ b/src/test/ui/issues/issue-17758.stderr
@@ -17,7 +17,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |         self.foo();
    |         ^^^^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the trait at 4:11...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the trait at 4:11...
   --> $DIR/issue-17758.rs:4:11
    |
 LL | trait Foo<'a> {
diff --git a/src/test/ui/issues/issue-17905-2.stderr b/src/test/ui/issues/issue-17905-2.stderr
index 585bc9c1488..04be62dc661 100644
--- a/src/test/ui/issues/issue-17905-2.stderr
+++ b/src/test/ui/issues/issue-17905-2.stderr
@@ -15,7 +15,7 @@ LL | |
 LL | |         println!("{:?}", self);
 LL | |     }
    | |_____^
-note: ...does not necessarily outlive the lifetime '_ as defined on the impl at 5:5
+note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 5:5
   --> $DIR/issue-17905-2.rs:5:5
    |
 LL |     &str,
@@ -29,7 +29,7 @@ LL |     fn say(self: &Pair<&str, isize>) {
    |
    = note: expected type `Pair<&str, _>`
               found type `Pair<&str, _>`
-note: the lifetime '_ as defined on the impl at 5:5...
+note: the lifetime `'_` as defined on the impl at 5:5...
   --> $DIR/issue-17905-2.rs:5:5
    |
 LL |     &str,
diff --git a/src/test/ui/issues/issue-18119.stderr b/src/test/ui/issues/issue-18119.stderr
index 4c5b940190e..ddee5a9da7a 100644
--- a/src/test/ui/issues/issue-18119.stderr
+++ b/src/test/ui/issues/issue-18119.stderr
@@ -18,3 +18,4 @@ LL | impl foo {}
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr
index 2754d6bdd83..31376f2d1be 100644
--- a/src/test/ui/issues/issue-20005.stderr
+++ b/src/test/ui/issues/issue-20005.stderr
@@ -7,13 +7,13 @@ LL |   trait From<Src> {
 LL | /     fn to<Dst>(
 LL | |         self
 LL | |     ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
+   | |                                                           - help: consider further restricting `Self`: `, Self: std::marker::Sized`
 LL | |         From::from(self)
 LL | |     }
    | |_____^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Self: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr
index dd895985c14..13c9c09461e 100644
--- a/src/test/ui/issues/issue-20831-debruijn.stderr
+++ b/src/test/ui/issues/issue-20831-debruijn.stderr
@@ -23,7 +23,7 @@ LL | |
 LL | |         self.sub = t;
 LL | |     }
    | |_____^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 26:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 26:6
   --> $DIR/issue-20831-debruijn.rs:26:6
    |
 LL | impl<'a> Publisher<'a> for MyStruct<'a> {
@@ -43,7 +43,7 @@ LL | |     }
    |
    = note: expected type `'a`
               found type `'_`
-note: the lifetime 'a as defined on the impl at 26:6...
+note: the lifetime `'a` as defined on the impl at 26:6...
   --> $DIR/issue-20831-debruijn.rs:26:6
    |
 LL | impl<'a> Publisher<'a> for MyStruct<'a> {
@@ -83,7 +83,7 @@ LL | |
 LL | |         self.sub = t;
 LL | |     }
    | |_____^
-note: ...but the lifetime must also be valid for the lifetime 'a as defined on the impl at 26:6...
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 26:6...
   --> $DIR/issue-20831-debruijn.rs:26:6
    |
 LL | impl<'a> Publisher<'a> for MyStruct<'a> {
diff --git a/src/test/ui/issues/issue-21449.stderr b/src/test/ui/issues/issue-21449.stderr
index 21de1ea0915..ecaf6faba42 100644
--- a/src/test/ui/issues/issue-21449.stderr
+++ b/src/test/ui/issues/issue-21449.stderr
@@ -6,3 +6,4 @@ LL |     let myVar = MyMod { T: 0 };
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/issues/issue-21475.rs b/src/test/ui/issues/issue-21475.rs
index 16d003aba7c..ab0a1886963 100644
--- a/src/test/ui/issues/issue-21475.rs
+++ b/src/test/ui/issues/issue-21475.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(unused_imports)]
+#![allow(unused_imports, overlapping_patterns)]
 // pretty-expanded FIXME #23616
 
 use m::{START, END};
diff --git a/src/test/ui/issues/issue-21837.stderr b/src/test/ui/issues/issue-21837.stderr
index 20d02a90315..50fdf2d6185 100644
--- a/src/test/ui/issues/issue-21837.stderr
+++ b/src/test/ui/issues/issue-21837.stderr
@@ -5,9 +5,9 @@ LL | pub struct Foo<T: Bound>(T);
    | ---------------------------- required by `Foo`
 ...
 LL | impl<T> Trait2 for Foo<T> {}
-   |         ^^^^^^ the trait `Bound` is not implemented for `T`
-   |
-   = help: consider adding a `where T: Bound` bound
+   |      -  ^^^^^^ the trait `Bound` is not implemented for `T`
+   |      |
+   |      help: consider restricting this bound: `T: Bound`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr
index fc5de23752b..283a5e04a8b 100644
--- a/src/test/ui/issues/issue-22872.stderr
+++ b/src/test/ui/issues/issue-22872.stderr
@@ -1,11 +1,12 @@
 error[E0277]: `<P as Process<'_>>::Item` is not an iterator
   --> $DIR/issue-22872.rs:20:40
    |
+LL | fn push_process<P>(process: P) where P: Process<'static> {
+   |                                                         - help: consider further restricting the associated type: `, <P as Process<'_>>::Item: std::iter::Iterator`
 LL |     let _: Box<dyn for<'b> Wrap<'b>> = Box::new(Wrapper(process));
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `<P as Process<'_>>::Item`
-   = help: consider adding a `where <P as Process<'_>>::Item: std::iter::Iterator` bound
    = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper<P>`
    = note: required for the cast to the object type `dyn for<'b> Wrap<'b>`
 
diff --git a/src/test/ui/issues/issue-23189.stderr b/src/test/ui/issues/issue-23189.stderr
index 50c09f17486..ed065212c56 100644
--- a/src/test/ui/issues/issue-23189.stderr
+++ b/src/test/ui/issues/issue-23189.stderr
@@ -6,3 +6,4 @@ LL |     let _ = module { x: 0 };
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/issues/issue-23477.rs b/src/test/ui/issues/issue-23477.rs
index 1ce05ba390d..988ebe03ccf 100644
--- a/src/test/ui/issues/issue-23477.rs
+++ b/src/test/ui/issues/issue-23477.rs
@@ -1,4 +1,5 @@
 // build-pass
+// ignore-asmjs wasm2js does not support source maps yet
 // compile-flags: -g
 
 pub struct Dst {
diff --git a/src/test/ui/issues/issue-24687-embed-debuginfo/main.rs b/src/test/ui/issues/issue-24687-embed-debuginfo/main.rs
index 773792c7a3f..f08bcdfe6d1 100644
--- a/src/test/ui/issues/issue-24687-embed-debuginfo/main.rs
+++ b/src/test/ui/issues/issue-24687-embed-debuginfo/main.rs
@@ -1,6 +1,7 @@
 // run-pass
 // aux-build:issue-24687-lib.rs
 // compile-flags:-g
+// ignore-asmjs wasm2js does not support source maps yet
 
 extern crate issue_24687_lib as d;
 
diff --git a/src/test/ui/issues/issue-24945-repeat-dash-opts.rs b/src/test/ui/issues/issue-24945-repeat-dash-opts.rs
index cf3834952c6..0f92fc2f7f3 100644
--- a/src/test/ui/issues/issue-24945-repeat-dash-opts.rs
+++ b/src/test/ui/issues/issue-24945-repeat-dash-opts.rs
@@ -3,6 +3,7 @@
 // as options to the compiler.
 
 // compile-flags:-g -g -O -O
+// ignore-asmjs wasm2js does not support source maps yet
 
 fn main() {
     assert_eq!(1, 1);
diff --git a/src/test/ui/issues/issue-26251.rs b/src/test/ui/issues/issue-26251.rs
index 0434ef9e5a9..edb06fea8ad 100644
--- a/src/test/ui/issues/issue-26251.rs
+++ b/src/test/ui/issues/issue-26251.rs
@@ -1,4 +1,6 @@
 // run-pass
+#![allow(overlapping_patterns)]
+
 fn main() {
     let x = 'a';
 
diff --git a/src/test/ui/issues/issue-26459.stderr b/src/test/ui/issues/issue-26459.stderr
index c7909a142be..187369263a4 100644
--- a/src/test/ui/issues/issue-26459.stderr
+++ b/src/test/ui/issues/issue-26459.stderr
@@ -6,3 +6,4 @@ LL |         char{ch} => true
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/issues/issue-26484.rs b/src/test/ui/issues/issue-26484.rs
index 3b40b3dd8f0..2a8750d3e43 100644
--- a/src/test/ui/issues/issue-26484.rs
+++ b/src/test/ui/issues/issue-26484.rs
@@ -1,5 +1,6 @@
 // run-pass
 // compile-flags:-g
+// ignore-asmjs wasm2js does not support source maps yet
 
 fn helper<F: FnOnce(usize) -> bool>(_f: F) {
     print!("");
diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr
index f7227c34101..553041c5106 100644
--- a/src/test/ui/issues/issue-27060-2.stderr
+++ b/src/test/ui/issues/issue-27060-2.stderr
@@ -1,12 +1,13 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/issue-27060-2.rs:3:5
    |
+LL | pub struct Bad<T: ?Sized> {
+   |                -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     data: T,
    |     ^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr
index 76cc3e7b0a3..fbc72d063f3 100644
--- a/src/test/ui/issues/issue-27078.stderr
+++ b/src/test/ui/issues/issue-27078.stderr
@@ -2,11 +2,12 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
   --> $DIR/issue-27078.rs:5:12
    |
 LL |     fn foo(self) -> &'static i32 {
-   |            ^^^^ doesn't have a size known at compile-time
+   |            ^^^^                 - help: consider further restricting `Self`: `where Self: std::marker::Sized`
+   |            |
+   |            doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Self`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Self: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/issues/issue-27815.stderr b/src/test/ui/issues/issue-27815.stderr
index 1d68e3bf558..43f78ccf639 100644
--- a/src/test/ui/issues/issue-27815.stderr
+++ b/src/test/ui/issues/issue-27815.stderr
@@ -24,3 +24,4 @@ LL |         u32 { x: 1 } => {}
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/issues/issue-27942.stderr b/src/test/ui/issues/issue-27942.stderr
index e03959598b8..d290b176161 100644
--- a/src/test/ui/issues/issue-27942.stderr
+++ b/src/test/ui/issues/issue-27942.stderr
@@ -11,7 +11,7 @@ note: the anonymous lifetime #1 defined on the method body at 5:5...
    |
 LL |     fn select(&self) -> BufferViewHandle<R>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the trait at 3:18
+note: ...does not necessarily outlive the lifetime `'a` as defined on the trait at 3:18
   --> $DIR/issue-27942.rs:3:18
    |
 LL | pub trait Buffer<'a, R: Resources<'a>> {
@@ -25,7 +25,7 @@ LL |     fn select(&self) -> BufferViewHandle<R>;
    |
    = note: expected type `Resources<'_>`
               found type `Resources<'a>`
-note: the lifetime 'a as defined on the trait at 3:18...
+note: the lifetime `'a` as defined on the trait at 3:18...
   --> $DIR/issue-27942.rs:3:18
    |
 LL | pub trait Buffer<'a, R: Resources<'a>> {
diff --git a/src/test/ui/issues/issue-28848.stderr b/src/test/ui/issues/issue-28848.stderr
index 5f0f202c0b2..726844a3184 100644
--- a/src/test/ui/issues/issue-28848.stderr
+++ b/src/test/ui/issues/issue-28848.stderr
@@ -4,12 +4,12 @@ error[E0478]: lifetime bound not satisfied
 LL |     Foo::<'a, 'b>::xmute(u)
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-note: lifetime parameter instantiated with the lifetime 'b as defined on the function body at 9:16
+note: lifetime parameter instantiated with the lifetime `'b` as defined on the function body at 9:16
   --> $DIR/issue-28848.rs:9:16
    |
 LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
    |                ^^
-note: but lifetime parameter must outlive the lifetime 'a as defined on the function body at 9:12
+note: but lifetime parameter must outlive the lifetime `'a` as defined on the function body at 9:12
   --> $DIR/issue-28848.rs:9:12
    |
 LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
diff --git a/src/test/ui/issues/issue-29948.rs b/src/test/ui/issues/issue-29948.rs
index 8ede8143ea6..5237a2f67bd 100644
--- a/src/test/ui/issues/issue-29948.rs
+++ b/src/test/ui/issues/issue-29948.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 use std::panic;
 
diff --git a/src/test/ui/issues/issue-30535.stderr b/src/test/ui/issues/issue-30535.stderr
index 5faf0374210..e3692934b62 100644
--- a/src/test/ui/issues/issue-30535.stderr
+++ b/src/test/ui/issues/issue-30535.stderr
@@ -9,3 +9,4 @@ LL |     _: foo::Foo::FooV
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/issues/issue-33096.rs b/src/test/ui/issues/issue-33096.rs
index f0b472e2fe8..2501e1430b3 100644
--- a/src/test/ui/issues/issue-33096.rs
+++ b/src/test/ui/issues/issue-33096.rs
@@ -1,5 +1,6 @@
 // run-pass
 // compile-flags: -g
+// ignore-asmjs wasm2js does not support source maps yet
 
 use std::ops::Deref;
 
diff --git a/src/test/ui/issues/issue-33992.rs b/src/test/ui/issues/issue-33992.rs
index 94fccff9fc6..a6b137ba645 100644
--- a/src/test/ui/issues/issue-33992.rs
+++ b/src/test/ui/issues/issue-33992.rs
@@ -1,7 +1,7 @@
 // run-pass
 // ignore-windows
 // ignore-macos
-// ignore-wasm32-bare common linkage not implemented right now
+// ignore-emscripten common linkage not implemented right now
 
 #![feature(linkage)]
 
diff --git a/src/test/ui/issues/issue-34569.rs b/src/test/ui/issues/issue-34569.rs
index 1f68560509e..88dcdd41138 100644
--- a/src/test/ui/issues/issue-34569.rs
+++ b/src/test/ui/issues/issue-34569.rs
@@ -1,5 +1,6 @@
 // run-pass
 // compile-flags:-g
+// ignore-asmjs wasm2js does not support source maps yet
 
 // In this test we just want to make sure that the code below does not lead to
 // a debuginfo verification assertion during compilation. This was caused by the
diff --git a/src/test/ui/issues/issue-35675.stderr b/src/test/ui/issues/issue-35675.stderr
index 856d6506f2a..91814d94963 100644
--- a/src/test/ui/issues/issue-35675.stderr
+++ b/src/test/ui/issues/issue-35675.stderr
@@ -67,5 +67,5 @@ LL | fn qux() -> Some {
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0412, E0425.
+Some errors have detailed explanations: E0412, E0425, E0573.
 For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-36856.rs b/src/test/ui/issues/issue-36856.rs
index f2dfaf3dd36..5657ba69f94 100644
--- a/src/test/ui/issues/issue-36856.rs
+++ b/src/test/ui/issues/issue-36856.rs
@@ -2,6 +2,7 @@
 // Regression test for #36856.
 
 // compile-flags:-g
+// ignore-asmjs wasm2js does not support source maps yet
 
 fn g() -> bool {
     false
diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr
index 9a5f659da16..8e75d7be066 100644
--- a/src/test/ui/issues/issue-37884.stderr
+++ b/src/test/ui/issues/issue-37884.stderr
@@ -21,7 +21,7 @@ LL | |     {
 LL | |         Some(&mut self.0)
 LL | |     }
    | |_____^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 3:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 3:6
   --> $DIR/issue-37884.rs:3:6
    |
 LL | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
diff --git a/src/test/ui/issues/issue-38821.stderr b/src/test/ui/issues/issue-38821.stderr
index dbd204ec299..0687fc940de 100644
--- a/src/test/ui/issues/issue-38821.stderr
+++ b/src/test/ui/issues/issue-38821.stderr
@@ -4,7 +4,6 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
 LL | #[derive(Debug, Copy, Clone)]
    |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
-   = help: consider adding a `where <Col as Expression>::SqlType: NotNull` bound
    = note: required because of the requirements on the impl of `IntoNullable` for `<Col as Expression>::SqlType`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-42210.rs b/src/test/ui/issues/issue-42210.rs
index 318e3099f98..01a5d563639 100644
--- a/src/test/ui/issues/issue-42210.rs
+++ b/src/test/ui/issues/issue-42210.rs
@@ -2,6 +2,7 @@
 // Regression test for #42210.
 
 // compile-flags: -g
+// ignore-asmjs wasm2js does not support source maps yet
 
 trait Foo {
     fn foo() { }
diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr
index bfdc4272fb3..6688203147e 100644
--- a/src/test/ui/issues/issue-42312.stderr
+++ b/src/test/ui/issues/issue-42312.stderr
@@ -2,11 +2,12 @@ error[E0277]: the size for values of type `<Self as std::ops::Deref>::Target` ca
   --> $DIR/issue-42312.rs:4:29
    |
 LL |     fn baz(_: Self::Target) where Self: Deref {}
-   |                             ^ doesn't have a size known at compile-time
+   |                             ^                - help: consider further restricting the associated type: `, <Self as std::ops::Deref>::Target: std::marker::Sized`
+   |                             |
+   |                             doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `<Self as std::ops::Deref>::Target`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where <Self as std::ops::Deref>::Target: std::marker::Sized` bound
    = note: all function arguments must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr
index fc05d280693..e91e53499ce 100644
--- a/src/test/ui/issues/issue-43784-associated-type.stderr
+++ b/src/test/ui/issues/issue-43784-associated-type.stderr
@@ -2,9 +2,9 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/issue-43784-associated-type.rs:13:9
    |
 LL | impl<T> Complete for T {
-   |         ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
+   |      -  ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |      |
+   |      help: consider restricting this bound: `T: std::marker::Copy`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-43784-supertrait.stderr b/src/test/ui/issues/issue-43784-supertrait.stderr
index 4c423f2e77f..5ac32041bce 100644
--- a/src/test/ui/issues/issue-43784-supertrait.stderr
+++ b/src/test/ui/issues/issue-43784-supertrait.stderr
@@ -2,9 +2,9 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/issue-43784-supertrait.rs:8:9
    |
 LL | impl<T> Complete for T {}
-   |         ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
+   |      -  ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |      |
+   |      help: consider restricting this bound: `T: std::marker::Copy`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-43853.rs b/src/test/ui/issues/issue-43853.rs
index 47c3ab59aa2..2a932db05af 100644
--- a/src/test/ui/issues/issue-43853.rs
+++ b/src/test/ui/issues/issue-43853.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 use std::panic;
 
diff --git a/src/test/ui/issues/issue-45731.rs b/src/test/ui/issues/issue-45731.rs
index d20c07276a8..5c5ac59873a 100644
--- a/src/test/ui/issues/issue-45731.rs
+++ b/src/test/ui/issues/issue-45731.rs
@@ -1,6 +1,7 @@
 // run-pass
 #![allow(unused_variables)]
 // compile-flags:--test -g
+// ignore-asmjs wasm2js does not support source maps yet
 
 #[cfg(target_os = "macos")]
 #[test]
diff --git a/src/test/ui/issues/issue-46332.stderr b/src/test/ui/issues/issue-46332.stderr
index 812a50000d1..c7e9d71700e 100644
--- a/src/test/ui/issues/issue-46332.stderr
+++ b/src/test/ui/issues/issue-46332.stderr
@@ -2,7 +2,7 @@ error[E0422]: cannot find struct, variant or union type `TyUInt` in this scope
   --> $DIR/issue-46332.rs:9:5
    |
 LL |     TyUInt {};
-   |     ^^^^^^ help: a struct with a similar name exists: `TyUint`
+   |     ^^^^^^ help: a struct with a similar name exists (notice the capitalization): `TyUint`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-46519.rs b/src/test/ui/issues/issue-46519.rs
index 461ea2498b0..40c3117f01c 100644
--- a/src/test/ui/issues/issue-46519.rs
+++ b/src/test/ui/issues/issue-46519.rs
@@ -1,6 +1,8 @@
 // run-pass
 // compile-flags:--test -O
 
+// ignore-emscripten compiled with panic=abort by default
+
 #[test]
 #[should_panic(expected = "creating inhabited type")]
 fn test() {
diff --git a/src/test/ui/issues/issue-47486.rs b/src/test/ui/issues/issue-47486.rs
new file mode 100644
index 00000000000..d686f02a9fe
--- /dev/null
+++ b/src/test/ui/issues/issue-47486.rs
@@ -0,0 +1,4 @@
+fn main() {
+    () < std::mem::size_of::<_>(); //~ ERROR: mismatched types
+    [0u8; std::mem::size_of::<_>()]; //~ ERROR: type annotations needed
+}
diff --git a/src/test/ui/issues/issue-47486.stderr b/src/test/ui/issues/issue-47486.stderr
new file mode 100644
index 00000000000..af6e3010f79
--- /dev/null
+++ b/src/test/ui/issues/issue-47486.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-47486.rs:2:10
+   |
+LL |     () < std::mem::size_of::<_>();
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found usize
+   |
+   = note: expected type `()`
+              found type `usize`
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-47486.rs:3:11
+   |
+LL |     [0u8; std::mem::size_of::<_>()];
+   |           ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/issues/issue-48508.rs b/src/test/ui/issues/issue-48508.rs
index 385192b882b..b7aa6422876 100644
--- a/src/test/ui/issues/issue-48508.rs
+++ b/src/test/ui/issues/issue-48508.rs
@@ -8,6 +8,7 @@
 
 // compile-flags:-g
 // ignore-pretty issue #37195
+// ignore-asmjs wasm2js does not support source maps yet
 
 #![feature(non_ascii_idents)]
 
diff --git a/src/test/ui/issues/issue-49579.rs b/src/test/ui/issues/issue-49579.rs
index 79cc107d4fe..767e06c4e90 100644
--- a/src/test/ui/issues/issue-49579.rs
+++ b/src/test/ui/issues/issue-49579.rs
@@ -1,5 +1,4 @@
 // build-pass (FIXME(62277): could be check-pass?)
-// ignore-emscripten no i128 support
 
 fn fibs(n: u32) -> impl Iterator<Item=u128> {
     (0 .. n)
diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr
index 8d74b8ecb88..b79a5ddf3e1 100644
--- a/src/test/ui/issues/issue-52213.stderr
+++ b/src/test/ui/issues/issue-52213.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |     match (&t,) {
    |           ^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 1:23...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 1:23...
   --> $DIR/issue-52213.rs:1:23
    |
 LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
@@ -12,7 +12,7 @@ LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
    = note: ...so that the types are compatible:
            expected (&&(T,),)
               found (&&'a (T,),)
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 1:27...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
   --> $DIR/issue-52213.rs:1:27
    |
 LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs
index 68d83805477..e7221e2cbb1 100644
--- a/src/test/ui/issues/issue-54348.rs
+++ b/src/test/ui/issues/issue-54348.rs
@@ -1,5 +1,7 @@
 fn main() {
     [1][0u64 as usize];
     [1][1.5 as usize]; //~ ERROR index out of bounds
+    //~| ERROR this expression will panic at runtime
     [1][1u64 as usize]; //~ ERROR index out of bounds
+    //~| ERROR this expression will panic at runtime
 }
diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr
index fa77bd6fd77..79320ef4f31 100644
--- a/src/test/ui/issues/issue-54348.stderr
+++ b/src/test/ui/issues/issue-54348.stderr
@@ -6,11 +6,23 @@ LL |     [1][1.5 as usize];
    |
    = note: `#[deny(const_err)]` on by default
 
+error: this expression will panic at runtime
+  --> $DIR/issue-54348.rs:3:5
+   |
+LL |     [1][1.5 as usize];
+   |     ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
 error: index out of bounds: the len is 1 but the index is 1
-  --> $DIR/issue-54348.rs:4:5
+  --> $DIR/issue-54348.rs:5:5
    |
 LL |     [1][1u64 as usize];
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: this expression will panic at runtime
+  --> $DIR/issue-54348.rs:5:5
+   |
+LL |     [1][1u64 as usize];
+   |     ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr
index 7cf597d3a98..7b910f5e3e5 100644
--- a/src/test/ui/issues/issue-55796.stderr
+++ b/src/test/ui/issues/issue-55796.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the trait at 5:17...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 5:17...
   --> $DIR/issue-55796.rs:5:17
    |
 LL | pub trait Graph<'a> {
@@ -25,7 +25,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the trait at 5:17...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the trait at 5:17...
   --> $DIR/issue-55796.rs:5:17
    |
 LL | pub trait Graph<'a> {
diff --git a/src/test/ui/issues/issue-58463.rs b/src/test/ui/issues/issue-58463.rs
index 8ab845366b7..af93f76221d 100644
--- a/src/test/ui/issues/issue-58463.rs
+++ b/src/test/ui/issues/issue-58463.rs
@@ -1,5 +1,7 @@
 // run-pass
 // compile-flags:-C debuginfo=2
+// ignore-asmjs wasm2js does not support source maps yet
+
 fn foo() -> impl Copy {
     foo
 }
diff --git a/src/test/ui/iterators/iter-count-overflow-debug.rs b/src/test/ui/iterators/iter-count-overflow-debug.rs
index d6612035750..fdd285dcad2 100644
--- a/src/test/ui/iterators/iter-count-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-count-overflow-debug.rs
@@ -1,6 +1,6 @@
 // run-pass
 // only-32bit too impatient for 2⁶⁴ items
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes -C opt-level=3
 
 use std::panic;
diff --git a/src/test/ui/iterators/iter-position-overflow-debug.rs b/src/test/ui/iterators/iter-position-overflow-debug.rs
index f1eded31702..b578999af8e 100644
--- a/src/test/ui/iterators/iter-position-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-position-overflow-debug.rs
@@ -1,6 +1,6 @@
 // run-pass
 // only-32bit too impatient for 2⁶⁴ items
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes -C opt-level=3
 
 use std::panic;
diff --git a/src/test/ui/iterators/iter-step-overflow-debug.rs b/src/test/ui/iterators/iter-step-overflow-debug.rs
index 5d67c7cbb42..3872a03b682 100644
--- a/src/test/ui/iterators/iter-step-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-step-overflow-debug.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes
 
 use std::panic;
diff --git a/src/test/ui/iterators/iter-sum-overflow-debug.rs b/src/test/ui/iterators/iter-sum-overflow-debug.rs
index ee4ab4d24c6..4a9e8cdb72e 100644
--- a/src/test/ui/iterators/iter-sum-overflow-debug.rs
+++ b/src/test/ui/iterators/iter-sum-overflow-debug.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C debug_assertions=yes
 
 use std::panic;
diff --git a/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs b/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
index 429f8e0bc96..6bd1425e324 100644
--- a/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
+++ b/src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: -C overflow-checks
 
 use std::panic;
diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr
index 25d0e74187f..82efa839905 100644
--- a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr
+++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr
@@ -1,42 +1,50 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/kindck-impl-type-params.rs:18:13
    |
+LL | fn f<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Send`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:18:13
    |
+LL | fn f<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/kindck-impl-type-params.rs:25:31
    |
+LL | fn g<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Send`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:25:31
    |
+LL | fn g<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr
index e6f7088bd46..777a553c2a5 100644
--- a/src/test/ui/kindck/kindck-impl-type-params.stderr
+++ b/src/test/ui/kindck/kindck-impl-type-params.stderr
@@ -1,42 +1,50 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/kindck-impl-type-params.rs:18:13
    |
+LL | fn f<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Send`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:18:13
    |
+LL | fn f<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a = &t as &dyn Gettable<T>;
    |             ^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/kindck-impl-type-params.rs:25:31
    |
+LL | fn g<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Send`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ `T` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:25:31
    |
+LL | fn g<T>(val: T) {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     let t: S<T> = S(marker::PhantomData);
 LL |     let a: &dyn Gettable<T> = &t;
    |                               ^^ the trait `std::marker::Copy` is not implemented for `T`
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
    = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
    = note: required for the cast to the object type `dyn Gettable<T>`
 
diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr
index e990f705af3..38c7393e136 100644
--- a/src/test/ui/lexical-scopes.stderr
+++ b/src/test/ui/lexical-scopes.stderr
@@ -16,4 +16,5 @@ LL |     Foo::f();
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0599`.
+Some errors have detailed explanations: E0574, E0599.
+For more information about an error, try `rustc --explain E0574`.
diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr
index 35d63c17276..b4011990b68 100644
--- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr
+++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr
@@ -6,7 +6,7 @@ LL |     ref_obj(x)
    |
    = note: expected type `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>`
               found type `&std::boxed::Box<(dyn std::ops::Fn() + 'a)>`
-note: the lifetime 'a as defined on the function body at 32:10...
+note: the lifetime `'a` as defined on the function body at 32:10...
   --> $DIR/lifetime-bound-will-change-warning.rs:32:10
    |
 LL | fn test2<'a>(x: &'a Box<dyn Fn() + 'a>) {
@@ -21,7 +21,7 @@ LL |     lib::ref_obj(x)
    |
    = note: expected type `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>`
               found type `&std::boxed::Box<(dyn std::ops::Fn() + 'a)>`
-note: the lifetime 'a as defined on the function body at 37:12...
+note: the lifetime `'a` as defined on the function body at 37:12...
   --> $DIR/lifetime-bound-will-change-warning.rs:37:12
    |
 LL | fn test2cc<'a>(x: &'a Box<dyn Fn() + 'a>) {
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.rs b/src/test/ui/lint/lint-exceeding-bitshifts2.rs
index 69b627355b8..2c213daddd7 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts2.rs
+++ b/src/test/ui/lint/lint-exceeding-bitshifts2.rs
@@ -8,7 +8,7 @@ fn main() {
       let n = 1u8 << (4+3);
       let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow
       let n = 1i64 >> [63][0];
-      let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation
+      let n = 1i64 >> [64][0]; //~ ERROR: attempt to shift right with overflow
 
       #[cfg(target_pointer_width = "32")]
       const BITS: usize = 32;
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr
index cb96982a789..d9c76d233d0 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr
@@ -10,6 +10,12 @@ note: lint level defined here
 LL | #![deny(exceeding_bitshifts, const_err)]
    |         ^^^^^^^^^^^^^^^^^^^
 
+error: attempt to shift right with overflow
+  --> $DIR/lint-exceeding-bitshifts2.rs:11:15
+   |
+LL |       let n = 1i64 >> [64][0];
+   |               ^^^^^^^^^^^^^^^
+
 error: attempt to shift left with overflow
   --> $DIR/lint-exceeding-bitshifts2.rs:17:15
    |
@@ -22,5 +28,5 @@ error: attempt to shift left with overflow
 LL |       let n = 1_usize << BITS;
    |               ^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/lint/lint-non-camel-case-types.stderr b/src/test/ui/lint/lint-non-camel-case-types.stderr
index 432a16debc6..177f8c8fe9b 100644
--- a/src/test/ui/lint/lint-non-camel-case-types.stderr
+++ b/src/test/ui/lint/lint-non-camel-case-types.stderr
@@ -14,25 +14,25 @@ error: type `foo` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:7:8
    |
 LL | struct foo {
-   |        ^^^ help: convert the identifier to upper camel case: `Foo`
+   |        ^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo`
 
 error: type `foo2` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:11:6
    |
 LL | enum foo2 {
-   |      ^^^^ help: convert the identifier to upper camel case: `Foo2`
+   |      ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo2`
 
 error: type `foo3` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:15:8
    |
 LL | struct foo3 {
-   |        ^^^^ help: convert the identifier to upper camel case: `Foo3`
+   |        ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo3`
 
 error: type `foo4` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:19:6
    |
 LL | type foo4 = isize;
-   |      ^^^^ help: convert the identifier to upper camel case: `Foo4`
+   |      ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo4`
 
 error: variant `bar` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:22:5
@@ -44,7 +44,7 @@ error: trait `foo6` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:25:7
    |
 LL | trait foo6 {
-   |       ^^^^ help: convert the identifier to upper camel case: `Foo6`
+   |       ^^^^ help: convert the identifier to upper camel case (notice the capitalization): `Foo6`
 
 error: type parameter `ty` should have an upper camel case name
   --> $DIR/lint-non-camel-case-types.rs:29:6
diff --git a/src/test/ui/lint/lint-non-snake-case-functions.stderr b/src/test/ui/lint/lint-non-snake-case-functions.stderr
index 49cbfa94126..c5eca89debb 100644
--- a/src/test/ui/lint/lint-non-snake-case-functions.stderr
+++ b/src/test/ui/lint/lint-non-snake-case-functions.stderr
@@ -38,7 +38,7 @@ error: trait method `a_b_C` should have a snake case name
   --> $DIR/lint-non-snake-case-functions.rs:25:8
    |
 LL |     fn a_b_C(&self) {}
-   |        ^^^^^ help: convert the identifier to snake case: `a_b_c`
+   |        ^^^^^ help: convert the identifier to snake case (notice the capitalization): `a_b_c`
 
 error: trait method `something__else` should have a snake case name
   --> $DIR/lint-non-snake-case-functions.rs:28:8
@@ -50,13 +50,13 @@ error: function `Cookie` should have a snake case name
   --> $DIR/lint-non-snake-case-functions.rs:38:4
    |
 LL | fn Cookie() {}
-   |    ^^^^^^ help: convert the identifier to snake case: `cookie`
+   |    ^^^^^^ help: convert the identifier to snake case (notice the capitalization): `cookie`
 
 error: function `bi_S_Cuit` should have a snake case name
   --> $DIR/lint-non-snake-case-functions.rs:41:8
    |
 LL | pub fn bi_S_Cuit() {}
-   |        ^^^^^^^^^ help: convert the identifier to snake case: `bi_s_cuit`
+   |        ^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `bi_s_cuit`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/lint/lint-non-uppercase-statics.stderr b/src/test/ui/lint/lint-non-uppercase-statics.stderr
index 8b477276efc..ceb83d08f27 100644
--- a/src/test/ui/lint/lint-non-uppercase-statics.stderr
+++ b/src/test/ui/lint/lint-non-uppercase-statics.stderr
@@ -2,7 +2,7 @@ error: static variable `foo` should have an upper case name
   --> $DIR/lint-non-uppercase-statics.rs:4:8
    |
 LL | static foo: isize = 1;
-   |        ^^^ help: convert the identifier to upper case: `FOO`
+   |        ^^^ help: convert the identifier to upper case (notice the capitalization): `FOO`
    |
 note: lint level defined here
   --> $DIR/lint-non-uppercase-statics.rs:1:11
diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr
index 9ea3795f89e..f614d5d71f8 100644
--- a/src/test/ui/lint/lint-uppercase-variables.stderr
+++ b/src/test/ui/lint/lint-uppercase-variables.stderr
@@ -21,7 +21,7 @@ error: structure field `X` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:10:5
    |
 LL |     X: usize
-   |     ^ help: convert the identifier to snake case: `x`
+   |     ^ help: convert the identifier to snake case (notice the capitalization): `x`
    |
 note: lint level defined here
   --> $DIR/lint-uppercase-variables.rs:3:9
@@ -33,7 +33,7 @@ error: variable `Xx` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:13:9
    |
 LL | fn test(Xx: usize) {
-   |         ^^ help: convert the identifier to snake case: `xx`
+   |         ^^ help: convert the identifier to snake case (notice the capitalization): `xx`
 
 error: variable `Test` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:18:9
@@ -45,7 +45,7 @@ error: variable `Foo` should have a snake case name
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
-   |         ^^^ help: convert the identifier to snake case: `foo`
+   |         ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/lint/must_use-unit.rs b/src/test/ui/lint/must_use-unit.rs
index 92568252164..4dd4798abb7 100644
--- a/src/test/ui/lint/must_use-unit.rs
+++ b/src/test/ui/lint/must_use-unit.rs
@@ -1,5 +1,4 @@
 #![feature(never_type)]
-
 #![deny(unused_must_use)]
 
 #[must_use]
diff --git a/src/test/ui/lint/must_use-unit.stderr b/src/test/ui/lint/must_use-unit.stderr
index f6229c0442f..0a9939b2015 100644
--- a/src/test/ui/lint/must_use-unit.stderr
+++ b/src/test/ui/lint/must_use-unit.stderr
@@ -1,17 +1,17 @@
 error: unused return value of `foo` that must be used
-  --> $DIR/must_use-unit.rs:14:5
+  --> $DIR/must_use-unit.rs:13:5
    |
 LL |     foo();
    |     ^^^^^^
    |
 note: lint level defined here
-  --> $DIR/must_use-unit.rs:3:9
+  --> $DIR/must_use-unit.rs:2:9
    |
 LL | #![deny(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
 
 error: unused return value of `bar` that must be used
-  --> $DIR/must_use-unit.rs:16:5
+  --> $DIR/must_use-unit.rs:15:5
    |
 LL |     bar();
    |     ^^^^^^
diff --git a/src/test/ui/lint/not_found.stderr b/src/test/ui/lint/not_found.stderr
index 70d49a4e69c..5016d9b97d6 100644
--- a/src/test/ui/lint/not_found.stderr
+++ b/src/test/ui/lint/not_found.stderr
@@ -16,5 +16,5 @@ warning: unknown lint: `Warnings`
   --> $DIR/not_found.rs:10:8
    |
 LL | #[deny(Warnings)]
-   |        ^^^^^^^^ help: did you mean: `warnings`
+   |        ^^^^^^^^ help: did you mean (notice the capitalization): `warnings`
 
diff --git a/src/test/ui/lint/reasons.stderr b/src/test/ui/lint/reasons.stderr
index cb5f4ddf47b..139b3f13fd6 100644
--- a/src/test/ui/lint/reasons.stderr
+++ b/src/test/ui/lint/reasons.stderr
@@ -15,7 +15,7 @@ warning: variable `Social_exchange_psychology` should have a snake case name
   --> $DIR/reasons.rs:30:9
    |
 LL |     let Social_exchange_psychology = CheaterDetectionMechanism {};
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `social_exchange_psychology`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `social_exchange_psychology`
    |
    = note: people shouldn't have to change their usual style habits
            to contribute to our project
diff --git a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr
index 5f289c0914d..2160df51a83 100644
--- a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr
+++ b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr
@@ -1,4 +1,4 @@
-TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }]
+TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }]
 error: unnecessary trailing semicolon
   --> $DIR/redundant-semi-proc-macro.rs:9:19
    |
diff --git a/src/test/ui/lint/unused_parens_json_suggestion.fixed b/src/test/ui/lint/unused_parens_json_suggestion.fixed
index 42740711910..15ee19755bf 100644
--- a/src/test/ui/lint/unused_parens_json_suggestion.fixed
+++ b/src/test/ui/lint/unused_parens_json_suggestion.fixed
@@ -1,5 +1,4 @@
-// compile-flags: --error-format pretty-json -Zunstable-options
-// build-pass (FIXME(62277): could be check-pass?)
+// compile-flags: --error-format json -Zunstable-options
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
@@ -8,13 +7,13 @@
 // stripping away any starting or ending parenthesis characters—hence this
 // test of the JSON error format.
 
-#![warn(unused_parens)]
+#![deny(unused_parens)]
 #![allow(unreachable_code)]
 
 fn main() {
     // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
     // the malformed `1 / (2 + 3`
-    let _a = 1 / (2 + 3);
+    let _a = 1 / (2 + 3); //~ERROR unnecessary parentheses
     f();
 }
 
diff --git a/src/test/ui/lint/unused_parens_json_suggestion.rs b/src/test/ui/lint/unused_parens_json_suggestion.rs
index 87192503986..d72df21e09a 100644
--- a/src/test/ui/lint/unused_parens_json_suggestion.rs
+++ b/src/test/ui/lint/unused_parens_json_suggestion.rs
@@ -1,5 +1,4 @@
-// compile-flags: --error-format pretty-json -Zunstable-options
-// build-pass (FIXME(62277): could be check-pass?)
+// compile-flags: --error-format json -Zunstable-options
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
@@ -8,13 +7,13 @@
 // stripping away any starting or ending parenthesis characters—hence this
 // test of the JSON error format.
 
-#![warn(unused_parens)]
+#![deny(unused_parens)]
 #![allow(unreachable_code)]
 
 fn main() {
     // We want to suggest the properly-balanced expression `1 / (2 + 3)`, not
     // the malformed `1 / (2 + 3`
-    let _a = (1 / (2 + 3));
+    let _a = (1 / (2 + 3)); //~ERROR unnecessary parentheses
     f();
 }
 
diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr
index 256c7555c90..c503c100808 100644
--- a/src/test/ui/lint/unused_parens_json_suggestion.stderr
+++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr
@@ -1,106 +1,16 @@
-{
-  "message": "unnecessary parentheses around assigned value",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_json_suggestion.rs",
-      "byte_start": 654,
-      "byte_end": 667,
-      "line_start": 17,
-      "line_end": 17,
-      "column_start": 14,
-      "column_end": 27,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    let _a = (1 / (2 + 3));",
-          "highlight_start": 14,
-          "highlight_end": 27
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "lint level defined here",
-      "code": null,
-      "level": "note",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_json_suggestion.rs",
-          "byte_start": 472,
-          "byte_end": 485,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 9,
-          "column_end": 22,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "#![warn(unused_parens)]",
-              "highlight_start": 9,
-              "highlight_end": 22
-            }
-          ],
-          "label": null,
-          "suggested_replacement": null,
-          "suggestion_applicability": null,
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    },
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_json_suggestion.rs",
-          "byte_start": 654,
-          "byte_end": 667,
-          "line_start": 17,
-          "line_end": 17,
-          "column_start": 14,
-          "column_end": 27,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    let _a = (1 / (2 + 3));",
-              "highlight_start": 14,
-              "highlight_end": 27
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "1 / (2 + 3)",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around assigned value
-  --> $DIR/unused_parens_json_suggestion.rs:17:14
+{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":609,"line_start":16,"line_end":16,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));
+  --> $DIR/unused_parens_json_suggestion.rs:16:14
    |
 LL |     let _a = (1 / (2 + 3));
    |              ^^^^^^^^^^^^^ help: remove these parentheses
    |
 note: lint level defined here
-  --> $DIR/unused_parens_json_suggestion.rs:11:9
+  --> $DIR/unused_parens_json_suggestion.rs:10:9
    |
-LL | #![warn(unused_parens)]
+LL | #![deny(unused_parens)]
    |         ^^^^^^^^^^^^^
 
-"
-}
+"}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
+
+"}
diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed
index 2459eb1ac5c..1d891d328dd 100644
--- a/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed
+++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.fixed
@@ -1,5 +1,4 @@
-// compile-flags: --error-format pretty-json -Zunstable-options
-// build-pass
+// compile-flags: --error-format json -Zunstable-options
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
@@ -8,14 +7,14 @@
 // stripping away any starting or ending parenthesis characters—hence this
 // test of the JSON error format.
 
-#![warn(unused_parens)]
+#![deny(unused_parens)]
 #![allow(unreachable_code)]
 
 fn main() {
 
     let _b = false;
 
-    if _b {
+    if _b { //~ ERROR unnecessary parentheses
         println!("hello");
     }
 
@@ -26,29 +25,29 @@ fn main() {
 fn f() -> bool {
     let c = false;
 
-    if c {
+    if c { //~ ERROR unnecessary parentheses
         println!("next");
     }
 
-    if c {
+    if c { //~ ERROR unnecessary parentheses
         println!("prev");
     }
 
     while false && true {
-        if c {
+        if c { //~ ERROR unnecessary parentheses
             println!("norm");
         }
 
     }
 
-    while true && false {
-        for _ in 0 .. 3 {
+    while true && false { //~ ERROR unnecessary parentheses
+        for _ in 0 .. 3 { //~ ERROR unnecessary parentheses
             println!("e~")
         }
     }
 
-    for _ in 0 .. 3 {
-        while true && false {
+    for _ in 0 .. 3 { //~ ERROR unnecessary parentheses
+        while true && false { //~ ERROR unnecessary parentheses
             println!("e~")
         }
     }
diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs
index 0e9869b67d5..494cd184506 100644
--- a/src/test/ui/lint/unused_parens_remove_json_suggestion.rs
+++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.rs
@@ -1,5 +1,4 @@
-// compile-flags: --error-format pretty-json -Zunstable-options
-// build-pass
+// compile-flags: --error-format json -Zunstable-options
 // run-rustfix
 
 // The output for humans should just highlight the whole span without showing
@@ -8,14 +7,14 @@
 // stripping away any starting or ending parenthesis characters—hence this
 // test of the JSON error format.
 
-#![warn(unused_parens)]
+#![deny(unused_parens)]
 #![allow(unreachable_code)]
 
 fn main() {
 
     let _b = false;
 
-    if (_b) {
+    if (_b) { //~ ERROR unnecessary parentheses
         println!("hello");
     }
 
@@ -26,29 +25,29 @@ fn main() {
 fn f() -> bool {
     let c = false;
 
-    if(c) {
+    if(c) { //~ ERROR unnecessary parentheses
         println!("next");
     }
 
-    if (c){
+    if (c){ //~ ERROR unnecessary parentheses
         println!("prev");
     }
 
     while (false && true){
-        if (c) {
+        if (c) { //~ ERROR unnecessary parentheses
             println!("norm");
         }
 
     }
 
-    while(true && false) {
-        for _ in (0 .. 3){
+    while(true && false) { //~ ERROR unnecessary parentheses
+        for _ in (0 .. 3){ //~ ERROR unnecessary parentheses
             println!("e~")
         }
     }
 
-    for _ in (0 .. 3) {
-        while (true && false) {
+    for _ in (0 .. 3) { //~ ERROR unnecessary parentheses
+        while (true && false) { //~ ERROR unnecessary parentheses
             println!("e~")
         }
     }
diff --git a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr
index b4eab200dd0..873f105435e 100644
--- a/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr
+++ b/src/test/ui/lint/unused_parens_remove_json_suggestion.stderr
@@ -1,666 +1,72 @@
-{
-  "message": "unnecessary parentheses around `if` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 521,
-      "byte_end": 525,
-      "line_start": 18,
-      "line_end": 18,
-      "column_start": 8,
-      "column_end": 12,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    if (_b) {",
-          "highlight_start": 8,
-          "highlight_end": 12
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "lint level defined here",
-      "code": null,
-      "level": "note",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 435,
-          "byte_end": 448,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 9,
-          "column_end": 22,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "#![warn(unused_parens)]",
-              "highlight_start": 9,
-              "highlight_end": 22
-            }
-          ],
-          "label": null,
-          "suggested_replacement": null,
-          "suggestion_applicability": null,
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    },
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 521,
-          "byte_end": 525,
-          "line_start": 18,
-          "line_end": 18,
-          "column_start": 8,
-          "column_end": 12,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    if (_b) {",
-              "highlight_start": 8,
-              "highlight_end": 12
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "_b",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `if` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:18:8
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":504,"line_start":17,"line_end":17,"column_start":8,"column_end":12,"is_primary":true,"text":[{"text":"    if (_b) {
+  --> $DIR/unused_parens_remove_json_suggestion.rs:17:8
    |
 LL |     if (_b) {
    |        ^^^^ help: remove these parentheses
    |
 note: lint level defined here
-  --> $DIR/unused_parens_remove_json_suggestion.rs:11:9
+  --> $DIR/unused_parens_remove_json_suggestion.rs:10:9
    |
-LL | #![warn(unused_parens)]
+LL | #![deny(unused_parens)]
    |         ^^^^^^^^^^^^^
 
-"
-}
-{
-  "message": "unnecessary parentheses around `if` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 618,
-      "byte_end": 621,
-      "line_start": 29,
-      "line_end": 29,
-      "column_start": 7,
-      "column_end": 10,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    if(c) {",
-          "highlight_start": 7,
-          "highlight_end": 10
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 618,
-          "byte_end": 621,
-          "line_start": 29,
-          "line_end": 29,
-          "column_start": 7,
-          "column_end": 10,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    if(c) {",
-              "highlight_start": 7,
-              "highlight_end": 10
-            }
-          ],
-          "label": null,
-          "suggested_replacement": " c",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `if` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:29:7
+"}
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":634,"line_start":28,"line_end":28,"column_start":7,"column_end":10,"is_primary":true,"text":[{"text":"    if(c) {
+  --> $DIR/unused_parens_remove_json_suggestion.rs:28:7
    |
 LL |     if(c) {
    |       ^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `if` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 664,
-      "byte_end": 667,
-      "line_start": 33,
-      "line_end": 33,
-      "column_start": 8,
-      "column_end": 11,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    if (c){",
-          "highlight_start": 8,
-          "highlight_end": 11
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 664,
-          "byte_end": 667,
-          "line_start": 33,
-          "line_end": 33,
-          "column_start": 8,
-          "column_end": 11,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    if (c){",
-              "highlight_start": 8,
-              "highlight_end": 11
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "c ",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `if` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:33:8
+"}
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":714,"line_start":32,"line_end":32,"column_start":8,"column_end":11,"is_primary":true,"text":[{"text":"    if (c){
+  --> $DIR/unused_parens_remove_json_suggestion.rs:32:8
    |
 LL |     if (c){
    |        ^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `while` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 712,
-      "byte_end": 727,
-      "line_start": 37,
-      "line_end": 37,
-      "column_start": 11,
-      "column_end": 26,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    while (false && true){",
-          "highlight_start": 11,
-          "highlight_end": 26
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 712,
-          "byte_end": 727,
-          "line_start": 37,
-          "line_end": 37,
-          "column_start": 11,
-          "column_end": 26,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    while (false && true){",
-              "highlight_start": 11,
-              "highlight_end": 26
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "false && true ",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `while` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:37:11
+"}
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":808,"line_start":36,"line_end":36,"column_start":11,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":808,"line_start":36,"line_end":36,"column_start":11,"column_end":26,"is_primary":true,"text":[{"text":"    while (false && true){","highlight_start":11,"highlight_end":26}],"label":null,"suggested_replacement":"false && true ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+  --> $DIR/unused_parens_remove_json_suggestion.rs:36:11
    |
 LL |     while (false && true){
    |           ^^^^^^^^^^^^^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `if` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 740,
-      "byte_end": 743,
-      "line_start": 38,
-      "line_end": 38,
-      "column_start": 12,
-      "column_end": 15,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "        if (c) {",
-          "highlight_start": 12,
-          "highlight_end": 15
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 740,
-          "byte_end": 743,
-          "line_start": 38,
-          "line_end": 38,
-          "column_start": 12,
-          "column_end": 15,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "        if (c) {",
-              "highlight_start": 12,
-              "highlight_end": 15
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "c",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `if` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:38:12
+"}
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":824,"line_start":37,"line_end":37,"column_start":12,"column_end":15,"is_primary":true,"text":[{"text":"        if (c) {
+  --> $DIR/unused_parens_remove_json_suggestion.rs:37:12
    |
 LL |         if (c) {
    |            ^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `while` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 803,
-      "byte_end": 818,
-      "line_start": 44,
-      "line_end": 44,
-      "column_start": 10,
-      "column_end": 25,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    while(true && false) {",
-          "highlight_start": 10,
-          "highlight_end": 25
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 803,
-          "byte_end": 818,
-          "line_start": 44,
-          "line_end": 44,
-          "column_start": 10,
-          "column_end": 25,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    while(true && false) {",
-              "highlight_start": 10,
-              "highlight_end": 25
-            }
-          ],
-          "label": null,
-          "suggested_replacement": " true && false",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `while` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:44:10
+"}
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":933,"line_start":43,"line_end":43,"column_start":10,"column_end":25,"is_primary":true,"text":[{"text":"    while(true && false) {
+  --> $DIR/unused_parens_remove_json_suggestion.rs:43:10
    |
 LL |     while(true && false) {
    |          ^^^^^^^^^^^^^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `for` head expression",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 838,
-      "byte_end": 846,
-      "line_start": 45,
-      "line_end": 45,
-      "column_start": 18,
-      "column_end": 26,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "        for _ in (0 .. 3){",
-          "highlight_start": 18,
-          "highlight_end": 26
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 838,
-          "byte_end": 846,
-          "line_start": 45,
-          "line_end": 45,
-          "column_start": 18,
-          "column_end": 26,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "        for _ in (0 .. 3){",
-              "highlight_start": 18,
-              "highlight_end": 26
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "0 .. 3 ",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `for` head expression
-  --> $DIR/unused_parens_remove_json_suggestion.rs:45:18
+"}
+{"message":"unnecessary parentheses around `for` head expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":995,"line_start":44,"line_end":44,"column_start":18,"column_end":26,"is_primary":true,"text":[{"text":"        for _ in (0 .. 3){
+  --> $DIR/unused_parens_remove_json_suggestion.rs:44:18
    |
 LL |         for _ in (0 .. 3){
    |                  ^^^^^^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `for` head expression",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 905,
-      "byte_end": 913,
-      "line_start": 50,
-      "line_end": 50,
-      "column_start": 14,
-      "column_end": 22,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    for _ in (0 .. 3) {",
-          "highlight_start": 14,
-          "highlight_end": 22
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 905,
-          "byte_end": 913,
-          "line_start": 50,
-          "line_end": 50,
-          "column_start": 14,
-          "column_end": 22,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "    for _ in (0 .. 3) {",
-              "highlight_start": 14,
-              "highlight_end": 22
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "0 .. 3",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `for` head expression
-  --> $DIR/unused_parens_remove_json_suggestion.rs:50:14
+"}
+{"message":"unnecessary parentheses around `for` head expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1096,"line_start":49,"line_end":49,"column_start":14,"column_end":22,"is_primary":true,"text":[{"text":"    for _ in (0 .. 3) {
+  --> $DIR/unused_parens_remove_json_suggestion.rs:49:14
    |
 LL |     for _ in (0 .. 3) {
    |              ^^^^^^^^ help: remove these parentheses
 
-"
-}
-{
-  "message": "unnecessary parentheses around `while` condition",
-  "code": {
-    "code": "unused_parens",
-    "explanation": null
-  },
-  "level": "warning",
-  "spans": [
-    {
-      "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-      "byte_start": 930,
-      "byte_end": 945,
-      "line_start": 51,
-      "line_end": 51,
-      "column_start": 15,
-      "column_end": 30,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "        while (true && false) {",
-          "highlight_start": 15,
-          "highlight_end": 30
-        }
-      ],
-      "label": null,
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "remove these parentheses",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/unused_parens_remove_json_suggestion.rs",
-          "byte_start": 930,
-          "byte_end": 945,
-          "line_start": 51,
-          "line_end": 51,
-          "column_start": 15,
-          "column_end": 30,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "        while (true && false) {",
-              "highlight_start": 15,
-              "highlight_end": 30
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "true && false",
-          "suggestion_applicability": "MachineApplicable",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "warning: unnecessary parentheses around `while` condition
-  --> $DIR/unused_parens_remove_json_suggestion.rs:51:15
+"}
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1162,"line_start":50,"line_end":50,"column_start":15,"column_end":30,"is_primary":true,"text":[{"text":"        while (true && false) {
+  --> $DIR/unused_parens_remove_json_suggestion.rs:50:15
    |
 LL |         while (true && false) {
    |               ^^^^^^^^^^^^^^^ help: remove these parentheses
 
-"
-}
+"}
+{"message":"aborting due to 9 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 9 previous errors
+
+"}
diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr
index 678c88849b5..1da5acc9661 100644
--- a/src/test/ui/lint/use_suggestion_json.stderr
+++ b/src/test/ui/lint/use_suggestion_json.stderr
@@ -395,7 +395,7 @@ mod foo {
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
 \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0mand 8 other candidates\u001b[0m
+\u001b[0m     and 8 other candidates\u001b[0m
 
 "
 }
diff --git a/src/test/ui/lub-if.stderr b/src/test/ui/lub-if.stderr
index 26f756c9183..0a4744013a6 100644
--- a/src/test/ui/lub-if.stderr
+++ b/src/test/ui/lub-if.stderr
@@ -5,7 +5,7 @@ LL |         s
    |         ^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 23:17
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 23:17
   --> $DIR/lub-if.rs:23:17
    |
 LL | pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
@@ -18,7 +18,7 @@ LL |         s
    |         ^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 32:17
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 32:17
   --> $DIR/lub-if.rs:32:17
    |
 LL | pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
diff --git a/src/test/ui/lub-match.stderr b/src/test/ui/lub-match.stderr
index 0cb0a23c6f2..168a3894469 100644
--- a/src/test/ui/lub-match.stderr
+++ b/src/test/ui/lub-match.stderr
@@ -5,7 +5,7 @@ LL |             s
    |             ^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 25:17
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 25:17
   --> $DIR/lub-match.rs:25:17
    |
 LL | pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
@@ -18,7 +18,7 @@ LL |             s
    |             ^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 35:17
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 35:17
   --> $DIR/lub-match.rs:35:17
    |
 LL | pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
diff --git a/src/test/ui/macros/macro-comma-behavior-rpass.rs b/src/test/ui/macros/macro-comma-behavior-rpass.rs
index 9f1a31d1ae2..1c791bb1ca3 100644
--- a/src/test/ui/macros/macro-comma-behavior-rpass.rs
+++ b/src/test/ui/macros/macro-comma-behavior-rpass.rs
@@ -13,6 +13,8 @@
 // compile-flags: --test -C debug_assertions=yes
 // revisions: std core
 
+// ignore-emscripten compiled with panic=abort by default
+
 #![cfg_attr(core, no_std)]
 
 #[cfg(std)] use std::fmt;
diff --git a/src/test/ui/macros/same-sequence-span.rs b/src/test/ui/macros/same-sequence-span.rs
index a4f70b6b68d..e0bb4d98525 100644
--- a/src/test/ui/macros/same-sequence-span.rs
+++ b/src/test/ui/macros/same-sequence-span.rs
@@ -4,7 +4,6 @@
 // left-hand side of a macro definition behave as if they had unique spans, and in particular that
 // they don't crash the compiler.
 
-#![feature(proc_macro_hygiene)]
 #![allow(unused_macros)]
 
 extern crate proc_macro_sequence;
diff --git a/src/test/ui/macros/same-sequence-span.stderr b/src/test/ui/macros/same-sequence-span.stderr
index 0eef4a2a678..896f579765f 100644
--- a/src/test/ui/macros/same-sequence-span.stderr
+++ b/src/test/ui/macros/same-sequence-span.stderr
@@ -1,5 +1,5 @@
 error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
-  --> $DIR/same-sequence-span.rs:15:18
+  --> $DIR/same-sequence-span.rs:14:18
    |
 LL |     (1 $x:expr $($y:tt,)*
    |                  ^^^^^ not allowed after `expr` fragments
@@ -7,7 +7,7 @@ LL |     (1 $x:expr $($y:tt,)*
    = note: allowed there are: `=>`, `,` or `;`
 
 error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments
-  --> $DIR/same-sequence-span.rs:16:18
+  --> $DIR/same-sequence-span.rs:15:18
    |
 LL |                $(= $z:tt)*
    |                  ^ not allowed after `expr` fragments
@@ -15,7 +15,7 @@ LL |                $(= $z:tt)*
    = note: allowed there are: `=>`, `,` or `;`
 
 error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
-  --> $DIR/same-sequence-span.rs:20:1
+  --> $DIR/same-sequence-span.rs:19:1
    |
 LL |   proc_macro_sequence::make_foo!();
    |   ^--------------------------------
@@ -30,7 +30,7 @@ LL | | fn main() {}
    = note: allowed there are: `=>`, `,` or `;`
 
 error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments
-  --> $DIR/same-sequence-span.rs:20:1
+  --> $DIR/same-sequence-span.rs:19:1
    |
 LL | proc_macro_sequence::make_foo!();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/malformed/malformed-plugin-1.stderr b/src/test/ui/malformed/malformed-plugin-1.stderr
index d8416c40954..3860864bd13 100644
--- a/src/test/ui/malformed/malformed-plugin-1.stderr
+++ b/src/test/ui/malformed/malformed-plugin-1.stderr
@@ -4,11 +4,11 @@ error: malformed `plugin` attribute input
 LL | #![plugin]
    | ^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]`
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/malformed-plugin-1.rs:2:1
    |
 LL | #![plugin]
-   | ^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/malformed/malformed-plugin-2.stderr b/src/test/ui/malformed/malformed-plugin-2.stderr
index 34383ba0828..e4bca93f13b 100644
--- a/src/test/ui/malformed/malformed-plugin-2.stderr
+++ b/src/test/ui/malformed/malformed-plugin-2.stderr
@@ -4,11 +4,11 @@ error: malformed `plugin` attribute input
 LL | #![plugin="bleh"]
    | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name|name(args))]`
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/malformed-plugin-2.rs:2:1
    |
 LL | #![plugin="bleh"]
-   | ^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/malformed/malformed-plugin-3.stderr b/src/test/ui/malformed/malformed-plugin-3.stderr
index 71f607d68a4..7393072cb1c 100644
--- a/src/test/ui/malformed/malformed-plugin-3.stderr
+++ b/src/test/ui/malformed/malformed-plugin-3.stderr
@@ -4,11 +4,11 @@ error[E0498]: malformed `plugin` attribute
 LL | #![plugin(foo="bleh")]
    | ^^^^^^^^^^^^^^^^^^^^^^ malformed attribute
 
-warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/malformed-plugin-3.rs:2:1
    |
 LL | #![plugin(foo="bleh")]
-   | ^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
diff --git a/src/test/ui/match/match-range-fail-dominate.rs b/src/test/ui/match/match-range-fail-dominate.rs
index a0cc773d20e..7de7b7e79be 100644
--- a/src/test/ui/match/match-range-fail-dominate.rs
+++ b/src/test/ui/match/match-range-fail-dominate.rs
@@ -1,39 +1,45 @@
-//error-pattern: unreachable
-//error-pattern: unreachable
-//error-pattern: unreachable
-//error-pattern: unreachable
-//error-pattern: unreachable
-
-#![deny(unreachable_patterns)]
+#![deny(unreachable_patterns, overlapping_patterns)]
 
 fn main() {
     match 5 {
       1 ..= 10 => { }
       5 ..= 6 => { }
+      //~^ ERROR unreachable pattern
       _ => {}
     };
 
     match 5 {
       3 ..= 6 => { }
       4 ..= 6 => { }
+      //~^ ERROR unreachable pattern
       _ => {}
     };
 
     match 5 {
       4 ..= 6 => { }
       4 ..= 6 => { }
+      //~^ ERROR unreachable pattern
       _ => {}
     };
 
     match 'c' {
       'A' ..= 'z' => {}
       'a' ..= 'z' => {}
+      //~^ ERROR unreachable pattern
       _ => {}
     };
 
     match 1.0f64 {
       0.01f64 ..= 6.5f64 => {}
-      0.02f64 => {}
+      //~^ WARNING floating-point types cannot be used in patterns
+      //~| WARNING floating-point types cannot be used in patterns
+      //~| WARNING floating-point types cannot be used in patterns
+      //~| WARNING this was previously accepted by the compiler
+      //~| WARNING this was previously accepted by the compiler
+      //~| WARNING this was previously accepted by the compiler
+      0.02f64 => {} //~ ERROR unreachable pattern
+      //~^ WARNING floating-point types cannot be used in patterns
+      //~| WARNING this was previously accepted by the compiler
       _ => {}
     };
 }
diff --git a/src/test/ui/match/match-range-fail-dominate.stderr b/src/test/ui/match/match-range-fail-dominate.stderr
index d0ff4930a45..c15186d2558 100644
--- a/src/test/ui/match/match-range-fail-dominate.stderr
+++ b/src/test/ui/match/match-range-fail-dominate.stderr
@@ -1,35 +1,35 @@
 error: unreachable pattern
-  --> $DIR/match-range-fail-dominate.rs:12:7
+  --> $DIR/match-range-fail-dominate.rs:6:7
    |
 LL |       5 ..= 6 => { }
    |       ^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/match-range-fail-dominate.rs:7:9
+  --> $DIR/match-range-fail-dominate.rs:1:9
    |
-LL | #![deny(unreachable_patterns)]
+LL | #![deny(unreachable_patterns, overlapping_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/match-range-fail-dominate.rs:18:7
+  --> $DIR/match-range-fail-dominate.rs:13:7
    |
 LL |       4 ..= 6 => { }
    |       ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/match-range-fail-dominate.rs:24:7
+  --> $DIR/match-range-fail-dominate.rs:20:7
    |
 LL |       4 ..= 6 => { }
    |       ^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/match-range-fail-dominate.rs:30:7
+  --> $DIR/match-range-fail-dominate.rs:27:7
    |
 LL |       'a' ..= 'z' => {}
    |       ^^^^^^^^^^^
 
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-range-fail-dominate.rs:35:7
+  --> $DIR/match-range-fail-dominate.rs:33:7
    |
 LL |       0.01f64 ..= 6.5f64 => {}
    |       ^^^^^^^
@@ -39,7 +39,7 @@ LL |       0.01f64 ..= 6.5f64 => {}
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-range-fail-dominate.rs:35:19
+  --> $DIR/match-range-fail-dominate.rs:33:19
    |
 LL |       0.01f64 ..= 6.5f64 => {}
    |                   ^^^^^^
@@ -48,7 +48,7 @@ LL |       0.01f64 ..= 6.5f64 => {}
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-range-fail-dominate.rs:36:7
+  --> $DIR/match-range-fail-dominate.rs:40:7
    |
 LL |       0.02f64 => {}
    |       ^^^^^^^
@@ -57,13 +57,13 @@ LL |       0.02f64 => {}
    = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
 
 error: unreachable pattern
-  --> $DIR/match-range-fail-dominate.rs:36:7
+  --> $DIR/match-range-fail-dominate.rs:40:7
    |
 LL |       0.02f64 => {}
    |       ^^^^^^^
 
 warning: floating-point types cannot be used in patterns
-  --> $DIR/match-range-fail-dominate.rs:35:7
+  --> $DIR/match-range-fail-dominate.rs:33:7
    |
 LL |       0.01f64 ..= 6.5f64 => {}
    |       ^^^^^^^
diff --git a/src/test/ui/match/match-ref-mut-invariance.stderr b/src/test/ui/match/match-ref-mut-invariance.stderr
index 30bbb8d7800..0a020989d6f 100644
--- a/src/test/ui/match/match-ref-mut-invariance.stderr
+++ b/src/test/ui/match/match-ref-mut-invariance.stderr
@@ -6,12 +6,12 @@ LL |         match self.0 { ref mut x => x }
    |
    = note: expected type `&'a mut &'a i32`
               found type `&'a mut &'b i32`
-note: the lifetime 'a as defined on the method body at 9:12...
+note: the lifetime `'a` as defined on the method body at 9:12...
   --> $DIR/match-ref-mut-invariance.rs:9:12
    |
 LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
    |            ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 8:6
+note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 8:6
   --> $DIR/match-ref-mut-invariance.rs:8:6
    |
 LL | impl<'b> S<'b> {
diff --git a/src/test/ui/match/match-ref-mut-let-invariance.stderr b/src/test/ui/match/match-ref-mut-let-invariance.stderr
index 6ca222d9c2f..1bea9bce11e 100644
--- a/src/test/ui/match/match-ref-mut-let-invariance.stderr
+++ b/src/test/ui/match/match-ref-mut-let-invariance.stderr
@@ -6,12 +6,12 @@ LL |         x
    |
    = note: expected type `&'a mut &'a i32`
               found type `&'a mut &'b i32`
-note: the lifetime 'a as defined on the method body at 9:12...
+note: the lifetime `'a` as defined on the method body at 9:12...
   --> $DIR/match-ref-mut-let-invariance.rs:9:12
    |
 LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
    |            ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 8:6
+note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 8:6
   --> $DIR/match-ref-mut-let-invariance.rs:8:6
    |
 LL | impl<'b> S<'b> {
diff --git a/src/test/ui/mir/mir_calls_to_shims.rs b/src/test/ui/mir/mir_calls_to_shims.rs
index 6f13d5612ce..de8d958af45 100644
--- a/src/test/ui/mir/mir_calls_to_shims.rs
+++ b/src/test/ui/mir/mir_calls_to_shims.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![feature(fn_traits)]
 #![feature(never_type)]
diff --git a/src/test/ui/mir/mir_drop_order.rs b/src/test/ui/mir/mir_drop_order.rs
index 2949437b1e4..2bc5cf1c976 100644
--- a/src/test/ui/mir/mir_drop_order.rs
+++ b/src/test/ui/mir/mir_drop_order.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 use std::cell::RefCell;
 use std::panic;
diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr
index 27df0241aa2..2b77d866fb3 100644
--- a/src/test/ui/mod/mod_file_disambig.stderr
+++ b/src/test/ui/mod/mod_file_disambig.stderr
@@ -8,3 +8,4 @@ LL | mod mod_file_disambig_aux;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0584`.
diff --git a/src/test/ui/multiple-plugin-registrars.stderr b/src/test/ui/multiple-plugin-registrars.stderr
index 3a7895a08c6..dad8172e0c5 100644
--- a/src/test/ui/multiple-plugin-registrars.stderr
+++ b/src/test/ui/multiple-plugin-registrars.stderr
@@ -1,16 +1,16 @@
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/multiple-plugin-registrars.rs:6:1
    |
 LL | #[plugin_registrar]
-   | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/issues/29597
+warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/multiple-plugin-registrars.rs:9:1
    |
 LL | #[plugin_registrar]
-   | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
 
 error: multiple plugin registration functions found
    |
diff --git a/src/test/run-fail/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs
index 8661a2f80a7..3aa5866ebfb 100644
--- a/src/test/run-fail/adjust_never.rs
+++ b/src/test/ui/never_type/adjust_never.rs
@@ -1,5 +1,6 @@
 // Test that a variable of type ! can coerce to another type.
 
+// run-fail
 // error-pattern:explicit
 
 #![feature(never_type)]
diff --git a/src/test/ui/call-fn-never-arg-wrong-type.rs b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs
index d06637e74a2..d06637e74a2 100644
--- a/src/test/ui/call-fn-never-arg-wrong-type.rs
+++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs
diff --git a/src/test/ui/call-fn-never-arg-wrong-type.stderr b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr
index 7a50fd367d2..7a50fd367d2 100644
--- a/src/test/ui/call-fn-never-arg-wrong-type.stderr
+++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr
diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs
index f5b2cfaefe0..6218572f8a7 100644
--- a/src/test/run-fail/call-fn-never-arg.rs
+++ b/src/test/ui/never_type/call-fn-never-arg.rs
@@ -1,5 +1,6 @@
 // Test that we can use a ! for an argument of type !
 
+// run-fail
 // error-pattern:wowzers!
 
 #![feature(never_type)]
diff --git a/src/test/run-fail/cast-never.rs b/src/test/ui/never_type/cast-never.rs
index 0b05a4b9112..46072e186e0 100644
--- a/src/test/run-fail/cast-never.rs
+++ b/src/test/ui/never_type/cast-never.rs
@@ -1,5 +1,6 @@
 // Test that we can explicitly cast ! to another type
 
+// run-fail
 // error-pattern:explicit
 
 #![feature(never_type)]
diff --git a/src/test/ui/defaulted-never-note.rs b/src/test/ui/never_type/defaulted-never-note.rs
index d3fb8a09414..d3fb8a09414 100644
--- a/src/test/ui/defaulted-never-note.rs
+++ b/src/test/ui/never_type/defaulted-never-note.rs
diff --git a/src/test/ui/defaulted-never-note.stderr b/src/test/ui/never_type/defaulted-never-note.stderr
index 28c9da059ed..28c9da059ed 100644
--- a/src/test/ui/defaulted-never-note.stderr
+++ b/src/test/ui/never_type/defaulted-never-note.stderr
diff --git a/src/test/ui/dispatch_from_dyn_zst.rs b/src/test/ui/never_type/dispatch_from_dyn_zst.rs
index 764f58ce9e8..764f58ce9e8 100644
--- a/src/test/ui/dispatch_from_dyn_zst.rs
+++ b/src/test/ui/never_type/dispatch_from_dyn_zst.rs
diff --git a/src/test/ui/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs
index 0f0f787b407..c68e6364ed4 100644
--- a/src/test/ui/diverging-fallback-control-flow.rs
+++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs
@@ -4,6 +4,7 @@
 #![allow(unused_assignments)]
 #![allow(unused_variables)]
 #![allow(unreachable_code)]
+
 // Test various cases where we permit an unconstrained variable
 // to fallback based on control-flow.
 //
diff --git a/src/test/ui/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs
index c5f12981ecc..9423f08858b 100644
--- a/src/test/ui/impl-for-never.rs
+++ b/src/test/ui/never_type/impl-for-never.rs
@@ -1,8 +1,9 @@
 // run-pass
-// Test that we can call static methods on ! both directly and when it appears in a generic
 
 #![feature(never_type)]
 
+// Test that we can call static methods on ! both directly and when it appears in a generic
+
 trait StringifyType {
     fn stringify_type() -> &'static str;
 }
diff --git a/src/test/ui/issues/issue-13352.rs b/src/test/ui/never_type/issue-13352.rs
index e6995be27d2..e6995be27d2 100644
--- a/src/test/ui/issues/issue-13352.rs
+++ b/src/test/ui/never_type/issue-13352.rs
diff --git a/src/test/ui/issues/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr
index 58ac74be3e3..58ac74be3e3 100644
--- a/src/test/ui/issues/issue-13352.stderr
+++ b/src/test/ui/never_type/issue-13352.stderr
diff --git a/src/test/ui/issues/issue-2149.rs b/src/test/ui/never_type/issue-2149.rs
index d46f0e61793..d46f0e61793 100644
--- a/src/test/ui/issues/issue-2149.rs
+++ b/src/test/ui/never_type/issue-2149.rs
diff --git a/src/test/ui/issues/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr
index 8ce2ba03332..8ce2ba03332 100644
--- a/src/test/ui/issues/issue-2149.stderr
+++ b/src/test/ui/never_type/issue-2149.stderr
diff --git a/src/test/ui/issues/issue-44402.rs b/src/test/ui/never_type/issue-44402.rs
index 29b7eb5ee49..699e480dfe7 100644
--- a/src/test/ui/issues/issue-44402.rs
+++ b/src/test/ui/never_type/issue-44402.rs
@@ -1,4 +1,5 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
+
 #![allow(dead_code)]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
diff --git a/src/test/ui/never-assign-dead-code.rs b/src/test/ui/never_type/never-assign-dead-code.rs
index fd5fbc30611..7bb7c87097c 100644
--- a/src/test/ui/never-assign-dead-code.rs
+++ b/src/test/ui/never_type/never-assign-dead-code.rs
@@ -1,10 +1,10 @@
 // Test that an assignment of type ! makes the rest of the block dead code.
 
+// check-pass
+
 #![feature(never_type)]
-// build-pass (FIXME(62277): could be check-pass?)
 #![warn(unused)]
 
-
 fn main() {
     let x: ! = panic!("aah"); //~ WARN unused
     drop(x); //~ WARN unreachable
diff --git a/src/test/ui/never-assign-dead-code.stderr b/src/test/ui/never_type/never-assign-dead-code.stderr
index b887d580e68..1860150fa8b 100644
--- a/src/test/ui/never-assign-dead-code.stderr
+++ b/src/test/ui/never_type/never-assign-dead-code.stderr
@@ -7,7 +7,7 @@ LL |     drop(x);
    |     ^^^^^^^^ unreachable statement
    |
 note: lint level defined here
-  --> $DIR/never-assign-dead-code.rs:5:9
+  --> $DIR/never-assign-dead-code.rs:6:9
    |
 LL | #![warn(unused)]
    |         ^^^^^^
@@ -29,7 +29,7 @@ LL |     let x: ! = panic!("aah");
    |         ^ help: consider prefixing with an underscore: `_x`
    |
 note: lint level defined here
-  --> $DIR/never-assign-dead-code.rs:5:9
+  --> $DIR/never-assign-dead-code.rs:6:9
    |
 LL | #![warn(unused)]
    |         ^^^^^^
diff --git a/src/test/ui/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs
index 67e26f5663f..67e26f5663f 100644
--- a/src/test/ui/never-assign-wrong-type.rs
+++ b/src/test/ui/never_type/never-assign-wrong-type.rs
diff --git a/src/test/ui/never-assign-wrong-type.stderr b/src/test/ui/never_type/never-assign-wrong-type.stderr
index da2e77d023d..da2e77d023d 100644
--- a/src/test/ui/never-assign-wrong-type.stderr
+++ b/src/test/ui/never_type/never-assign-wrong-type.stderr
diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/ui/never_type/never-associated-type.rs
index 587f0f72d5a..7f0a3fef6a9 100644
--- a/src/test/run-fail/never-associated-type.rs
+++ b/src/test/ui/never_type/never-associated-type.rs
@@ -1,5 +1,6 @@
 // Test that we can use ! as an associated type.
 
+// run-fail
 // error-pattern:kapow!
 
 #![feature(never_type)]
diff --git a/src/test/ui/never-from-impl-is-reserved.rs b/src/test/ui/never_type/never-from-impl-is-reserved.rs
index 9d16015bdc1..9d16015bdc1 100644
--- a/src/test/ui/never-from-impl-is-reserved.rs
+++ b/src/test/ui/never_type/never-from-impl-is-reserved.rs
diff --git a/src/test/ui/never-from-impl-is-reserved.stderr b/src/test/ui/never_type/never-from-impl-is-reserved.stderr
index 8b8d0f4ea73..8b8d0f4ea73 100644
--- a/src/test/ui/never-from-impl-is-reserved.stderr
+++ b/src/test/ui/never_type/never-from-impl-is-reserved.stderr
diff --git a/src/test/ui/never-result.rs b/src/test/ui/never_type/never-result.rs
index 98ce326aa66..35af37910ef 100644
--- a/src/test/ui/never-result.rs
+++ b/src/test/ui/never_type/never-result.rs
@@ -2,6 +2,7 @@
 
 #![allow(unused_variables)]
 #![allow(unreachable_code)]
+
 // Test that we can extract a ! through pattern matching then use it as several different types.
 
 #![feature(never_type)]
diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/ui/never_type/never-type-arg.rs
index 1747e96eef4..a82d351f6cf 100644
--- a/src/test/run-fail/never-type-arg.rs
+++ b/src/test/ui/never_type/never-type-arg.rs
@@ -1,5 +1,6 @@
 // Test that we can use ! as an argument to a trait impl.
 
+// run-fail
 // error-pattern:oh no!
 
 #![feature(never_type)]
diff --git a/src/test/ui/never-type-rvalues.rs b/src/test/ui/never_type/never-type-rvalues.rs
index 9ccc73dbf92..9ccc73dbf92 100644
--- a/src/test/ui/never-type-rvalues.rs
+++ b/src/test/ui/never_type/never-type-rvalues.rs
diff --git a/src/test/ui/never_coercions.rs b/src/test/ui/never_type/never_coercions.rs
index 105c3863533..105c3863533 100644
--- a/src/test/ui/never_coercions.rs
+++ b/src/test/ui/never_type/never_coercions.rs
diff --git a/src/test/ui/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs
index 5bad756b876..fce3ced9aac 100644
--- a/src/test/ui/never_transmute_never.rs
+++ b/src/test/ui/never_type/never_transmute_never.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![crate_type="lib"]
 
diff --git a/src/test/ui/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs
index b0d66295618..72b844d8b48 100644
--- a/src/test/ui/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/never_type/panic-uninitialized-zeroed.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare always compiled as panic=abort right now and this requires unwinding
+// ignore-emscripten compiled with panic=abort by default
 // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
 // in a runtime panic.
 
diff --git a/src/test/ui/try_from.rs b/src/test/ui/never_type/try_from.rs
index 50451576f9c..50451576f9c 100644
--- a/src/test/ui/try_from.rs
+++ b/src/test/ui/never_type/try_from.rs
diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr
index b19e3a9dfb3..74c33df37a0 100644
--- a/src/test/ui/nll/issue-50716.stderr
+++ b/src/test/ui/nll/issue-50716.stderr
@@ -6,7 +6,7 @@ LL |     let _x = *s;
    |
    = note: expected type `std::marker::Sized`
               found type `std::marker::Sized`
-note: the lifetime 'a as defined on the function body at 9:8...
+note: the lifetime `'a` as defined on the function body at 9:8...
   --> $DIR/issue-50716.rs:9:8
    |
 LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr
index 90a35177f4c..0cdc2d94439 100644
--- a/src/test/ui/nll/issue-52742.stderr
+++ b/src/test/ui/nll/issue-52742.stderr
@@ -4,7 +4,7 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |         self.y = b.z
    |                  ^^^
    |
-note: ...the reference is valid for the lifetime '_ as defined on the impl at 12:10...
+note: ...the reference is valid for the lifetime `'_` as defined on the impl at 12:10...
   --> $DIR/issue-52742.rs:12:10
    |
 LL | impl Foo<'_, '_> {
diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr
index e00e6f36f1a..714a63b670c 100644
--- a/src/test/ui/nll/issue-55394.stderr
+++ b/src/test/ui/nll/issue-55394.stderr
@@ -16,7 +16,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |         Foo { bar }
    |               ^^^
-note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 7:10...
+note: but, the lifetime must be valid for the lifetime `'_` as defined on the impl at 7:10...
   --> $DIR/issue-55394.rs:7:10
    |
 LL | impl Foo<'_> {
diff --git a/src/test/ui/nll/issue-55401.stderr b/src/test/ui/nll/issue-55401.stderr
index 4ec16ba055a..2dc7236cbc2 100644
--- a/src/test/ui/nll/issue-55401.stderr
+++ b/src/test/ui/nll/issue-55401.stderr
@@ -5,7 +5,7 @@ LL |     *y
    |     ^^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 1:47
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 1:47
   --> $DIR/issue-55401.rs:1:47
    |
 LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr
index 77a372d9cf5..3a152fbc6fc 100644
--- a/src/test/ui/nll/normalization-bounds-error.stderr
+++ b/src/test/ui/nll/normalization-bounds-error.stderr
@@ -4,12 +4,12 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` d
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'd as defined on the function body at 12:14...
+note: first, the lifetime cannot outlive the lifetime `'d` as defined on the function body at 12:14...
   --> $DIR/normalization-bounds-error.rs:12:14
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    |              ^^
-note: ...but the lifetime must also be valid for the lifetime 'a as defined on the function body at 12:18...
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the function body at 12:18...
   --> $DIR/normalization-bounds-error.rs:12:18
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
diff --git a/src/test/ui/nll/trait-associated-constant.stderr b/src/test/ui/nll/trait-associated-constant.stderr
index f39f668e232..ecf9748af9e 100644
--- a/src/test/ui/nll/trait-associated-constant.stderr
+++ b/src/test/ui/nll/trait-associated-constant.stderr
@@ -6,12 +6,12 @@ LL |     const AC: Option<&'c str> = None;
    |
    = note: expected type `std::option::Option<&'b str>`
               found type `std::option::Option<&'c str>`
-note: the lifetime 'c as defined on the impl at 20:18...
+note: the lifetime `'c` as defined on the impl at 20:18...
   --> $DIR/trait-associated-constant.rs:20:18
    |
 LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
    |                  ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 20:14
+note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 20:14
   --> $DIR/trait-associated-constant.rs:20:14
    |
 LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr
index 74651741752..6986389af88 100644
--- a/src/test/ui/nll/type-alias-free-regions.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.stderr
@@ -14,7 +14,7 @@ LL | |     }
    = note: ...so that the expression is assignable:
            expected std::boxed::Box<std::boxed::Box<&isize>>
               found std::boxed::Box<std::boxed::Box<&isize>>
-note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 15:6...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6...
   --> $DIR/type-alias-free-regions.rs:15:6
    |
 LL | impl<'a> FromBox<'a> for C<'a> {
@@ -39,7 +39,7 @@ LL | |     }
    = note: ...so that the expression is assignable:
            expected std::boxed::Box<&isize>
               found std::boxed::Box<&isize>
-note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 25:6...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6...
   --> $DIR/type-alias-free-regions.rs:25:6
    |
 LL | impl<'a> FromTuple<'a> for C<'a> {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
index f5657f9e4ea..4ebd9910788 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 LL |     <Foo<'a>>::C
    |     ^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 7:8...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 7:8...
   --> $DIR/constant-in-expr-inherent-1.rs:7:8
    |
 LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
index 0a8ad4221c9..4c7adf75d2f 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
@@ -5,7 +5,7 @@ LL |     <() as Foo<'a>>::C
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 17:8
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 17:8
   --> $DIR/constant-in-expr-normalize.rs:17:8
    |
 LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
index d596aaf098f..d01d022cba7 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
@@ -5,7 +5,7 @@ LL |     <() as Foo<'a>>::C
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 9:8
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 9:8
   --> $DIR/constant-in-expr-trait-item-1.rs:9:8
    |
 LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
index 80ff9a043d4..dd294280b90 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
@@ -5,7 +5,7 @@ LL |     <T as Foo<'a>>::C
    |     ^^^^^^^^^^^^^^^^^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 9:8
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 9:8
   --> $DIR/constant-in-expr-trait-item-2.rs:9:8
    |
 LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
index f7db4038b8a..d61659e7e9a 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 LL |     T::C
    |     ^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:8...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:8...
   --> $DIR/constant-in-expr-trait-item-3.rs:9:8
    |
 LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
diff --git a/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs b/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs
index d210abdf499..ced3c61ec16 100644
--- a/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs
+++ b/src/test/ui/numbers-arithmetic/float-int-invalid-const-cast.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-emscripten no i128 support
 
 #![deny(const_err)]
 
diff --git a/src/test/ui/numbers-arithmetic/i128.rs b/src/test/ui/numbers-arithmetic/i128.rs
index ea0ef95e4f1..ef558c0aa0c 100644
--- a/src/test/ui/numbers-arithmetic/i128.rs
+++ b/src/test/ui/numbers-arithmetic/i128.rs
@@ -1,9 +1,6 @@
 // run-pass
 #![allow(overflowing_literals)]
 
-// ignore-emscripten i128 doesn't work
-
-
 #![feature(test)]
 
 extern crate test;
diff --git a/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs b/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
index e9927304f23..c1959866e5c 100644
--- a/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
+++ b/src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
@@ -1,6 +1,6 @@
 // run-pass
 // compile-flags: -C debug_assertions=yes
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // ignore-emscripten dies with an LLVM error
 
 use std::panic;
diff --git a/src/test/ui/numbers-arithmetic/u128-as-f32.rs b/src/test/ui/numbers-arithmetic/u128-as-f32.rs
index bef7deb6276..2671a267f4a 100644
--- a/src/test/ui/numbers-arithmetic/u128-as-f32.rs
+++ b/src/test/ui/numbers-arithmetic/u128-as-f32.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-emscripten u128 not supported
 
 #![feature(test)]
 #![deny(overflowing_literals)]
diff --git a/src/test/ui/numbers-arithmetic/u128.rs b/src/test/ui/numbers-arithmetic/u128.rs
index 93940716323..0b2305c6e8b 100644
--- a/src/test/ui/numbers-arithmetic/u128.rs
+++ b/src/test/ui/numbers-arithmetic/u128.rs
@@ -1,6 +1,4 @@
 // run-pass
-// ignore-emscripten u128 not supported
-
 
 #![feature(test)]
 
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
index 217e8504aa3..d66322c48ec 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to
 LL |     ss
    |     ^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 54:10...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 54:10...
   --> $DIR/object-lifetime-default-elision.rs:54:10
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
@@ -14,7 +14,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |     ss
    |     ^^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 54:13...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 54:13...
   --> $DIR/object-lifetime-default-elision.rs:54:13
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
@@ -29,7 +29,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |     ss
    |     ^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 54:10...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 54:10...
   --> $DIR/object-lifetime-default-elision.rs:54:10
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
@@ -39,7 +39,7 @@ note: ...so that the declared lifetime parameter bounds are satisfied
    |
 LL |     ss
    |     ^^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 54:13...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 54:13...
   --> $DIR/object-lifetime-default-elision.rs:54:13
    |
 LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr
index 4f9cef12c5e..99f0ce0602b 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr
@@ -6,7 +6,7 @@ LL |     ss.t = t;
    |
    = note: expected type `&'a std::boxed::Box<(dyn Test + 'static)>`
               found type `&'a std::boxed::Box<(dyn Test + 'a)>`
-note: the lifetime 'a as defined on the function body at 14:6...
+note: the lifetime `'a` as defined on the function body at 14:6...
   --> $DIR/object-lifetime-default-from-rptr-box-error.rs:14:6
    |
 LL | fn c<'a>(t: &'a Box<dyn Test+'a>, mut ss: SomeStruct<'a>) {
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr
index 3b7faee68aa..07d4d8c8ed4 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.stderr
@@ -6,7 +6,7 @@ LL |     ss.t = t;
    |
    = note: expected type `&'a MyBox<(dyn Test + 'static)>`
               found type `&'a MyBox<(dyn Test + 'a)>`
-note: the lifetime 'a as defined on the function body at 20:6...
+note: the lifetime `'a` as defined on the function body at 20:6...
   --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:6
    |
 LL | fn c<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr
index 928b9201982..f825475b96b 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.stderr
@@ -18,7 +18,7 @@ LL |     load0(ss)
    |
    = note: expected type `&MyBox<(dyn SomeTrait + 'static)>`
               found type `&MyBox<(dyn SomeTrait + 'a)>`
-note: the lifetime 'a as defined on the function body at 30:10...
+note: the lifetime `'a` as defined on the function body at 30:10...
   --> $DIR/object-lifetime-default-mybox.rs:30:10
    |
 LL | fn load2<'a>(ss: &MyBox<dyn SomeTrait + 'a>) -> MyBox<dyn SomeTrait + 'a> {
diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs
index 5d72771c2dc..6dcb852a366 100644
--- a/src/test/ui/panic-runtime/transitive-link-a-bunch.rs
+++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.rs
@@ -4,7 +4,7 @@
 // aux-build:wants-panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
 // error-pattern: is not compiled with this crate's panic strategy `unwind`
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![no_std]
 #![no_main]
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
index 4c25c09d643..e7811d40b5b 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
@@ -1,7 +1,7 @@
 // error-pattern:is incompatible with this crate's strategy of `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![no_std]
 #![no_main]
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs
index 478af451e7f..44671796c01 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort2.rs
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.rs
@@ -2,7 +2,7 @@
 // aux-build:panic-runtime-abort.rs
 // aux-build:wants-panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![no_std]
 #![no_main]
diff --git a/src/test/ui/parser/doc-inside-trait-item.stderr b/src/test/ui/parser/doc-inside-trait-item.stderr
index 3287ece9ae6..261e27b6e0d 100644
--- a/src/test/ui/parser/doc-inside-trait-item.stderr
+++ b/src/test/ui/parser/doc-inside-trait-item.stderr
@@ -8,3 +8,4 @@ LL |     /// empty doc
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0584`.
diff --git a/src/test/ui/parser/intersection-patterns.rs b/src/test/ui/parser/intersection-patterns.rs
new file mode 100644
index 00000000000..adb607cf6b9
--- /dev/null
+++ b/src/test/ui/parser/intersection-patterns.rs
@@ -0,0 +1,40 @@
+// This tests the parser recovery in `recover_intersection_pat`
+// and serves as a regression test for the diagnostics issue #65400.
+//
+// The general idea is that for `$pat_lhs @ $pat_rhs` where
+// `$pat_lhs` is not generated by `ref? mut? $ident` we want
+// to suggest either switching the order or note that intersection
+// patterns are not allowed.
+
+fn main() {
+    let s: Option<u8> = None;
+
+    match s {
+        Some(x) @ y => {}
+        //~^ ERROR pattern on wrong side of `@`
+        //~| pattern on the left, should be on the right
+        //~| binding on the right, should be on the left
+        //~| HELP switch the order
+        //~| SUGGESTION y @ Some(x)
+        _ => {}
+    }
+
+    match s {
+        Some(x) @ Some(y) => {}
+        //~^ ERROR left-hand side of `@` must be a binding
+        //~| interpreted as a pattern, not a binding
+        //~| also a pattern
+        //~| NOTE bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+        _ => {}
+    }
+
+    match 2 {
+        1 ..= 5 @ e => {}
+        //~^ ERROR pattern on wrong side of `@`
+        //~| pattern on the left, should be on the right
+        //~| binding on the right, should be on the left
+        //~| HELP switch the order
+        //~| SUGGESTION e @ 1 ..=5
+        _ => {}
+    }
+}
diff --git a/src/test/ui/parser/intersection-patterns.stderr b/src/test/ui/parser/intersection-patterns.stderr
new file mode 100644
index 00000000000..f5bfee5bbd6
--- /dev/null
+++ b/src/test/ui/parser/intersection-patterns.stderr
@@ -0,0 +1,33 @@
+error: pattern on wrong side of `@`
+  --> $DIR/intersection-patterns.rs:13:9
+   |
+LL |         Some(x) @ y => {}
+   |         -------^^^-
+   |         |         |
+   |         |         binding on the right, should be on the left
+   |         pattern on the left, should be on the right
+   |         help: switch the order: `y @ Some(x)`
+
+error: left-hand side of `@` must be a binding
+  --> $DIR/intersection-patterns.rs:23:9
+   |
+LL |         Some(x) @ Some(y) => {}
+   |         -------^^^-------
+   |         |         |
+   |         |         also a pattern
+   |         interpreted as a pattern, not a binding
+   |
+   = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+error: pattern on wrong side of `@`
+  --> $DIR/intersection-patterns.rs:32:9
+   |
+LL |         1 ..= 5 @ e => {}
+   |         -------^^^-
+   |         |         |
+   |         |         binding on the right, should be on the left
+   |         pattern on the left, should be on the right
+   |         help: switch the order: `e @ 1 ..=5`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.rs b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs
new file mode 100644
index 00000000000..0f5a2cb09ec
--- /dev/null
+++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.rs
@@ -0,0 +1,5 @@
+fn main() {
+
+}
+    let _ = ();
+} //~ ERROR unexpected close delimiter
diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr
new file mode 100644
index 00000000000..5ae5fc91a4e
--- /dev/null
+++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr
@@ -0,0 +1,14 @@
+error: unexpected close delimiter: `}`
+  --> $DIR/mismatched-delim-brace-empty-block.rs:5:1
+   |
+LL |   fn main() {
+   |  ___________-
+LL | |
+LL | | }
+   | |_- this block is empty, you might have not meant to close it
+LL |       let _ = ();
+LL |   }
+   |   ^ unexpected close delimiter
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr
index 9021bd30a77..6acc09b62c8 100644
--- a/src/test/ui/partialeq_help.stderr
+++ b/src/test/ui/partialeq_help.stderr
@@ -5,7 +5,6 @@ LL |     a == b;
    |       ^^ no implementation for `&T == T`
    |
    = help: the trait `std::cmp::PartialEq<T>` is not implemented for `&T`
-   = help: consider adding a `where &T: std::cmp::PartialEq<T>` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr
index ac48ee0cb0f..4d9d06b8986 100644
--- a/src/test/ui/phantom-oibit.stderr
+++ b/src/test/ui/phantom-oibit.stderr
@@ -3,12 +3,13 @@ error[E0277]: `T` cannot be shared between threads safely
    |
 LL | fn is_zen<T: Zen>(_: T) {}
    |    ------    --- required by this bound in `is_zen`
-...
+LL | 
+LL | fn not_sync<T>(x: Guard<T>) {
+   |             - help: consider restricting this bound: `T: std::marker::Sync`
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Sync` bound
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
@@ -19,11 +20,12 @@ error[E0277]: `T` cannot be shared between threads safely
 LL | fn is_zen<T: Zen>(_: T) {}
    |    ------    --- required by this bound in `is_zen`
 ...
+LL | fn nested_not_sync<T>(x: Nested<Guard<T>>) {
+   |                    - help: consider restricting this bound: `T: std::marker::Sync`
 LL |     is_zen(x)
    |            ^ `T` cannot be shared between threads safely
    |
    = help: the trait `std::marker::Sync` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Sync` bound
    = note: required because of the requirements on the impl of `Zen` for `&T`
    = note: required because it appears within the type `std::marker::PhantomData<&T>`
    = note: required because it appears within the type `Guard<'_, T>`
diff --git a/src/test/ui/precise_pointer_size_matching.rs b/src/test/ui/precise_pointer_size_matching.rs
index 759b63b188b..54aeb8616d9 100644
--- a/src/test/ui/precise_pointer_size_matching.rs
+++ b/src/test/ui/precise_pointer_size_matching.rs
@@ -8,7 +8,7 @@
 #![feature(precise_pointer_size_matching)]
 #![feature(exclusive_range_pattern)]
 
-#![deny(unreachable_patterns)]
+#![deny(unreachable_patterns, overlapping_patterns)]
 
 use std::{usize, isize};
 
diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr
index 09148f9d0e6..8ffc12c31cb 100644
--- a/src/test/ui/privacy/privacy-ns1.stderr
+++ b/src/test/ui/privacy/privacy-ns1.stderr
@@ -72,5 +72,5 @@ LL | use foo3::Bar;
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0412, E0423, E0425.
+Some errors have detailed explanations: E0412, E0423, E0425, E0573.
 For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr
index 8ea32f36f9e..13057a899f3 100644
--- a/src/test/ui/privacy/privacy-ns2.stderr
+++ b/src/test/ui/privacy/privacy-ns2.stderr
@@ -82,5 +82,5 @@ LL |     use foo3::{Bar,Baz};
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0423, E0603.
+Some errors have detailed explanations: E0423, E0573, E0603.
 For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs b/src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs
new file mode 100644
index 00000000000..548fefe76f5
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/gen-macro-rules-hygiene.rs
@@ -0,0 +1,23 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn gen_macro_rules(_: TokenStream) -> TokenStream {
+    "
+    macro_rules! generated {() => {
+        struct ItemDef;
+        let local_def = 0;
+
+        ItemUse; // OK
+        local_use; // ERROR
+        break 'label_use; // ERROR
+
+        type DollarCrate = $crate::ItemUse; // OK
+    }}
+    ".parse().unwrap()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/more-gates.rs b/src/test/ui/proc-macro/auxiliary/more-gates.rs
deleted file mode 100644
index 6b609eaee12..00000000000
--- a/src/test/ui/proc-macro/auxiliary/more-gates.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// force-host
-// no-prefer-dynamic
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::*;
-
-#[proc_macro_attribute]
-pub fn attr2mac1(_: TokenStream, _: TokenStream) -> TokenStream {
-    "macro_rules! foo1 { (a) => (a) }".parse().unwrap()
-}
-
-#[proc_macro_attribute]
-pub fn attr2mac2(_: TokenStream, _: TokenStream) -> TokenStream {
-    "macro foo2(a) { a }".parse().unwrap()
-}
-
-#[proc_macro]
-pub fn mac2mac1(_: TokenStream) -> TokenStream {
-    "macro_rules! foo3 { (a) => (a) }".parse().unwrap()
-}
-
-#[proc_macro]
-pub fn mac2mac2(_: TokenStream) -> TokenStream {
-    "macro foo4(a) { a }".parse().unwrap()
-}
-
-#[proc_macro]
-pub fn tricky(_: TokenStream) -> TokenStream {
-    "fn foo() {
-        macro_rules! foo { (a) => (a) }
-    }".parse().unwrap()
-}
diff --git a/src/test/ui/proc-macro/expand-with-a-macro.rs b/src/test/ui/proc-macro/expand-with-a-macro.rs
index 418178d0f0e..690a76ef3e0 100644
--- a/src/test/ui/proc-macro/expand-with-a-macro.rs
+++ b/src/test/ui/proc-macro/expand-with-a-macro.rs
@@ -1,7 +1,7 @@
 // run-pass
 // aux-build:expand-with-a-macro.rs
 
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![deny(warnings)]
 
diff --git a/src/test/ui/proc-macro/gen-macro-rules-hygiene.rs b/src/test/ui/proc-macro/gen-macro-rules-hygiene.rs
new file mode 100644
index 00000000000..195bda82e9c
--- /dev/null
+++ b/src/test/ui/proc-macro/gen-macro-rules-hygiene.rs
@@ -0,0 +1,23 @@
+// `macro_rules` items produced by transparent macros have correct hygiene in basic cases.
+// Local variables and labels are hygienic, items are not hygienic.
+// `$crate` refers to the crate that defines `macro_rules` and not the outer transparent macro.
+
+// aux-build:gen-macro-rules-hygiene.rs
+
+#[macro_use]
+extern crate gen_macro_rules_hygiene;
+
+struct ItemUse;
+
+gen_macro_rules!();
+//~^ ERROR use of undeclared label `'label_use`
+//~| ERROR cannot find value `local_use` in this scope
+
+fn main() {
+    'label_use: loop {
+        let local_use = 1;
+        generated!();
+        ItemDef; // OK
+        local_def; //~ ERROR cannot find value `local_def` in this scope
+    }
+}
diff --git a/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr b/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
new file mode 100644
index 00000000000..ecebdfa9656
--- /dev/null
+++ b/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
@@ -0,0 +1,28 @@
+error[E0426]: use of undeclared label `'label_use`
+  --> $DIR/gen-macro-rules-hygiene.rs:12:1
+   |
+LL | gen_macro_rules!();
+   | ^^^^^^^^^^^^^^^^^^^ undeclared label `'label_use`
+...
+LL |         generated!();
+   |         ------------- in this macro invocation
+
+error[E0425]: cannot find value `local_use` in this scope
+  --> $DIR/gen-macro-rules-hygiene.rs:12:1
+   |
+LL | gen_macro_rules!();
+   | ^^^^^^^^^^^^^^^^^^^ not found in this scope
+...
+LL |         generated!();
+   |         ------------- in this macro invocation
+
+error[E0425]: cannot find value `local_def` in this scope
+  --> $DIR/gen-macro-rules-hygiene.rs:21:9
+   |
+LL |         local_def;
+   |         ^^^^^^^^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0425, E0426.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui/proc-macro/more-gates.rs b/src/test/ui/proc-macro/more-gates.rs
deleted file mode 100644
index b870b438a65..00000000000
--- a/src/test/ui/proc-macro/more-gates.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// aux-build:more-gates.rs
-
-#![feature(decl_macro)]
-
-extern crate more_gates as foo;
-
-use foo::*;
-
-#[attr2mac1]
-//~^ ERROR: cannot expand to macro definitions
-pub fn a() {}
-#[attr2mac2]
-//~^ ERROR: cannot expand to macro definitions
-pub fn a() {}
-
-mac2mac1!(); //~ ERROR: cannot expand to macro definitions
-mac2mac2!(); //~ ERROR: cannot expand to macro definitions
-
-tricky!();
-//~^ ERROR: cannot expand to macro definitions
-
-fn main() {}
diff --git a/src/test/ui/proc-macro/more-gates.stderr b/src/test/ui/proc-macro/more-gates.stderr
deleted file mode 100644
index ad96f78c77a..00000000000
--- a/src/test/ui/proc-macro/more-gates.stderr
+++ /dev/null
@@ -1,48 +0,0 @@
-error[E0658]: procedural macros cannot expand to macro definitions
-  --> $DIR/more-gates.rs:9:1
-   |
-LL | #[attr2mac1]
-   | ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
-error[E0658]: procedural macros cannot expand to macro definitions
-  --> $DIR/more-gates.rs:12:1
-   |
-LL | #[attr2mac2]
-   | ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
-error[E0658]: procedural macros cannot expand to macro definitions
-  --> $DIR/more-gates.rs:16:1
-   |
-LL | mac2mac1!();
-   | ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
-error[E0658]: procedural macros cannot expand to macro definitions
-  --> $DIR/more-gates.rs:17:1
-   |
-LL | mac2mac2!();
-   | ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
-error[E0658]: procedural macros cannot expand to macro definitions
-  --> $DIR/more-gates.rs:19:1
-   |
-LL | tricky!();
-   | ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/54727
-   = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/reachable-unnameable-items.rs b/src/test/ui/reachable-unnameable-items.rs
index f1e53a0d8b4..26c51efea1e 100644
--- a/src/test/ui/reachable-unnameable-items.rs
+++ b/src/test/ui/reachable-unnameable-items.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // aux-build:reachable-unnameable-items.rs
 
 extern crate reachable_unnameable_items;
diff --git a/src/test/ui/unreachable/auxiliary/unreachable_variant.rs b/src/test/ui/reachable/auxiliary/unreachable_variant.rs
index 4e94a4b5ed8..4e94a4b5ed8 100644
--- a/src/test/ui/unreachable/auxiliary/unreachable_variant.rs
+++ b/src/test/ui/reachable/auxiliary/unreachable_variant.rs
diff --git a/src/test/ui/unreachable/unreachable-arm.rs b/src/test/ui/reachable/unreachable-arm.rs
index 64c38968516..64c38968516 100644
--- a/src/test/ui/unreachable/unreachable-arm.rs
+++ b/src/test/ui/reachable/unreachable-arm.rs
diff --git a/src/test/ui/unreachable/unreachable-arm.stderr b/src/test/ui/reachable/unreachable-arm.stderr
index 8e65745c7b0..8e65745c7b0 100644
--- a/src/test/ui/unreachable/unreachable-arm.stderr
+++ b/src/test/ui/reachable/unreachable-arm.stderr
diff --git a/src/test/ui/unreachable/unreachable-code.rs b/src/test/ui/reachable/unreachable-code.rs
index ad0dc8a8b9c..ad0dc8a8b9c 100644
--- a/src/test/ui/unreachable/unreachable-code.rs
+++ b/src/test/ui/reachable/unreachable-code.rs
diff --git a/src/test/ui/unreachable/unreachable-code.stderr b/src/test/ui/reachable/unreachable-code.stderr
index 184440db5df..184440db5df 100644
--- a/src/test/ui/unreachable/unreachable-code.stderr
+++ b/src/test/ui/reachable/unreachable-code.stderr
diff --git a/src/test/ui/unreachable/unreachable-in-call.rs b/src/test/ui/reachable/unreachable-in-call.rs
index dd94e79f4d8..dd94e79f4d8 100644
--- a/src/test/ui/unreachable/unreachable-in-call.rs
+++ b/src/test/ui/reachable/unreachable-in-call.rs
diff --git a/src/test/ui/unreachable/unreachable-in-call.stderr b/src/test/ui/reachable/unreachable-in-call.stderr
index 1d081d1c762..1d081d1c762 100644
--- a/src/test/ui/unreachable/unreachable-in-call.stderr
+++ b/src/test/ui/reachable/unreachable-in-call.stderr
diff --git a/src/test/ui/unreachable/unreachable-loop-patterns.rs b/src/test/ui/reachable/unreachable-loop-patterns.rs
index 56ab1a270a7..6f1d2efa1b2 100644
--- a/src/test/ui/unreachable/unreachable-loop-patterns.rs
+++ b/src/test/ui/reachable/unreachable-loop-patterns.rs
@@ -1,5 +1,3 @@
-// compile-fail
-
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
 
diff --git a/src/test/ui/unreachable/unreachable-loop-patterns.stderr b/src/test/ui/reachable/unreachable-loop-patterns.stderr
index 254d1178d14..bb5103320d2 100644
--- a/src/test/ui/unreachable/unreachable-loop-patterns.stderr
+++ b/src/test/ui/reachable/unreachable-loop-patterns.stderr
@@ -1,17 +1,17 @@
 error: unreachable pattern
-  --> $DIR/unreachable-loop-patterns.rs:20:9
+  --> $DIR/unreachable-loop-patterns.rs:18:9
    |
 LL |     for _ in unimplemented!() as Void {}
    |         ^
    |
 note: lint level defined here
-  --> $DIR/unreachable-loop-patterns.rs:7:9
+  --> $DIR/unreachable-loop-patterns.rs:5:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/unreachable-loop-patterns.rs:20:14
+  --> $DIR/unreachable-loop-patterns.rs:18:14
    |
 LL |     for _ in unimplemented!() as Void {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/unreachable/unreachable-try-pattern.rs b/src/test/ui/reachable/unreachable-try-pattern.rs
index cbc5fcee2f0..23360e73f4a 100644
--- a/src/test/ui/unreachable/unreachable-try-pattern.rs
+++ b/src/test/ui/reachable/unreachable-try-pattern.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![feature(never_type, exhaustive_patterns)]
 #![warn(unreachable_code)]
 #![warn(unreachable_patterns)]
diff --git a/src/test/ui/unreachable/unreachable-try-pattern.stderr b/src/test/ui/reachable/unreachable-try-pattern.stderr
index 707038442a2..707038442a2 100644
--- a/src/test/ui/unreachable/unreachable-try-pattern.stderr
+++ b/src/test/ui/reachable/unreachable-try-pattern.stderr
diff --git a/src/test/ui/unreachable/unreachable-variant.rs b/src/test/ui/reachable/unreachable-variant.rs
index 008c2d476d7..008c2d476d7 100644
--- a/src/test/ui/unreachable/unreachable-variant.rs
+++ b/src/test/ui/reachable/unreachable-variant.rs
diff --git a/src/test/ui/unreachable/unreachable-variant.stderr b/src/test/ui/reachable/unreachable-variant.stderr
index 276c77f9b42..276c77f9b42 100644
--- a/src/test/ui/unreachable/unreachable-variant.stderr
+++ b/src/test/ui/reachable/unreachable-variant.stderr
diff --git a/src/test/ui/unreachable/unwarned-match-on-never.rs b/src/test/ui/reachable/unwarned-match-on-never.rs
index 71f8fe3a783..71f8fe3a783 100644
--- a/src/test/ui/unreachable/unwarned-match-on-never.rs
+++ b/src/test/ui/reachable/unwarned-match-on-never.rs
diff --git a/src/test/ui/unreachable/unwarned-match-on-never.stderr b/src/test/ui/reachable/unwarned-match-on-never.stderr
index 6b2fb4a33c1..6b2fb4a33c1 100644
--- a/src/test/ui/unreachable/unwarned-match-on-never.stderr
+++ b/src/test/ui/reachable/unwarned-match-on-never.stderr
diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
index 751a4c1021e..184cead2123 100644
--- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
+++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
@@ -10,12 +10,12 @@ error[E0478]: lifetime bound not satisfied
 LL |     z: Box<dyn Is<'a>+'b+'c>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: lifetime parameter instantiated with the lifetime 'b as defined on the struct at 11:15
+note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 11:15
   --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15
    |
 LL | struct Foo<'a,'b,'c> {
    |               ^^
-note: but lifetime parameter must outlive the lifetime 'a as defined on the struct at 11:12
+note: but lifetime parameter must outlive the lifetime `'a` as defined on the struct at 11:12
   --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:12
    |
 LL | struct Foo<'a,'b,'c> {
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.rs b/src/test/ui/regions/region-invariant-static-error-reporting.rs
index df92ed51e9a..911904813d0 100644
--- a/src/test/ui/regions/region-invariant-static-error-reporting.rs
+++ b/src/test/ui/regions/region-invariant-static-error-reporting.rs
@@ -3,7 +3,7 @@
 // over time, but this test used to exhibit some pretty bogus messages
 // that were not remotely helpful.
 
-// error-pattern:the lifetime 'a
+// error-pattern:the lifetime `'a`
 // error-pattern:the static lifetime
 
 struct Invariant<'a>(Option<&'a mut &'a mut ()>);
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.stderr
index 60e70ddcd97..8358a7988c8 100644
--- a/src/test/ui/regions/region-invariant-static-error-reporting.stderr
+++ b/src/test/ui/regions/region-invariant-static-error-reporting.stderr
@@ -13,7 +13,7 @@ LL | |     };
    |
    = note: expected type `Invariant<'a>`
               found type `Invariant<'static>`
-note: the lifetime 'a as defined on the function body at 13:10...
+note: the lifetime `'a` as defined on the function body at 13:10...
   --> $DIR/region-invariant-static-error-reporting.rs:13:10
    |
 LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
diff --git a/src/test/ui/regions/region-object-lifetime-2.stderr b/src/test/ui/regions/region-object-lifetime-2.stderr
index cc8d150d04c..74ea1b731e9 100644
--- a/src/test/ui/regions/region-object-lifetime-2.stderr
+++ b/src/test/ui/regions/region-object-lifetime-2.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflictin
 LL |     x.borrowed()
    |       ^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:42...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:42...
   --> $DIR/region-object-lifetime-2.rs:9:42
    |
 LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
@@ -14,7 +14,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |     x.borrowed()
    |     ^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 9:45...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 9:45...
   --> $DIR/region-object-lifetime-2.rs:9:45
    |
 LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
diff --git a/src/test/ui/regions/region-object-lifetime-4.stderr b/src/test/ui/regions/region-object-lifetime-4.stderr
index 23fd4d03628..10532182905 100644
--- a/src/test/ui/regions/region-object-lifetime-4.stderr
+++ b/src/test/ui/regions/region-object-lifetime-4.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflictin
 LL |     x.borrowed()
    |       ^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 11:41...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 11:41...
   --> $DIR/region-object-lifetime-4.rs:11:41
    |
 LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
@@ -14,7 +14,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |     x.borrowed()
    |     ^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 11:44...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 11:44...
   --> $DIR/region-object-lifetime-4.rs:11:44
    |
 LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (dyn Foo + 'b)) -> &'b () {
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index 3ccb8866ca4..14934d6fa48 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -29,7 +29,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |     Box::new(v)
    |              ^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 25:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 25:6...
   --> $DIR/region-object-lifetime-in-coercion.rs:25:6
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
@@ -37,7 +37,7 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    = note: ...so that the expression is assignable:
            expected &[u8]
               found &'a [u8]
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 25:9...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9...
   --> $DIR/region-object-lifetime-in-coercion.rs:25:9
    |
 LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.stderr
index ac5e5e9aabc..7a051b8ac83 100644
--- a/src/test/ui/regions/regions-addr-of-upvar-self.stderr
+++ b/src/test/ui/regions/regions-addr-of-upvar-self.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to
 LL |             let p: &'static mut usize = &mut self.food;
    |                                         ^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 9:18...
+note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 9:18...
   --> $DIR/regions-addr-of-upvar-self.rs:9:18
    |
 LL |         let _f = || {
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr
index 61be0778c99..c0401780b8f 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifet
 LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 33:15
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 33:15
   --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 33:18
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 33:18
   --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:18
    |
 LL | fn with_assoc<'a,'b>() {
diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
index d01e9911039..a636c9ef22c 100644
--- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 LL | impl<'a> Foo<'static> for &'a i32 {
    |          ^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 14:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 14:6...
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:6
    |
 LL | impl<'a> Foo<'static> for &'a i32 {
@@ -25,7 +25,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 LL | impl<'a,'b> Foo<'b> for &'a i64 {
    |             ^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 19:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 19:6...
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:6
    |
 LL | impl<'a,'b> Foo<'b> for &'a i64 {
@@ -33,7 +33,7 @@ LL | impl<'a,'b> Foo<'b> for &'a i64 {
    = note: ...so that the types are compatible:
            expected Foo<'b>
               found Foo<'_>
-note: but, the lifetime must be valid for the lifetime 'b as defined on the impl at 19:9...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9...
   --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9
    |
 LL | impl<'a,'b> Foo<'b> for &'a i64 {
diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
index 33a4ea01ce2..81256e3b46c 100644
--- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
+++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 LL | impl<'a> Foo for &'a i32 {
    |          ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 9:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 9:6...
   --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:6
    |
 LL | impl<'a> Foo for &'a i32 {
diff --git a/src/test/ui/regions/regions-bounds.stderr b/src/test/ui/regions/regions-bounds.stderr
index 27eb8891c6c..a15710b86c0 100644
--- a/src/test/ui/regions/regions-bounds.stderr
+++ b/src/test/ui/regions/regions-bounds.stderr
@@ -6,12 +6,12 @@ LL |     return e;
    |
    = note: expected type `TupleStruct<'b>`
               found type `TupleStruct<'a>`
-note: the lifetime 'a as defined on the function body at 8:10...
+note: the lifetime `'a` as defined on the function body at 8:10...
   --> $DIR/regions-bounds.rs:8:10
    |
 LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
    |          ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the function body at 8:13
+note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 8:13
   --> $DIR/regions-bounds.rs:8:13
    |
 LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
@@ -25,12 +25,12 @@ LL |     return e;
    |
    = note: expected type `Struct<'b>`
               found type `Struct<'a>`
-note: the lifetime 'a as defined on the function body at 12:10...
+note: the lifetime `'a` as defined on the function body at 12:10...
   --> $DIR/regions-bounds.rs:12:10
    |
 LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
    |          ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the function body at 12:13
+note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 12:13
   --> $DIR/regions-bounds.rs:12:13
    |
 LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 7af608d2c80..8e473dad693 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to
 LL |     box B(&*v) as Box<dyn X>
    |           ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
   --> $DIR/regions-close-object-into-object-2.rs:9:6
    |
 LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index ef47db18d39..c80d13e15b1 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to
 LL |     box B(&*v) as Box<dyn X>
    |           ^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6...
   --> $DIR/regions-close-object-into-object-4.rs:9:6
    |
 LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
index 6f7466a8b0e..ef21316ea83 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requiremen
 LL |     box v as Box<dyn SomeTrait + 'a>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 18:20...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 18:20...
   --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20
    |
 LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
@@ -14,7 +14,7 @@ note: ...so that the declared lifetime parameter bounds are satisfied
    |
 LL |     box v as Box<dyn SomeTrait + 'a>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: but, the lifetime must be valid for the lifetime 'c as defined on the function body at 18:26...
+note: but, the lifetime must be valid for the lifetime `'c` as defined on the function body at 18:26...
   --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26
    |
 LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr
index 4d00783d180..12b89787d5f 100644
--- a/src/test/ui/regions/regions-creating-enums4.stderr
+++ b/src/test/ui/regions/regions-creating-enums4.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
 LL |     Ast::Add(x, y)
    |     ^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 6:16...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 6:16...
   --> $DIR/regions-creating-enums4.rs:6:16
    |
 LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
@@ -12,7 +12,7 @@ LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
    = note: ...so that the expression is assignable:
            expected &Ast<'_>
               found &Ast<'a>
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 6:19...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19...
   --> $DIR/regions-creating-enums4.rs:6:19
    |
 LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
diff --git a/src/test/ui/regions/regions-early-bound-error-method.stderr b/src/test/ui/regions/regions-early-bound-error-method.stderr
index 7b9f2c9503b..9095451da05 100644
--- a/src/test/ui/regions/regions-early-bound-error-method.stderr
+++ b/src/test/ui/regions/regions-early-bound-error-method.stderr
@@ -4,12 +4,12 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |         g2.get()
    |         ^^^^^^^^
    |
-note: ...the reference is valid for the lifetime 'a as defined on the impl at 18:6...
+note: ...the reference is valid for the lifetime `'a` as defined on the impl at 18:6...
   --> $DIR/regions-early-bound-error-method.rs:18:6
    |
 LL | impl<'a> Box<'a> {
    |      ^^
-note: ...but the borrowed content is only valid for the lifetime 'b as defined on the method body at 19:11
+note: ...but the borrowed content is only valid for the lifetime `'b` as defined on the method body at 19:11
   --> $DIR/regions-early-bound-error-method.rs:19:11
    |
 LL |     fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
diff --git a/src/test/ui/regions/regions-early-bound-error.stderr b/src/test/ui/regions/regions-early-bound-error.stderr
index a68355b78f5..162d573362d 100644
--- a/src/test/ui/regions/regions-early-bound-error.stderr
+++ b/src/test/ui/regions/regions-early-bound-error.stderr
@@ -4,12 +4,12 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |     g1.get()
    |     ^^^^^^^^
    |
-note: ...the reference is valid for the lifetime 'b as defined on the function body at 18:11...
+note: ...the reference is valid for the lifetime `'b` as defined on the function body at 18:11...
   --> $DIR/regions-early-bound-error.rs:18:11
    |
 LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
    |           ^^
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 18:8
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 18:8
   --> $DIR/regions-early-bound-error.rs:18:8
    |
 LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
diff --git a/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr b/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr
index 3b8f09f1ad8..ad555efadf7 100644
--- a/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-callee-4.stderr
@@ -8,12 +8,12 @@ LL | |     let z: Option<&'a &'b usize> = None;
 LL | | }
    | |_^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 5:14
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 5:14
   --> $DIR/regions-free-region-ordering-callee-4.rs:5:14
    |
 LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) {
    |              ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 5:18
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 5:18
   --> $DIR/regions-free-region-ordering-callee-4.rs:5:18
    |
 LL | fn ordering4<'a, 'b, F>(a: &'a usize, b: &'b usize, x: F) where F: FnOnce(&'a &'b usize) {
diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr
index 676e96a038b..10644174b9b 100644
--- a/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to
 LL |             None => &self.val
    |                     ^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the method body at 14:12...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the method body at 14:12...
   --> $DIR/regions-free-region-ordering-incorrect.rs:14:12
    |
 LL |     fn get<'a>(&'a self) -> &'b T {
@@ -14,7 +14,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |             None => &self.val
    |                     ^^^^^^^^^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the impl at 13:6...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 13:6...
   --> $DIR/regions-free-region-ordering-incorrect.rs:13:6
    |
 LL | impl<'b, T> Node<'b, T> {
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
index b3390bcc4d5..c4ca7e97074 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
@@ -7,12 +7,12 @@ LL | | {
 LL | | }
    | |_^
    |
-note: the pointer is valid for the lifetime 'x as defined on the function body at 21:11
+note: the pointer is valid for the lifetime `'x` as defined on the function body at 21:11
   --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:11
    |
 LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
    |           ^^
-note: but the referenced data is only valid for the lifetime 'y as defined on the function body at 21:15
+note: but the referenced data is only valid for the lifetime `'y` as defined on the function body at 21:15
   --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:15
    |
 LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >)
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr
index d31ed3ede36..f4e223bbf6f 100644
--- a/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.stderr
@@ -6,7 +6,7 @@ LL |     b_isize
    |
    = note: expected type `Invariant<'static>`
               found type `Invariant<'r>`
-note: the lifetime 'r as defined on the function body at 11:23...
+note: the lifetime `'r` as defined on the function body at 11:23...
   --> $DIR/regions-infer-invariance-due-to-decl.rs:11:23
    |
 LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr
index f8bdd014db7..6322244fcf9 100644
--- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.stderr
@@ -6,7 +6,7 @@ LL |     b_isize
    |
    = note: expected type `Invariant<'static>`
               found type `Invariant<'r>`
-note: the lifetime 'r as defined on the function body at 9:23...
+note: the lifetime `'r` as defined on the function body at 9:23...
   --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:9:23
    |
 LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr
index 1de6f22f08e..7baae69945f 100644
--- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.stderr
@@ -6,7 +6,7 @@ LL |     b_isize
    |
    = note: expected type `Invariant<'static>`
               found type `Invariant<'r>`
-note: the lifetime 'r as defined on the function body at 9:23...
+note: the lifetime `'r` as defined on the function body at 9:23...
   --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:9:23
    |
 LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
diff --git a/src/test/ui/regions/regions-infer-not-param.stderr b/src/test/ui/regions/regions-infer-not-param.stderr
index f43ab829121..6365769430f 100644
--- a/src/test/ui/regions/regions-infer-not-param.stderr
+++ b/src/test/ui/regions/regions-infer-not-param.stderr
@@ -6,12 +6,12 @@ LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
    |
    = note: expected type `Direct<'b>`
               found type `Direct<'a>`
-note: the lifetime 'a as defined on the function body at 15:16...
+note: the lifetime `'a` as defined on the function body at 15:16...
   --> $DIR/regions-infer-not-param.rs:15:16
    |
 LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
    |                ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the function body at 15:19
+note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 15:19
   --> $DIR/regions-infer-not-param.rs:15:19
    |
 LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
@@ -25,12 +25,12 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |
    = note: expected type `Indirect2<'b>`
               found type `Indirect2<'a>`
-note: the lifetime 'a as defined on the function body at 19:19...
+note: the lifetime `'a` as defined on the function body at 19:19...
   --> $DIR/regions-infer-not-param.rs:19:19
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |                   ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the function body at 19:22
+note: ...does not necessarily outlive the lifetime `'b` as defined on the function body at 19:22
   --> $DIR/regions-infer-not-param.rs:19:22
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
@@ -44,12 +44,12 @@ LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |
    = note: expected type `Indirect2<'b>`
               found type `Indirect2<'a>`
-note: the lifetime 'b as defined on the function body at 19:22...
+note: the lifetime `'b` as defined on the function body at 19:22...
   --> $DIR/regions-infer-not-param.rs:19:22
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
    |                      ^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 19:19
+note: ...does not necessarily outlive the lifetime `'a` as defined on the function body at 19:19
   --> $DIR/regions-infer-not-param.rs:19:19
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr
index 1b999ed059c..b1fd337b8d0 100644
--- a/src/test/ui/regions/regions-infer-paramd-indirect.stderr
+++ b/src/test/ui/regions/regions-infer-paramd-indirect.stderr
@@ -17,7 +17,7 @@ LL | |
 LL | |
 LL | |     }
    | |_____^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 16:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 16:6
   --> $DIR/regions-infer-paramd-indirect.rs:16:6
    |
 LL | impl<'a> SetF<'a> for C<'a> {
diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr
index bc3c06d7ff3..f4eb5c8644f 100644
--- a/src/test/ui/regions/regions-nested-fns.stderr
+++ b/src/test/ui/regions/regions-nested-fns.stderr
@@ -49,7 +49,7 @@ LL | |         if false { return ay; }
 LL | |         return z;
 LL | |     }));
    | |_____^
-note: ...but the borrowed content is only valid for the lifetime 'x as defined on the function body at 3:11
+note: ...but the borrowed content is only valid for the lifetime `'x` as defined on the function body at 3:11
   --> $DIR/regions-nested-fns.rs:3:11
    |
 LL | fn nested<'x>(x: &'x isize) {
diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
index c44edf1f03b..d29fd80943f 100644
--- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
+++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr
@@ -7,12 +7,12 @@ LL | | {
 LL | | }
    | |_^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 22:8...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:8
    |
 LL | fn bar<'a, 'b>()
    |        ^^
-note: ...but the lifetime must also be valid for the lifetime 'b as defined on the function body at 22:12...
+note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
   --> $DIR/regions-normalize-in-where-clause-list.rs:22:12
    |
 LL | fn bar<'a, 'b>()
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr
index ed5800940ee..0992d9bf295 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a WithHrAssoc<TheType<'b>>`, reference has a longer lif
 LL |     let _: &'a WithHrAssoc<TheType<'b>> = loop { };
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 27:15
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 27:15
   --> $DIR/regions-outlives-projection-container-hrtb.rs:27:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 27:18
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 27:18
   --> $DIR/regions-outlives-projection-container-hrtb.rs:27:18
    |
 LL | fn with_assoc<'a,'b>() {
@@ -21,12 +21,12 @@ error[E0491]: in type `&'a WithHrAssocSub<TheType<'b>>`, reference has a longer
 LL |     let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 46:19
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 46:19
   --> $DIR/regions-outlives-projection-container-hrtb.rs:46:19
    |
 LL | fn with_assoc_sub<'a,'b>() {
    |                   ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 46:22
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 46:22
   --> $DIR/regions-outlives-projection-container-hrtb.rs:46:22
    |
 LL | fn with_assoc_sub<'a,'b>() {
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr
index 152e6c5600c..49e28a14d8a 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifet
 LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 27:15
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 27:15
   --> $DIR/regions-outlives-projection-container-wc.rs:27:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 27:18
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 27:18
   --> $DIR/regions-outlives-projection-container-wc.rs:27:18
    |
 LL | fn with_assoc<'a,'b>() {
diff --git a/src/test/ui/regions/regions-outlives-projection-container.stderr b/src/test/ui/regions/regions-outlives-projection-container.stderr
index 3c1a98a3c01..dba15fb0576 100644
--- a/src/test/ui/regions/regions-outlives-projection-container.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifet
 LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 28:15
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 28:15
   --> $DIR/regions-outlives-projection-container.rs:28:15
    |
 LL | fn with_assoc<'a,'b>() {
    |               ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 28:18
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 28:18
   --> $DIR/regions-outlives-projection-container.rs:28:18
    |
 LL | fn with_assoc<'a,'b>() {
@@ -21,12 +21,12 @@ error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer li
 LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 50:18
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 50:18
   --> $DIR/regions-outlives-projection-container.rs:50:18
    |
 LL | fn without_assoc<'a,'b>() {
    |                  ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 50:21
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 50:21
   --> $DIR/regions-outlives-projection-container.rs:50:21
    |
 LL | fn without_assoc<'a,'b>() {
@@ -38,12 +38,12 @@ error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifet
 LL |     call::<&'a WithAssoc<TheType<'b>>>();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 58:20
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 58:20
   --> $DIR/regions-outlives-projection-container.rs:58:20
    |
 LL | fn call_with_assoc<'a,'b>() {
    |                    ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 58:23
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 58:23
   --> $DIR/regions-outlives-projection-container.rs:58:23
    |
 LL | fn call_with_assoc<'a,'b>() {
@@ -55,12 +55,12 @@ error[E0491]: in type `&'a WithoutAssoc<TheType<'b>>`, reference has a longer li
 LL |     call::<&'a WithoutAssoc<TheType<'b>>>();
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the function body at 67:23
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 67:23
   --> $DIR/regions-outlives-projection-container.rs:67:23
    |
 LL | fn call_without_assoc<'a,'b>() {
    |                       ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 67:26
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 67:26
   --> $DIR/regions-outlives-projection-container.rs:67:26
    |
 LL | fn call_without_assoc<'a,'b>() {
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr
index 72e47cea094..49076673ad3 100644
--- a/src/test/ui/regions/regions-ret-borrowed-1.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr
@@ -12,7 +12,7 @@ LL |     with(|o| o)
    = note: ...so that the expression is assignable:
            expected &isize
               found &isize
-note: but, the lifetime must be valid for the lifetime 'a as defined on the function body at 9:14...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14...
   --> $DIR/regions-ret-borrowed-1.rs:9:14
    |
 LL | fn return_it<'a>() -> &'a isize {
diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr
index ce0c429ccb2..eb1ade27ace 100644
--- a/src/test/ui/regions/regions-ret-borrowed.stderr
+++ b/src/test/ui/regions/regions-ret-borrowed.stderr
@@ -12,7 +12,7 @@ LL |     with(|o| o)
    = note: ...so that the expression is assignable:
            expected &isize
               found &isize
-note: but, the lifetime must be valid for the lifetime 'a as defined on the function body at 12:14...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14...
   --> $DIR/regions-ret-borrowed.rs:12:14
    |
 LL | fn return_it<'a>() -> &'a isize {
diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
index be441bc4808..946465bcb5f 100644
--- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
+++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
@@ -4,7 +4,7 @@ error[E0495]: cannot infer an appropriate lifetime for borrow expression due to
 LL |         let mut f = || &mut x;
    |                        ^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 7:21...
+note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 7:21...
   --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:21
    |
 LL |         let mut f = || &mut x;
diff --git a/src/test/ui/regions/regions-static-bound.migrate.stderr b/src/test/ui/regions/regions-static-bound.migrate.stderr
index 21ead8b768f..6e631d40d45 100644
--- a/src/test/ui/regions/regions-static-bound.migrate.stderr
+++ b/src/test/ui/regions/regions-static-bound.migrate.stderr
@@ -5,7 +5,7 @@ LL |     t
    |     ^
    |
    = note: ...the reference is valid for the static lifetime...
-note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 8:24
+note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the function body at 8:24
   --> $DIR/regions-static-bound.rs:8:24
    |
 LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr
index 421f826ccc5..f835c005ff9 100644
--- a/src/test/ui/regions/regions-trait-1.stderr
+++ b/src/test/ui/regions/regions-trait-1.stderr
@@ -6,7 +6,7 @@ LL |     fn get_ctxt(&self) -> &'a Ctxt {
    |
    = note: expected type `fn(&HasCtxt<'a>) -> &Ctxt`
               found type `fn(&HasCtxt<'a>) -> &'a Ctxt`
-note: the lifetime 'a as defined on the impl at 12:6...
+note: the lifetime `'a` as defined on the impl at 12:6...
   --> $DIR/regions-trait-1.rs:12:6
    |
 LL | impl<'a> GetCtxt for HasCtxt<'a> {
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr
index d88be05cb87..b7c7f93149d 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr
@@ -4,12 +4,12 @@ error[E0478]: lifetime bound not satisfied
 LL |     x
    |     ^
    |
-note: lifetime parameter instantiated with the lifetime 'a as defined on the function body at 13:9
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the function body at 13:9
   --> $DIR/regions-trait-object-subtyping.rs:13:9
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
    |         ^^
-note: but lifetime parameter must outlive the lifetime 'b as defined on the function body at 13:12
+note: but lifetime parameter must outlive the lifetime `'b` as defined on the function body at 13:12
   --> $DIR/regions-trait-object-subtyping.rs:13:12
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
@@ -21,7 +21,7 @@ error[E0495]: cannot infer an appropriate lifetime for automatic coercion due to
 LL |     x
    |     ^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 13:9...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 13:9...
   --> $DIR/regions-trait-object-subtyping.rs:13:9
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
@@ -31,7 +31,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |     x
    |     ^
-note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 13:12...
+note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 13:12...
   --> $DIR/regions-trait-object-subtyping.rs:13:12
    |
 LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
@@ -48,12 +48,12 @@ LL |     x
    |
    = note: expected type `Wrapper<&'b mut (dyn Dummy + 'b)>`
               found type `Wrapper<&'a mut (dyn Dummy + 'a)>`
-note: the lifetime 'b as defined on the function body at 20:15...
+note: the lifetime `'b` as defined on the function body at 20:15...
   --> $DIR/regions-trait-object-subtyping.rs:20:15
    |
 LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
    |               ^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the function body at 20:9
+note: ...does not necessarily outlive the lifetime `'a` as defined on the function body at 20:9
   --> $DIR/regions-trait-object-subtyping.rs:20:9
    |
 LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dummy> {
diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr
index 90b37ce935a..aae519c5df2 100644
--- a/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr
+++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.stderr
@@ -6,7 +6,7 @@ LL |     let _: Invariant<'static> = c;
    |
    = note: expected type `Invariant<'static>`
               found type `Invariant<'b>`
-note: the lifetime 'b as defined on the function body at 11:9...
+note: the lifetime `'b` as defined on the function body at 11:9...
   --> $DIR/regions-variance-invariant-use-covariant.rs:11:9
    |
 LL | fn use_<'b>(c: Invariant<'b>) {
diff --git a/src/test/ui/regions/regions-wf-trait-object.stderr b/src/test/ui/regions/regions-wf-trait-object.stderr
index 4e12478c36d..9f395086041 100644
--- a/src/test/ui/regions/regions-wf-trait-object.stderr
+++ b/src/test/ui/regions/regions-wf-trait-object.stderr
@@ -4,12 +4,12 @@ error[E0478]: lifetime bound not satisfied
 LL |     x: Box<dyn TheTrait<'a>+'b>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: lifetime parameter instantiated with the lifetime 'b as defined on the struct at 6:15
+note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 6:15
   --> $DIR/regions-wf-trait-object.rs:6:15
    |
 LL | struct Foo<'a,'b> {
    |               ^^
-note: but lifetime parameter must outlive the lifetime 'a as defined on the struct at 6:12
+note: but lifetime parameter must outlive the lifetime `'a` as defined on the struct at 6:12
   --> $DIR/regions-wf-trait-object.rs:6:12
    |
 LL | struct Foo<'a,'b> {
diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr
index 16d27c9d961..609a40163a3 100644
--- a/src/test/ui/reject-specialized-drops-8142.stderr
+++ b/src/test/ui/reject-specialized-drops-8142.stderr
@@ -34,7 +34,7 @@ LL | impl                    Drop for N<'static>     { fn drop(&mut self) { } }
    |
    = note: expected type `N<'n>`
               found type `N<'static>`
-note: the lifetime 'n as defined on the struct at 8:10...
+note: the lifetime `'n` as defined on the struct at 8:10...
   --> $DIR/reject-specialized-drops-8142.rs:8:10
    |
 LL | struct N<'n> { x: &'n i8 }
@@ -95,12 +95,12 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'lw`
 LL | impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'l1 as defined on the struct at 17:10...
+note: first, the lifetime cannot outlive the lifetime `'l1` as defined on the struct at 17:10...
   --> $DIR/reject-specialized-drops-8142.rs:17:10
    |
 LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
    |          ^^^
-note: ...but the lifetime must also be valid for the lifetime 'l2 as defined on the struct at 17:15...
+note: ...but the lifetime must also be valid for the lifetime `'l2` as defined on the struct at 17:15...
   --> $DIR/reject-specialized-drops-8142.rs:17:15
    |
 LL | struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr
index 219516d8abc..df001d6b5f2 100644
--- a/src/test/ui/repr/repr-packed-contains-align.stderr
+++ b/src/test/ui/repr/repr-packed-contains-align.stderr
@@ -56,3 +56,4 @@ LL | | }
 
 error: aborting due to 8 previous errors
 
+For more information about this error, try `rustc --explain E0588`.
diff --git a/src/test/ui/resolve/issue-16058.stderr b/src/test/ui/resolve/issue-16058.stderr
index 64177ac2a83..9766f8f1412 100644
--- a/src/test/ui/resolve/issue-16058.stderr
+++ b/src/test/ui/resolve/issue-16058.stderr
@@ -14,3 +14,4 @@ LL | use std::thread::Result;
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/resolve/issue-21221-1.stderr b/src/test/ui/resolve/issue-21221-1.stderr
index d00d87393aa..513e02f74e3 100644
--- a/src/test/ui/resolve/issue-21221-1.stderr
+++ b/src/test/ui/resolve/issue-21221-1.stderr
@@ -27,7 +27,7 @@ LL | use mul3::Mul;
    |
 LL | use mul4::Mul;
    |
-and 2 other candidates
+     and 2 other candidates
 
 error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
   --> $DIR/issue-21221-1.rs:63:6
diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr
index 7790383843e..329543114a6 100644
--- a/src/test/ui/resolve/issue-2356.stderr
+++ b/src/test/ui/resolve/issue-2356.stderr
@@ -61,8 +61,14 @@ LL |         purr();
 error[E0424]: expected value, found module `self`
   --> $DIR/issue-2356.rs:65:8
    |
-LL |     if self.whiskers > 3 {
-   |        ^^^^ `self` value is a keyword only available in methods with `self` parameter
+LL | /   fn meow() {
+LL | |     if self.whiskers > 3 {
+   | |        ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+LL | |
+LL | |         println!("MEOW");
+LL | |     }
+LL | |   }
+   | |___- this function doesn't have a `self` parameter
 
 error[E0425]: cannot find function `grow_older` in this scope
   --> $DIR/issue-2356.rs:72:5
@@ -97,8 +103,12 @@ LL |     purr_louder();
 error[E0424]: expected value, found module `self`
   --> $DIR/issue-2356.rs:92:5
    |
-LL |     self += 1;
-   |     ^^^^ `self` value is a keyword only available in methods with `self` parameter
+LL | / fn main() {
+LL | |     self += 1;
+   | |     ^^^^ `self` value is a keyword only available in methods with a `self` parameter
+LL | |
+LL | | }
+   | |_- this function doesn't have a `self` parameter
 
 error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr
index 2e3c0f5448e..e693a0ef91f 100644
--- a/src/test/ui/resolve/levenshtein.stderr
+++ b/src/test/ui/resolve/levenshtein.stderr
@@ -38,13 +38,13 @@ error[E0412]: cannot find type `first` in module `m`
   --> $DIR/levenshtein.rs:28:15
    |
 LL |     let b: m::first = m::second; // Misspelled item in module.
-   |               ^^^^^ help: a struct with a similar name exists: `First`
+   |               ^^^^^ help: a struct with a similar name exists (notice the capitalization): `First`
 
 error[E0425]: cannot find value `second` in module `m`
   --> $DIR/levenshtein.rs:28:26
    |
 LL |     let b: m::first = m::second; // Misspelled item in module.
-   |                          ^^^^^^ help: a unit struct with a similar name exists: `Second`
+   |                          ^^^^^^ help: a unit struct with a similar name exists (notice the capitalization): `Second`
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
index 39825c4f9a9..c8e8b9dcfc6 100644
--- a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
+++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs
@@ -1,6 +1,8 @@
 // compile-flags: --test
 // run-pass
 
+// ignore-emscripten compiled with panic=abort by default
+
 #![feature(test)]
 
 extern crate test;
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
index a16fb7670a6..ea8a3c177e9 100644
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
@@ -1,13 +1,12 @@
 #![feature(rustc_attrs)]
 #![feature(untagged_unions)]
-#![allow(unions_with_drop_fields)]
 
 #[rustc_outlives]
-union Foo<'b, U> { //~ ERROR rustc_outlives
+union Foo<'b, U: Copy> { //~ ERROR rustc_outlives
     bar: Bar<'b, U>
 }
 
-union Bar<'a, T> where T: 'a {
+union Bar<'a, T: Copy> where T: 'a {
     x: &'a (),
     y: T,
 }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
index adf62651cac..8aa246e8bfe 100644
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
@@ -1,7 +1,7 @@
 error: rustc_outlives
-  --> $DIR/explicit-union.rs:6:1
+  --> $DIR/explicit-union.rs:5:1
    |
-LL | / union Foo<'b, U> {
+LL | / union Foo<'b, U: Copy> {
 LL | |     bar: Bar<'b, U>
 LL | | }
    | |_^
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
index 0ff667fbeba..0da3cc2ba1b 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
@@ -1,14 +1,13 @@
 #![feature(rustc_attrs)]
 #![feature(untagged_unions)]
-#![allow(unions_with_drop_fields)]
 
 #[rustc_outlives]
-union Foo<'a, T> { //~ ERROR rustc_outlives
+union Foo<'a, T: Copy> { //~ ERROR rustc_outlives
     field1: Bar<'a, T>
 }
 
 // Type U needs to outlive lifetime 'b
-union Bar<'b, U> {
+union Bar<'b, U: Copy> {
     field2: &'b U
 }
 
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
index fc4b1a22329..a42285a56d0 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
@@ -1,7 +1,7 @@
 error: rustc_outlives
-  --> $DIR/nested-union.rs:6:1
+  --> $DIR/nested-union.rs:5:1
    |
-LL | / union Foo<'a, T> {
+LL | / union Foo<'a, T: Copy> {
 LL | |     field1: Bar<'a, T>
 LL | | }
    | |_^
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr
index be8b5c6446c..6efc1176d05 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a rev_variant_struct_region::Foo<'b>`, reference has a
 LL |         type Out = &'a Foo<'b>;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10
+note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10
   --> $DIR/regions-outlives-nominal-type-region-rev.rs:16:10
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
    |          ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the impl at 16:14
+note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14
   --> $DIR/regions-outlives-nominal-type-region-rev.rs:16:14
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr
index 9a3ba2d65ca..06e5f24dec9 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a variant_struct_region::Foo<'b>`, reference has a long
 LL |         type Out = &'a Foo<'b>;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10
+note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10
   --> $DIR/regions-outlives-nominal-type-region.rs:16:10
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
    |          ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the impl at 16:14
+note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14
   --> $DIR/regions-outlives-nominal-type-region.rs:16:14
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr
index 5389beea3a7..d02f7b79621 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a l
 LL |         type Out = &'a Foo<&'b i32>;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10
+note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10
   --> $DIR/regions-outlives-nominal-type-type-rev.rs:16:10
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
    |          ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the impl at 16:14
+note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14
   --> $DIR/regions-outlives-nominal-type-type-rev.rs:16:14
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr
index 2f3ef48a054..40c70f53245 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr
@@ -4,12 +4,12 @@ error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a l
 LL |         type Out = &'a Foo<&'b i32>;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the impl at 16:10
+note: the pointer is valid for the lifetime `'a` as defined on the impl at 16:10
   --> $DIR/regions-outlives-nominal-type-type.rs:16:10
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
    |          ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the impl at 16:14
+note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 16:14
   --> $DIR/regions-outlives-nominal-type-type.rs:16:14
    |
 LL |     impl<'a, 'b> Trait<'a, 'b> for usize {
diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
index 5a11c5fb95f..825c1015c51 100644
--- a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr
@@ -32,12 +32,12 @@ error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data
 LL |     type Out = &'a &'b T;
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-note: the pointer is valid for the lifetime 'a as defined on the impl at 24:6
+note: the pointer is valid for the lifetime `'a` as defined on the impl at 24:6
   --> $DIR/regions-struct-not-wf.rs:24:6
    |
 LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 {
    |      ^^
-note: but the referenced data is only valid for the lifetime 'b as defined on the impl at 24:10
+note: but the referenced data is only valid for the lifetime `'b` as defined on the impl at 24:10
   --> $DIR/regions-struct-not-wf.rs:24:10
    |
 LL | impl<'a, 'b, T> Trait1<'a, 'b, T> for u32 {
diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs
index 580e67513b3..f8abd1b96d8 100644
--- a/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs
+++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/range.rs
@@ -3,7 +3,7 @@ pub fn main() {
     let i = 5;
     match &&&&i {
         1 ..= 3 => panic!(),
-        3 ..= 8 => {},
+        4 ..= 8 => {},
         _ => panic!(),
     }
 }
diff --git a/src/test/ui/rfcs/rfc1857-drop-order.rs b/src/test/ui/rfcs/rfc1857-drop-order.rs
index 7923aa7c0e2..b10b6ec11b5 100644
--- a/src/test/ui/rfcs/rfc1857-drop-order.rs
+++ b/src/test/ui/rfcs/rfc1857-drop-order.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 
 #![allow(dead_code, unreachable_code)]
 
diff --git a/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr b/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr
index 030fa56dcff..973c486970e 100644
--- a/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr
+++ b/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr
@@ -13,7 +13,7 @@ LL | use std::collections::hash_map::Drain;
    |
 LL | use std::collections::hash_set::Drain;
    |
-and 3 other candidates
+     and 3 other candidates
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/save-analysis/issue-64659.rs b/src/test/ui/save-analysis/issue-64659.rs
new file mode 100644
index 00000000000..a3d88a20377
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-64659.rs
@@ -0,0 +1,10 @@
+// check-pass
+// compile-flags: -Zsave-analysis
+
+trait Trait { type Assoc; }
+
+fn main() {
+    struct Data<T: Trait> {
+        x: T::Assoc,
+    }
+}
diff --git a/src/test/ui/save-analysis/issue-65411.rs b/src/test/ui/save-analysis/issue-65411.rs
new file mode 100644
index 00000000000..9e58b8da5d2
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-65411.rs
@@ -0,0 +1,15 @@
+// check-pass
+// compile-flags: -Zsave-analysis
+
+trait Trait { type Assoc; }
+trait GenericTrait<T> {}
+struct Wrapper<B> { b: B }
+
+fn func() {
+    // Processing associated path in impl block definition inside a function
+    // body does not ICE
+    impl<B: Trait> GenericTrait<B::Assoc> for Wrapper<B> {}
+}
+
+
+fn main() {}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
index 2fb152475a1..bce1900ca60 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
@@ -6,12 +6,12 @@ LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
    |                |
    |                ...but this borrow...
    |
-note: ...can't outlive the lifetime '_ as defined on the method body at 8:26
+note: ...can't outlive the lifetime `'_` as defined on the method body at 8:26
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:26
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
    |                          ^
-help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime '_ as defined on the method body at 8:26
+help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'_` as defined on the method body at 8:26
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
    |                                     ^^^^^^^^^^^^^^^
diff --git a/src/test/ui/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs
index 73f23a9cc17..3b1eb9e1dfa 100644
--- a/src/test/ui/self/self-in-typedefs.rs
+++ b/src/test/ui/self/self-in-typedefs.rs
@@ -3,7 +3,8 @@
 #![feature(untagged_unions)]
 
 #![allow(dead_code)]
-#![allow(unions_with_drop_fields)]
+
+use std::mem::ManuallyDrop;
 
 enum A<'a, T: 'a>
 where
@@ -26,6 +27,14 @@ where
     Self: Send, T: PartialEq<Self>
 {
     foo: &'a Self,
+    bar: ManuallyDrop<T>,
+}
+
+union D<'a, T: 'a>
+where
+    Self: Send, T: PartialEq<Self> + Copy
+{
+    foo: &'a Self,
     bar: T,
 }
 
diff --git a/src/test/ui/sepcomp/sepcomp-lib-lto.rs b/src/test/ui/sepcomp/sepcomp-lib-lto.rs
index 164ae79c254..51a572899f8 100644
--- a/src/test/ui/sepcomp/sepcomp-lib-lto.rs
+++ b/src/test/ui/sepcomp/sepcomp-lib-lto.rs
@@ -4,6 +4,7 @@
 
 // aux-build:sepcomp_lib.rs
 // compile-flags: -C lto -g
+// ignore-asmjs wasm2js does not support source maps yet
 // no-prefer-dynamic
 
 extern crate sepcomp_lib;
diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
index 45951561e72..5275b7b1ddf 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr
@@ -2,9 +2,9 @@ error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied
   --> $DIR/specialization-wfcheck.rs:7:17
    |
 LL | default impl<U> Foo<'static, U> for () {}
-   |                 ^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::cmp::Eq` bound
+   |              -  ^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `U`
+   |              |
+   |              help: consider restricting this bound: `U: std::cmp::Eq`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/static/static-closures.stderr b/src/test/ui/static/static-closures.stderr
index ced78c03e09..99235e26e15 100644
--- a/src/test/ui/static/static-closures.stderr
+++ b/src/test/ui/static/static-closures.stderr
@@ -6,3 +6,4 @@ LL |     static || {};
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0697`.
diff --git a/src/test/ui/static/static-lifetime.stderr b/src/test/ui/static/static-lifetime.stderr
index 8516ac07b6c..bda325dc011 100644
--- a/src/test/ui/static/static-lifetime.stderr
+++ b/src/test/ui/static/static-lifetime.stderr
@@ -4,7 +4,7 @@ error[E0478]: lifetime bound not satisfied
 LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
    |                    ^^^^^^^^^
    |
-note: lifetime parameter instantiated with the lifetime 'a as defined on the impl at 3:6
+note: lifetime parameter instantiated with the lifetime `'a` as defined on the impl at 3:6
   --> $DIR/static-lifetime.rs:3:6
    |
 LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
diff --git a/src/test/ui/suggestions/constrain-trait.fixed b/src/test/ui/suggestions/constrain-trait.fixed
new file mode 100644
index 00000000000..dda9e931353
--- /dev/null
+++ b/src/test/ui/suggestions/constrain-trait.fixed
@@ -0,0 +1,47 @@
+// run-rustfix
+// check-only
+
+#[derive(Debug)]
+struct Demo {
+    a: String
+}
+
+trait GetString {
+    fn get_a(&self) -> &String;
+}
+
+trait UseString: std::fmt::Debug + GetString {
+    fn use_string(&self) {
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+    }
+}
+
+trait UseString2: GetString {
+    fn use_string(&self) {
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+    }
+}
+
+impl GetString for Demo {
+    fn get_a(&self) -> &String {
+        &self.a
+    }
+}
+
+impl UseString for Demo {}
+impl UseString2 for Demo {}
+
+
+#[cfg(test)]
+mod tests {
+    use crate::{Demo, UseString};
+
+    #[test]
+    fn it_works() {
+        let d = Demo { a: "test".to_string() };
+        d.use_string();
+    }
+}
+
+
+fn main() {}
diff --git a/src/test/ui/suggestions/constrain-trait.rs b/src/test/ui/suggestions/constrain-trait.rs
new file mode 100644
index 00000000000..4ef0eff5bd7
--- /dev/null
+++ b/src/test/ui/suggestions/constrain-trait.rs
@@ -0,0 +1,47 @@
+// run-rustfix
+// check-only
+
+#[derive(Debug)]
+struct Demo {
+    a: String
+}
+
+trait GetString {
+    fn get_a(&self) -> &String;
+}
+
+trait UseString: std::fmt::Debug {
+    fn use_string(&self) {
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+    }
+}
+
+trait UseString2 {
+    fn use_string(&self) {
+        println!("{:?}", self.get_a()); //~ ERROR no method named `get_a` found for type `&Self`
+    }
+}
+
+impl GetString for Demo {
+    fn get_a(&self) -> &String {
+        &self.a
+    }
+}
+
+impl UseString for Demo {}
+impl UseString2 for Demo {}
+
+
+#[cfg(test)]
+mod tests {
+    use crate::{Demo, UseString};
+
+    #[test]
+    fn it_works() {
+        let d = Demo { a: "test".to_string() };
+        d.use_string();
+    }
+}
+
+
+fn main() {}
diff --git a/src/test/ui/suggestions/constrain-trait.stderr b/src/test/ui/suggestions/constrain-trait.stderr
new file mode 100644
index 00000000000..3cc351ac80a
--- /dev/null
+++ b/src/test/ui/suggestions/constrain-trait.stderr
@@ -0,0 +1,27 @@
+error[E0599]: no method named `get_a` found for type `&Self` in the current scope
+  --> $DIR/constrain-trait.rs:15:31
+   |
+LL |         println!("{:?}", self.get_a());
+   |                               ^^^^^ method not found in `&Self`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `get_a`, perhaps you need to add another supertrait for it:
+   |
+LL | trait UseString: std::fmt::Debug + GetString {
+   |                                  ^^^^^^^^^^^
+
+error[E0599]: no method named `get_a` found for type `&Self` in the current scope
+  --> $DIR/constrain-trait.rs:21:31
+   |
+LL |         println!("{:?}", self.get_a());
+   |                               ^^^^^ method not found in `&Self`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `get_a`, perhaps you need to add a supertrait for it:
+   |
+LL | trait UseString2: GetString {
+   |                 ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
new file mode 100644
index 00000000000..265ccb3125c
--- /dev/null
+++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.rs
@@ -0,0 +1,25 @@
+// Running rustfix would cause the same suggestion to be applied multiple times, which results in
+// invalid code.
+
+trait Parent {
+    type Ty;
+    type Assoc: Child<Self::Ty>;
+}
+
+trait Child<T> {}
+
+struct ChildWrapper<T>(T);
+
+impl<A, T> Child<A> for ChildWrapper<T> where T: Child<A> {}
+
+struct ParentWrapper<T>(T);
+
+impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+    //~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+    //~| ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+    type Ty = A;
+    type Assoc = ChildWrapper<T::Assoc>;
+    //~^ ERROR the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
new file mode 100644
index 00000000000..bdea8ab97e5
--- /dev/null
+++ b/src/test/ui/suggestions/missing-assoc-type-bound-restriction.stderr
@@ -0,0 +1,43 @@
+error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+  --> $DIR/missing-assoc-type-bound-restriction.rs:17:1
+   |
+LL |   trait Parent {
+   |   ------------ required by `Parent`
+...
+LL |   impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+   |   ^                                                     - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
+   |  _|
+   | |
+LL | |
+LL | |
+LL | |     type Ty = A;
+LL | |     type Assoc = ChildWrapper<T::Assoc>;
+LL | |
+LL | | }
+   | |_^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+
+error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+  --> $DIR/missing-assoc-type-bound-restriction.rs:17:28
+   |
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+   |                            ^^^^^^                     - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
+   |                            |
+   |                            the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+   |
+   = note: required because of the requirements on the impl of `Child<A>` for `ChildWrapper<<T as Parent>::Assoc>`
+
+error[E0277]: the trait bound `<T as Parent>::Assoc: Child<A>` is not satisfied
+  --> $DIR/missing-assoc-type-bound-restriction.rs:21:5
+   |
+LL | trait Parent {
+   | ------------ required by `Parent`
+...
+LL | impl<A, T: Parent<Ty = A>> Parent for ParentWrapper<T> {
+   |                                                       - help: consider further restricting the associated type: `where <T as Parent>::Assoc: Child<A>`
+...
+LL |     type Assoc = ChildWrapper<T::Assoc>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Child<A>` is not implemented for `<T as Parent>::Assoc`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/restrict-type-argument.rs b/src/test/ui/suggestions/restrict-type-argument.rs
new file mode 100644
index 00000000000..c4ebfbe922c
--- /dev/null
+++ b/src/test/ui/suggestions/restrict-type-argument.rs
@@ -0,0 +1,31 @@
+fn is_send<T: Send>(val: T) {}
+
+fn use_impl_sync(val: impl Sync) {
+    is_send(val); //~ ERROR `impl Sync` cannot be sent between threads safely
+}
+
+fn use_where<S>(val: S) where S: Sync {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_bound<S: Sync>(val: S) {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_bound_2<
+    S // Make sure we can synthezise a correct suggestion span for this case
+    :
+    Sync
+>(val: S) {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn use_unbound<S>(val: S) {
+    is_send(val); //~ ERROR `S` cannot be sent between threads safely
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr
new file mode 100644
index 00000000000..d6840ca4d72
--- /dev/null
+++ b/src/test/ui/suggestions/restrict-type-argument.stderr
@@ -0,0 +1,83 @@
+error[E0277]: `impl Sync` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:4:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+LL | 
+LL | fn use_impl_sync(val: impl Sync) {
+   |                       --------- help: consider further restricting this bound: `impl Sync + std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `impl Sync` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `impl Sync`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:8:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_where<S>(val: S) where S: Sync {
+   |                                      - help: consider further restricting type parameter `S`: `, S: std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:12:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_bound<S: Sync>(val: S) {
+   |              -- help: consider further restricting this bound: `S: std::marker::Send +`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:20:13
+   |
+LL |   fn is_send<T: Send>(val: T) {}
+   |      -------    ---- required by this bound in `is_send`
+...
+LL | /     S // Make sure we can synthezise a correct suggestion span for this case
+LL | |     :
+   | |_____- help: consider further restricting this bound: `S: std::marker::Send +`
+...
+LL |       is_send(val);
+   |               ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:24:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_bound_and_where<S: Sync>(val: S) where S: std::fmt::Debug {
+   |                                                                 - help: consider further restricting type parameter `S`: `, S: std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error[E0277]: `S` cannot be sent between threads safely
+  --> $DIR/restrict-type-argument.rs:28:13
+   |
+LL | fn is_send<T: Send>(val: T) {}
+   |    -------    ---- required by this bound in `is_send`
+...
+LL | fn use_unbound<S>(val: S) {
+   |                - help: consider restricting this bound: `S: std::marker::Send`
+LL |     is_send(val);
+   |             ^^^ `S` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `S`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index a3d966bb0b0..610937739c1 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h059bf53000885489E)
+error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h636bc933fc62ee2fE)
   --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h059bf53000885489)
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h636bc933fc62ee2f)
   --> $DIR/impl1.rs:61:13
    |
 LL |             #[rustc_symbol_name]
diff --git a/src/test/ui/synthetic-param.rs b/src/test/ui/synthetic-param.rs
index e53e3ba06e0..e14697f5c3e 100644
--- a/src/test/ui/synthetic-param.rs
+++ b/src/test/ui/synthetic-param.rs
@@ -17,12 +17,12 @@ impl<S> Bar<S> {
 }
 
 fn main() {
-    func::<u8>(42); //~ ERROR cannot provide explicit type parameters
+    func::<u8>(42); //~ ERROR cannot provide explicit generic arguments
     func(42); // Ok
 
-    Foo::func::<u8>(42); //~ ERROR cannot provide explicit type parameters
+    Foo::func::<u8>(42); //~ ERROR cannot provide explicit generic arguments
     Foo::func(42); // Ok
 
-    Bar::<i8>::func::<u8>(42); //~ ERROR cannot provide explicit type parameters
+    Bar::<i8>::func::<u8>(42); //~ ERROR cannot provide explicit generic arguments
     Bar::<i8>::func(42); // Ok
 }
diff --git a/src/test/ui/synthetic-param.stderr b/src/test/ui/synthetic-param.stderr
index bfafd8cbd72..f8d14f26f32 100644
--- a/src/test/ui/synthetic-param.stderr
+++ b/src/test/ui/synthetic-param.stderr
@@ -1,16 +1,16 @@
-error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position.
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
   --> $DIR/synthetic-param.rs:20:5
    |
 LL |     func::<u8>(42);
    |     ^^^^^^^^^^
 
-error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position.
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
   --> $DIR/synthetic-param.rs:23:5
    |
 LL |     Foo::func::<u8>(42);
    |     ^^^^^^^^^^^^^^^
 
-error[E0632]: cannot provide explicit type parameters when `impl Trait` is used in argument position.
+error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
   --> $DIR/synthetic-param.rs:26:5
    |
 LL |     Bar::<i8>::func::<u8>(42);
diff --git a/src/test/ui/test-attrs/test-allow-fail-attr.rs b/src/test/ui/test-attrs/test-allow-fail-attr.rs
index 1a478460efc..55b743ab7c7 100644
--- a/src/test/ui/test-attrs/test-allow-fail-attr.rs
+++ b/src/test/ui/test-attrs/test-allow-fail-attr.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: --test
 #![feature(allow_fail)]
 
diff --git a/src/test/ui/test-attrs/test-should-fail-good-message.rs b/src/test/ui/test-attrs/test-should-fail-good-message.rs
index 9fa759f9eb4..2284953fbbe 100644
--- a/src/test/ui/test-attrs/test-should-fail-good-message.rs
+++ b/src/test/ui/test-attrs/test-should-fail-good-message.rs
@@ -1,5 +1,5 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
+// ignore-emscripten compiled with panic=abort by default
 // compile-flags: --test
 #[test]
 #[should_panic(expected = "foo")]
diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
index 6bef793e0e7..b831e624cb6 100644
--- a/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
+++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-1.stderr
@@ -42,4 +42,5 @@ LL |     rustfmt::skip;
 
 error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0423`.
+Some errors have detailed explanations: E0423, E0573.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/traits/trait-alias/trait-alias-wf.stderr b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr
index ca6d0584716..4355a517bd7 100644
--- a/src/test/ui/traits/trait-alias/trait-alias-wf.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr
@@ -4,9 +4,10 @@ error[E0277]: the trait bound `T: Foo` is not satisfied
 LL | trait A<T: Foo> {}
    | --------------- required by `A`
 LL | trait B<T> = A<T>;
-   | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
-   |
-   = help: consider adding a `where T: Foo` bound
+   | ^^^^^^^^-^^^^^^^^^
+   | |       |
+   | |       help: consider restricting this bound: `T: Foo`
+   | the trait `Foo` is not implemented for `T`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-as-struct-constructor.stderr b/src/test/ui/traits/trait-as-struct-constructor.stderr
index 434dcbc8736..e1d54fbf8aa 100644
--- a/src/test/ui/traits/trait-as-struct-constructor.stderr
+++ b/src/test/ui/traits/trait-as-struct-constructor.stderr
@@ -6,3 +6,4 @@ LL |     TraitNotAStruct{ value: 0 };
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
index bd76df8071a..96bbd1f3e4f 100644
--- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
+++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr
@@ -5,9 +5,9 @@ LL | struct Foo<T:Trait> {
    | ------------------- required by `Foo`
 ...
 LL | impl<T> Foo<T> {
-   |         ^^^^^^ the trait `Trait` is not implemented for `T`
-   |
-   = help: consider adding a `where T: Trait` bound
+   |      -  ^^^^^^ the trait `Trait` is not implemented for `T`
+   |      |
+   |      help: consider restricting this bound: `T: Trait`
 
 error[E0277]: the trait bound `isize: Trait` is not satisfied
   --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5
@@ -33,10 +33,10 @@ error[E0277]: the trait bound `U: Trait` is not satisfied
 LL | struct Foo<T:Trait> {
    | ------------------- required by `Foo`
 ...
+LL | struct Badness<U> {
+   |                - help: consider restricting this bound: `U: Trait`
 LL |     b: Foo<U>,
    |     ^^^^^^^^^ the trait `Trait` is not implemented for `U`
-   |
-   = help: consider adding a `where U: Trait` bound
 
 error[E0277]: the trait bound `V: Trait` is not satisfied
   --> $DIR/trait-bounds-on-structs-and-enums.rs:31:21
@@ -44,10 +44,10 @@ error[E0277]: the trait bound `V: Trait` is not satisfied
 LL | enum Bar<T:Trait> {
    | ----------------- required by `Bar`
 ...
+LL | enum MoreBadness<V> {
+   |                  - help: consider restricting this bound: `V: Trait`
 LL |     EvenMoreBadness(Bar<V>),
    |                     ^^^^^^ the trait `Trait` is not implemented for `V`
-   |
-   = help: consider adding a `where V: Trait` bound
 
 error[E0277]: the trait bound `i32: Trait` is not satisfied
   --> $DIR/trait-bounds-on-structs-and-enums.rs:35:5
diff --git a/src/test/ui/traits/trait-impl-for-module.stderr b/src/test/ui/traits/trait-impl-for-module.stderr
index 4a06cd777d4..c62bcfca94d 100644
--- a/src/test/ui/traits/trait-impl-for-module.stderr
+++ b/src/test/ui/traits/trait-impl-for-module.stderr
@@ -6,3 +6,4 @@ LL | impl A for a {
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 4c63d609775..88c9c473eb0 100644
--- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -4,12 +4,12 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` d
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |             ^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 24:6...
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 24:6...
   --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |      ^^
-note: ...but the lifetime must also be valid for the lifetime 'b as defined on the impl at 24:9...
+note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the impl at 24:9...
   --> $DIR/trait-impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:9
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
diff --git a/src/test/ui/traits/trait-matching-lifetimes.stderr b/src/test/ui/traits/trait-matching-lifetimes.stderr
index 80c577674d1..e1ccde3c9d1 100644
--- a/src/test/ui/traits/trait-matching-lifetimes.stderr
+++ b/src/test/ui/traits/trait-matching-lifetimes.stderr
@@ -6,12 +6,12 @@ LL |     fn foo(x: Foo<'b,'a>) {
    |
    = note: expected type `fn(Foo<'a, 'b>)`
               found type `fn(Foo<'b, 'a>)`
-note: the lifetime 'b as defined on the impl at 13:9...
+note: the lifetime `'b` as defined on the impl at 13:9...
   --> $DIR/trait-matching-lifetimes.rs:13:9
    |
 LL | impl<'a,'b> Tr for Foo<'a,'b> {
    |         ^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 13:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 13:6
   --> $DIR/trait-matching-lifetimes.rs:13:6
    |
 LL | impl<'a,'b> Tr for Foo<'a,'b> {
@@ -25,12 +25,12 @@ LL |     fn foo(x: Foo<'b,'a>) {
    |
    = note: expected type `fn(Foo<'a, 'b>)`
               found type `fn(Foo<'b, 'a>)`
-note: the lifetime 'a as defined on the impl at 13:6...
+note: the lifetime `'a` as defined on the impl at 13:6...
   --> $DIR/trait-matching-lifetimes.rs:13:6
    |
 LL | impl<'a,'b> Tr for Foo<'a,'b> {
    |      ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 13:9
+note: ...does not necessarily outlive the lifetime `'b` as defined on the impl at 13:9
   --> $DIR/trait-matching-lifetimes.rs:13:9
    |
 LL | impl<'a,'b> Tr for Foo<'a,'b> {
diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr
index d15edaa9c81..f1004ea9dc6 100644
--- a/src/test/ui/traits/trait-suggest-where-clause.stderr
+++ b/src/test/ui/traits/trait-suggest-where-clause.stderr
@@ -1,6 +1,9 @@
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:9:20
    |
+LL | fn check<T: Iterator, U: ?Sized>() {
+   |                       -- help: consider further restricting this bound: `U: std::marker::Sized +`
+LL |     // suggest a where-clause, if needed
 LL |     mem::size_of::<U>();
    |                    ^ doesn't have a size known at compile-time
    | 
@@ -11,11 +14,13 @@ LL | pub const fn size_of<T>() -> usize {
    |
    = help: the trait `std::marker::Sized` is not implemented for `U`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where U: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `U` cannot be known at compilation time
   --> $DIR/trait-suggest-where-clause.rs:12:5
    |
+LL | fn check<T: Iterator, U: ?Sized>() {
+   |                       -- help: consider further restricting this bound: `U: std::marker::Sized +`
+...
 LL |     mem::size_of::<Misc<U>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    | 
@@ -26,7 +31,6 @@ LL | pub const fn size_of<T>() -> usize {
    |
    = help: within `Misc<U>`, the trait `std::marker::Sized` is not implemented for `U`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where U: std::marker::Sized` bound
    = note: required because it appears within the type `Misc<U>`
 
 error[E0277]: the trait bound `u64: std::convert::From<T>` is not satisfied
@@ -35,7 +39,6 @@ error[E0277]: the trait bound `u64: std::convert::From<T>` is not satisfied
 LL |     <u64 as From<T>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<T>` is not implemented for `u64`
    |
-   = help: consider adding a `where u64: std::convert::From<T>` bound
    = note: required by `std::convert::From::from`
 
 error[E0277]: the trait bound `u64: std::convert::From<<T as std::iter::Iterator>::Item>` is not satisfied
@@ -44,7 +47,6 @@ error[E0277]: the trait bound `u64: std::convert::From<<T as std::iter::Iterator
 LL |     <u64 as From<<T as Iterator>::Item>>::from;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<<T as std::iter::Iterator>::Item>` is not implemented for `u64`
    |
-   = help: consider adding a `where u64: std::convert::From<<T as std::iter::Iterator>::Item>` bound
    = note: required by `std::convert::From::from`
 
 error[E0277]: the trait bound `Misc<_>: std::convert::From<T>` is not satisfied
diff --git a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr
index db77e82adbd..85c7a55c313 100644
--- a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr
+++ b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr
@@ -7,10 +7,10 @@ LL |     c.same_as(22)
 error[E0277]: the trait bound `C: CompareTo<i32>` is not satisfied
   --> $DIR/traits-repeated-supertrait-ambig.rs:30:7
    |
+LL | fn with_trait<C:CompareToInts>(c: &C) -> bool {
+   |               -- help: consider further restricting this bound: `C: CompareTo<i32> +`
 LL |     c.same_as(22)
    |       ^^^^^^^ the trait `CompareTo<i32>` is not implemented for `C`
-   |
-   = help: consider adding a `where C: CompareTo<i32>` bound
 
 error[E0277]: the trait bound `dyn CompareToInts: CompareTo<i32>` is not satisfied
   --> $DIR/traits-repeated-supertrait-ambig.rs:34:5
@@ -27,10 +27,10 @@ error[E0277]: the trait bound `C: CompareTo<i32>` is not satisfied
 LL |     fn same_as(&self, t: T) -> bool;
    |     -------------------------------- required by `CompareTo::same_as`
 ...
+LL | fn with_ufcs2<C:CompareToInts>(c: &C) -> bool {
+   |               -- help: consider further restricting this bound: `C: CompareTo<i32> +`
 LL |     CompareTo::same_as(c, 22)
    |     ^^^^^^^^^^^^^^^^^^ the trait `CompareTo<i32>` is not implemented for `C`
-   |
-   = help: consider adding a `where C: CompareTo<i32>` bound
 
 error[E0277]: the trait bound `i64: CompareTo<i32>` is not satisfied
   --> $DIR/traits-repeated-supertrait-ambig.rs:42:23
diff --git a/src/test/ui/try-block/try-block-in-edition2015.stderr b/src/test/ui/try-block/try-block-in-edition2015.stderr
index 7034cdce755..c94e43131fa 100644
--- a/src/test/ui/try-block/try-block-in-edition2015.stderr
+++ b/src/test/ui/try-block/try-block-in-edition2015.stderr
@@ -21,3 +21,4 @@ LL |     let try_result: Option<_> = try {
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
index dd90dd1b06f..63c07224353 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr
@@ -9,8 +9,10 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
    |
 LL | type Underconstrained<T: Trait> = impl 'static;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
+...
+LL | fn underconstrain<T>(_: T) -> Underconstrained<T> {
+   |                   - help: consider restricting this bound: `T: Trait`
    |
-   = help: consider adding a `where T: Trait` bound
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
index 574432bdcf6..ba892f6ed7c 100644
--- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr
@@ -15,9 +15,11 @@ error[E0277]: `U` doesn't implement `std::fmt::Debug`
    |
 LL | type Underconstrained<T: std::fmt::Debug> = impl 'static;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+...
+LL | fn underconstrained<U>(_: U) -> Underconstrained<U> {
+   |                     - help: consider restricting this bound: `U: std::fmt::Debug`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `U`
-   = help: consider adding a `where U: std::fmt::Debug` bound
    = note: the return type of a function must have a statically known size
 
 error[E0277]: `V` doesn't implement `std::fmt::Debug`
@@ -25,9 +27,11 @@ error[E0277]: `V` doesn't implement `std::fmt::Debug`
    |
 LL | type Underconstrained2<T: std::fmt::Debug> = impl 'static;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
+...
+LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
+   |                         - help: consider restricting this bound: `V: std::fmt::Debug`
    |
    = help: the trait `std::fmt::Debug` is not implemented for `V`
-   = help: consider adding a `where V: std::fmt::Debug` bound
    = note: the return type of a function must have a statically known size
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/type/type-ascription-with-fn-call.stderr b/src/test/ui/type/type-ascription-with-fn-call.stderr
index 624c817e33e..eeaca5300f9 100644
--- a/src/test/ui/type/type-ascription-with-fn-call.stderr
+++ b/src/test/ui/type/type-ascription-with-fn-call.stderr
@@ -11,3 +11,4 @@ LL |     f();
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr
index 742a709958f..6802bc38b89 100644
--- a/src/test/ui/type/type-check-defaults.stderr
+++ b/src/test/ui/type/type-check-defaults.stderr
@@ -52,9 +52,10 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL | trait Super<T: Copy> { }
    | -------------------- required by `Super`
 LL | trait Base<T = String>: Super<T> { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
+   | ^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^
+   | |          |
+   | |          help: consider restricting this bound: `T: std::marker::Copy`
+   | the trait `std::marker::Copy` is not implemented for `T`
 
 error[E0277]: cannot add `u8` to `i32`
   --> $DIR/type-check-defaults.rs:24:66
diff --git a/src/test/ui/type/type-params-in-different-spaces-2.stderr b/src/test/ui/type/type-params-in-different-spaces-2.stderr
index 7d4bbc813c0..7ce249a60b8 100644
--- a/src/test/ui/type/type-params-in-different-spaces-2.stderr
+++ b/src/test/ui/type/type-params-in-different-spaces-2.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `Self: Tr<U>` is not satisfied
 LL |     fn op(_: T) -> Self;
    |     -------------------- required by `Tr::op`
 ...
+LL |     fn test<U>(u: U) -> Self {
+   |                             - help: consider further restricting `Self`: `where Self: Tr<U>`
 LL |         Tr::op(u)
    |         ^^^^^^ the trait `Tr<U>` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: Tr<U>` bound
 
 error[E0277]: the trait bound `Self: Tr<U>` is not satisfied
   --> $DIR/type-params-in-different-spaces-2.rs:16:9
@@ -15,10 +15,10 @@ error[E0277]: the trait bound `Self: Tr<U>` is not satisfied
 LL |     fn op(_: T) -> Self;
    |     -------------------- required by `Tr::op`
 ...
+LL |     fn test<U>(u: U) -> Self {
+   |                             - help: consider further restricting `Self`: `where Self: Tr<U>`
 LL |         Tr::op(u)
    |         ^^^^^^ the trait `Tr<U>` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: Tr<U>` bound
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
new file mode 100644
index 00000000000..7a108d880be
--- /dev/null
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+// Test that we do not consider associated types to be sendable without
+// some applicable trait bound (and we don't ICE).
+#![allow(dead_code)]
+
+trait Trait {
+    type AssocType;
+    fn dummy(&self) { }
+}
+fn bar<T:Trait+Send>() where <T as Trait>::AssocType: std::marker::Send  {
+    is_send::<T::AssocType>(); //~ ERROR E0277
+}
+
+fn is_send<T:Send>() {
+}
+
+fn main() { }
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs
index d6483539386..bafc1657737 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.rs
@@ -1,5 +1,7 @@
+// run-rustfix
 // Test that we do not consider associated types to be sendable without
 // some applicable trait bound (and we don't ICE).
+#![allow(dead_code)]
 
 trait Trait {
     type AssocType;
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
index b842d0ae1a2..2e54cdf0132 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr
@@ -1,6 +1,8 @@
 error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely
-  --> $DIR/typeck-default-trait-impl-assoc-type.rs:9:5
+  --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5
    |
+LL | fn bar<T:Trait+Send>() {
+   |                       - help: consider further restricting the associated type: `where <T as Trait>::AssocType: std::marker::Send`
 LL |     is_send::<T::AssocType>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
 ...
@@ -8,7 +10,6 @@ LL | fn is_send<T:Send>() {
    |    -------   ---- required by this bound in `is_send`
    |
    = help: the trait `std::marker::Send` is not implemented for `<T as Trait>::AssocType`
-   = help: consider adding a `where <T as Trait>::AssocType: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
index b3139083b1a..a84aef5fdbd 100644
--- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
+++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr
@@ -1,6 +1,8 @@
 error[E0277]: `T` cannot be sent between threads safely
   --> $DIR/typeck-default-trait-impl-send-param.rs:5:15
    |
+LL | fn foo<T>() {
+   |        - help: consider restricting this bound: `T: std::marker::Send`
 LL |     is_send::<T>()
    |               ^ `T` cannot be sent between threads safely
 ...
@@ -8,7 +10,6 @@ LL | fn is_send<T:Send>() {
    |    -------   ---- required by this bound in `is_send`
    |
    = help: the trait `std::marker::Send` is not implemented for `T`
-   = help: consider adding a `where T: std::marker::Send` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr
index b2fe1b281fc..de3a997a19e 100644
--- a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr
+++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr
@@ -38,7 +38,7 @@ note: the anonymous lifetime #1 defined on the method body at 37:5...
    |
 LL |     fn dummy2(self: &Bar<T>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 35:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6
   --> $DIR/ufcs-explicit-self-bad.rs:35:6
    |
 LL | impl<'a, T> SomeTrait for &'a Bar<T> {
@@ -52,7 +52,7 @@ LL |     fn dummy2(self: &Bar<T>) {}
    |
    = note: expected type `&'a Bar<T>`
               found type `&Bar<T>`
-note: the lifetime 'a as defined on the impl at 35:6...
+note: the lifetime `'a` as defined on the impl at 35:6...
   --> $DIR/ufcs-explicit-self-bad.rs:35:6
    |
 LL | impl<'a, T> SomeTrait for &'a Bar<T> {
@@ -76,7 +76,7 @@ note: the anonymous lifetime #2 defined on the method body at 39:5...
    |
 LL |     fn dummy3(self: &&Bar<T>) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 35:6
+note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 35:6
   --> $DIR/ufcs-explicit-self-bad.rs:35:6
    |
 LL | impl<'a, T> SomeTrait for &'a Bar<T> {
@@ -90,7 +90,7 @@ LL |     fn dummy3(self: &&Bar<T>) {}
    |
    = note: expected type `&'a Bar<T>`
               found type `&Bar<T>`
-note: the lifetime 'a as defined on the impl at 35:6...
+note: the lifetime `'a` as defined on the impl at 35:6...
   --> $DIR/ufcs-explicit-self-bad.rs:35:6
    |
 LL | impl<'a, T> SomeTrait for &'a Bar<T> {
diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr
index 5ee8adaaf27..39752f66b9d 100644
--- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr
+++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr
@@ -200,5 +200,5 @@ LL |     <u8 as Dr>::X::N;
 
 error: aborting due to 32 previous errors
 
-Some errors have detailed explanations: E0223, E0433, E0599.
+Some errors have detailed explanations: E0223, E0433, E0575, E0599.
 For more information about an error, try `rustc --explain E0223`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs b/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs
index f86499e2e3f..5d1e00d2d35 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs
@@ -10,6 +10,7 @@
 // This is a regression test for issue #17021.
 //
 // compile-flags: -g
+// ignore-asmjs wasm2js does not support source maps yet
 
 use std::ptr;
 
diff --git a/src/test/ui/underscore-imports/hygiene-2.rs b/src/test/ui/underscore-imports/hygiene-2.rs
new file mode 100644
index 00000000000..bea61eae6b5
--- /dev/null
+++ b/src/test/ui/underscore-imports/hygiene-2.rs
@@ -0,0 +1,33 @@
+// Make sure that underscore imports with different contexts can exist in the
+// same scope.
+
+// check-pass
+
+#![feature(decl_macro)]
+
+mod x {
+    pub use std::ops::Deref as _;
+}
+
+macro n() {
+    pub use crate::x::*;
+}
+
+#[macro_export]
+macro_rules! p {
+    () => { pub use crate::x::*; }
+}
+
+macro m($y:ident) {
+    mod $y {
+        crate::n!(); // Reexport of `Deref` should not be imported in `main`
+        crate::p!(); // Reexport of `Deref` should be imported into `main`
+    }
+}
+
+m!(y);
+
+fn main() {
+    use crate::y::*;
+    (&()).deref();
+}
diff --git a/src/test/ui/underscore-imports/hygiene.rs b/src/test/ui/underscore-imports/hygiene.rs
new file mode 100644
index 00000000000..a254f6eaa59
--- /dev/null
+++ b/src/test/ui/underscore-imports/hygiene.rs
@@ -0,0 +1,40 @@
+// Make sure that underscore imports have the same hygiene considerations as
+// other imports.
+
+#![feature(decl_macro)]
+
+mod x {
+    pub use std::ops::Deref as _;
+}
+
+
+macro glob_import() {
+    pub use crate::x::*;
+}
+
+macro underscore_import() {
+    use std::ops::DerefMut as _;
+}
+
+mod y {
+    crate::glob_import!();
+    crate::underscore_import!();
+}
+
+macro create_module($y:ident) {
+    mod $y {
+        crate::glob_import!();
+        crate::underscore_import!();
+    }
+}
+
+create_module!(z);
+
+fn main() {
+    use crate::y::*;
+    use crate::z::*;
+    glob_import!();
+    underscore_import!();
+    (&()).deref();              //~ ERROR no method named `deref`
+    (&mut ()).deref_mut();      //~ ERROR no method named `deref_mut`
+}
diff --git a/src/test/ui/underscore-imports/hygiene.stderr b/src/test/ui/underscore-imports/hygiene.stderr
new file mode 100644
index 00000000000..44cfc5cc5d2
--- /dev/null
+++ b/src/test/ui/underscore-imports/hygiene.stderr
@@ -0,0 +1,27 @@
+error[E0599]: no method named `deref` found for type `&()` in the current scope
+  --> $DIR/hygiene.rs:38:11
+   |
+LL |     (&()).deref();
+   |           ^^^^^ method not found in `&()`
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use std::ops::Deref;
+   |
+
+error[E0599]: no method named `deref_mut` found for type `&mut ()` in the current scope
+  --> $DIR/hygiene.rs:39:15
+   |
+LL |     (&mut ()).deref_mut();
+   |               ^^^^^^^^^ method not found in `&mut ()`
+   |
+   = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+   |
+LL | use std::ops::DerefMut;
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/underscore-imports/macro-expanded.rs b/src/test/ui/underscore-imports/macro-expanded.rs
new file mode 100644
index 00000000000..43f527bc9a4
--- /dev/null
+++ b/src/test/ui/underscore-imports/macro-expanded.rs
@@ -0,0 +1,45 @@
+// Check that macro expanded underscore imports behave as expected
+
+// check-pass
+
+#![feature(decl_macro, rustc_attrs)]
+
+mod x {
+    pub use std::ops::Not as _;
+}
+
+macro m() {
+    mod w {
+        mod y {
+            pub use std::ops::Deref as _;
+        }
+        use crate::x::*;
+        use self::y::*;
+        use std::ops::DerefMut as _;
+        fn f() {
+            false.not();
+            (&()).deref();
+            (&mut ()).deref_mut();
+        }
+    }
+}
+
+#[rustc_macro_transparency = "transparent"]
+macro n() {
+    mod z {
+        pub use std::ops::Deref as _;
+    }
+    use crate::x::*;
+    use crate::z::*;
+    use std::ops::DerefMut as _;
+    fn f() {
+        false.not();
+        (&()).deref();
+        (&mut ()).deref_mut();
+    }
+}
+
+m!();
+n!();
+
+fn main() {}
diff --git a/src/test/ui/always-inhabited-union-ref.rs b/src/test/ui/uninhabited/always-inhabited-union-ref.rs
index 11eae2af9c9..11eae2af9c9 100644
--- a/src/test/ui/always-inhabited-union-ref.rs
+++ b/src/test/ui/uninhabited/always-inhabited-union-ref.rs
diff --git a/src/test/ui/always-inhabited-union-ref.stderr b/src/test/ui/uninhabited/always-inhabited-union-ref.stderr
index 792ab6f59a4..792ab6f59a4 100644
--- a/src/test/ui/always-inhabited-union-ref.stderr
+++ b/src/test/ui/uninhabited/always-inhabited-union-ref.stderr
diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs
new file mode 100644
index 00000000000..91e9a0d0b65
--- /dev/null
+++ b/src/test/ui/union/issue-41073.rs
@@ -0,0 +1,24 @@
+#![feature(untagged_unions)]
+
+union Test {
+    a: A, //~ ERROR unions may not contain fields that need dropping
+    b: B
+}
+
+#[derive(Debug)]
+struct A(i32);
+impl Drop for A {
+    fn drop(&mut self) { println!("A"); }
+}
+
+#[derive(Debug)]
+struct B(f32);
+impl Drop for B {
+    fn drop(&mut self) { println!("B"); }
+}
+
+fn main() {
+    let mut test = Test { a: A(3) };
+    println!("{:?}", unsafe { test.b });
+    unsafe { test.b = B(0.5); }
+}
diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr
new file mode 100644
index 00000000000..2e9598b2271
--- /dev/null
+++ b/src/test/ui/union/issue-41073.stderr
@@ -0,0 +1,15 @@
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/issue-41073.rs:4:5
+   |
+LL |     a: A,
+   |     ^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/issue-41073.rs:4:5
+   |
+LL |     a: A,
+   |     ^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs
index 1b6052f10ba..edf08e6ca67 100644
--- a/src/test/ui/union/union-borrow-move-parent-sibling.rs
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs
@@ -1,51 +1,90 @@
 #![feature(untagged_unions)]
 #![allow(unused)]
 
-#[allow(unions_with_drop_fields)]
+use std::ops::{Deref, DerefMut};
+
+#[derive(Default)]
+struct MockBox<T> {
+    value: [T; 1],
+}
+
+impl<T> MockBox<T> {
+    fn new(value: T) -> Self { MockBox { value: [value] } }
+}
+
+impl<T> Deref for MockBox<T> {
+    type Target = T;
+    fn deref(&self) -> &T { &self.value[0] }
+}
+
+impl<T> DerefMut for MockBox<T> {
+    fn deref_mut(&mut self) -> &mut T { &mut self.value[0] }
+}
+
+#[derive(Default)]
+struct MockVec<T> {
+    value: [T; 0],
+}
+
+impl<T> MockVec<T> {
+    fn new() -> Self { MockVec { value: [] } }
+}
+
+impl<T> Deref for MockVec<T> {
+    type Target = [T];
+    fn deref(&self) -> &[T] { &self.value }
+}
+
+impl<T> DerefMut for MockVec<T> {
+    fn deref_mut(&mut self) -> &mut [T] { &mut self.value }
+}
+
+
 union U {
-    x: ((Vec<u8>, Vec<u8>), Vec<u8>),
-    y: Box<Vec<u8>>,
+    x: ((MockVec<u8>, MockVec<u8>), MockVec<u8>),
+    y: MockBox<MockVec<u8>>,
 }
 
 fn use_borrow<T>(_: &T) {}
 
 unsafe fn parent_sibling_borrow() {
-    let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
     let a = &mut u.x.0;
     let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`)
     use_borrow(a);
 }
 
 unsafe fn parent_sibling_move() {
-    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
     let a = u.x.0;
     let b = u.y; //~ ERROR use of moved value: `u`
 }
 
 unsafe fn grandparent_sibling_borrow() {
-    let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
     let a = &mut (u.x.0).0;
     let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`)
     use_borrow(a);
 }
 
 unsafe fn grandparent_sibling_move() {
-    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
     let a = (u.x.0).0;
     let b = u.y; //~ ERROR use of moved value: `u`
 }
 
 unsafe fn deref_sibling_borrow() {
-    let mut u = U { y: Box::default() };
+    let mut u = U { y: MockBox::default() };
     let a = &mut *u.y;
     let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
     use_borrow(a);
 }
 
 unsafe fn deref_sibling_move() {
-    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
-    let a = *u.y;
-    let b = u.x; //~ ERROR use of moved value: `u`
+    let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+    // No way to test deref-move without Box in union
+    // let a = *u.y;
+    // let b = u.x; ERROR use of moved value: `u`
 }
 
 
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.stderr
index 2f4c921ea08..8ba155bafb0 100644
--- a/src/test/ui/union/union-borrow-move-parent-sibling.stderr
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:15:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:53:13
    |
 LL |     let a = &mut u.x.0;
    |             ---------- mutable borrow occurs here (via `u.x.0`)
@@ -11,9 +11,9 @@ LL |     use_borrow(a);
    = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
 
 error[E0382]: use of moved value: `u`
-  --> $DIR/union-borrow-move-parent-sibling.rs:22:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:60:13
    |
-LL |     let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+LL |     let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
    |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |     let a = u.x.0;
    |             ----- value moved here
@@ -21,7 +21,7 @@ LL |     let b = u.y;
    |             ^^^ value used here after move
 
 error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:28:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:66:13
    |
 LL |     let a = &mut (u.x.0).0;
    |             -------------- mutable borrow occurs here (via `u.x.0.0`)
@@ -33,38 +33,28 @@ LL |     use_borrow(a);
    = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
 
 error[E0382]: use of moved value: `u`
-  --> $DIR/union-borrow-move-parent-sibling.rs:35:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:73:13
    |
-LL |     let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+LL |     let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
    |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |     let a = (u.x.0).0;
    |             --------- value moved here
 LL |     let b = u.y;
    |             ^^^ value used here after move
 
-error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:41:13
+error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
+  --> $DIR/union-borrow-move-parent-sibling.rs:79:13
    |
 LL |     let a = &mut *u.y;
-   |             --------- mutable borrow occurs here (via `*u.y`)
+   |                   --- mutable borrow occurs here (via `u.y`)
 LL |     let b = &u.x;
-   |             ^^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here
+   |             ^^^^ immutable borrow of `u.x` -- which overlaps with `u.y` -- occurs here
 LL |     use_borrow(a);
    |                - mutable borrow later used here
    |
-   = note: `u.x` is a field of the union `U`, so it overlaps the field `*u.y`
+   = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
 
-error[E0382]: use of moved value: `u`
-  --> $DIR/union-borrow-move-parent-sibling.rs:48:13
-   |
-LL |     let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
-   |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
-LL |     let a = *u.y;
-   |             ---- value moved here
-LL |     let b = u.x;
-   |             ^^^ value used here after move
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0382, E0502.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs
new file mode 100644
index 00000000000..8f816cc1b73
--- /dev/null
+++ b/src/test/ui/union/union-custom-drop.rs
@@ -0,0 +1,19 @@
+// test for a union with a field that's a union with a manual impl Drop
+// Ensures we do not treat all unions as not having any drop glue.
+
+#![feature(untagged_unions)]
+
+union Foo {
+    bar: Bar, //~ ERROR unions may not contain fields that need dropping
+}
+
+union Bar {
+    a: i32,
+    b: u32,
+}
+
+impl Drop for Bar {
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr
new file mode 100644
index 00000000000..ee2333f905f
--- /dev/null
+++ b/src/test/ui/union/union-custom-drop.stderr
@@ -0,0 +1,15 @@
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/union-custom-drop.rs:7:5
+   |
+LL |     bar: Bar,
+   |     ^^^^^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/union-custom-drop.rs:7:5
+   |
+LL |     bar: Bar,
+   |     ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs
index 64c3caef449..60e280f53f5 100644
--- a/src/test/ui/union/union-derive-clone.rs
+++ b/src/test/ui/union/union-derive-clone.rs
@@ -1,5 +1,7 @@
 #![feature(untagged_unions)]
 
+use std::mem::ManuallyDrop;
+
 #[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied
 union U1 {
     a: u8,
@@ -18,14 +20,19 @@ union U3 {
 }
 
 #[derive(Clone, Copy)]
-union U4<T> {
+union U4<T: Copy> {
     a: T, // OK
 }
 
+#[derive(Clone, Copy)]
+union U5<T> {
+    a: ManuallyDrop<T>, // OK
+}
+
 #[derive(Clone)]
 struct CloneNoCopy;
 
 fn main() {
-    let u = U4 { a: CloneNoCopy };
-    let w = u.clone(); //~ ERROR no method named `clone` found for type `U4<CloneNoCopy>`
+    let u = U5 { a: ManuallyDrop::new(CloneNoCopy) };
+    let w = u.clone(); //~ ERROR no method named `clone` found for type `U5<CloneNoCopy>`
 }
diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr
index 4f4c779b12b..6893f9176f2 100644
--- a/src/test/ui/union/union-derive-clone.stderr
+++ b/src/test/ui/union/union-derive-clone.stderr
@@ -1,22 +1,22 @@
 error[E0277]: the trait bound `U1: std::marker::Copy` is not satisfied
-  --> $DIR/union-derive-clone.rs:3:10
+  --> $DIR/union-derive-clone.rs:5:10
    |
 LL | #[derive(Clone)]
    |          ^^^^^ the trait `std::marker::Copy` is not implemented for `U1`
    |
    = note: required by `std::clone::AssertParamIsCopy`
 
-error[E0599]: no method named `clone` found for type `U4<CloneNoCopy>` in the current scope
-  --> $DIR/union-derive-clone.rs:30:15
+error[E0599]: no method named `clone` found for type `U5<CloneNoCopy>` in the current scope
+  --> $DIR/union-derive-clone.rs:37:15
    |
-LL | union U4<T> {
+LL | union U5<T> {
    | ----------- method `clone` not found for this
 ...
 LL |     let w = u.clone();
-   |               ^^^^^ method not found in `U4<CloneNoCopy>`
+   |               ^^^^^ method not found in `U5<CloneNoCopy>`
    |
    = note: the method `clone` exists but the following trait bounds were not satisfied:
-           `U4<CloneNoCopy> : std::clone::Clone`
+           `U5<CloneNoCopy> : std::clone::Clone`
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `std::clone::Clone`
diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs
index d4b82cdb250..b2f7ae679fd 100644
--- a/src/test/ui/union/union-derive-rpass.rs
+++ b/src/test/ui/union/union-derive-rpass.rs
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
-#![allow(unions_with_drop_fields)]
 
 // Some traits can be derived for unions.
 
@@ -24,11 +23,11 @@ impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } }
     Copy,
     Eq
 )]
-union W<T> {
+union W<T: Copy> {
     a: T,
 }
 
-impl<T> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } }
+impl<T: Copy> PartialEq for W<T> { fn eq(&self, rhs: &Self) -> bool { true } }
 
 fn main() {
     let u = U { b: 0 };
diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs
index c4349c45464..f1511b0a601 100644
--- a/src/test/ui/union/union-drop-assign.rs
+++ b/src/test/ui/union/union-drop-assign.rs
@@ -1,15 +1,16 @@
 // run-pass
 #![allow(unused_assignments)]
-#![allow(unions_with_drop_fields)]
 
 // Drop works for union itself.
 
 #![feature(untagged_unions)]
 
+use std::mem::ManuallyDrop;
+
 struct S;
 
 union U {
-    a: S
+    a: ManuallyDrop<S>
 }
 
 impl Drop for S {
@@ -28,11 +29,11 @@ static mut CHECK: u8 = 0;
 
 fn main() {
     unsafe {
-        let mut u = U { a: S };
+        let mut u = U { a: ManuallyDrop::new(S) };
         assert_eq!(CHECK, 0);
-        u = U { a: S };
+        u = U { a: ManuallyDrop::new(S) };
         assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped
-        u.a = S;
+        *u.a = S;
         assert_eq!(CHECK, 11); // union field is assigned, field is dropped
     }
 }
diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs
index 2060950dda9..daa03ce6b6f 100644
--- a/src/test/ui/union/union-drop.rs
+++ b/src/test/ui/union/union-drop.rs
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
-#![allow(unions_with_drop_fields)]
 
 // Drop works for union itself.
 
@@ -21,12 +20,6 @@ union Y {
     a: S,
 }
 
-impl Drop for S {
-    fn drop(&mut self) {
-        unsafe { CHECK += 10; }
-    }
-}
-
 impl Drop for U {
     fn drop(&mut self) {
         unsafe { CHECK += 1; }
@@ -51,10 +44,10 @@ fn main() {
         {
             let w = W { a: S };
         }
-        assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called
+        assert_eq!(CHECK, 2); // 2, dtor of W is called
         {
             let y = Y { a: S };
         }
-        assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called
+        assert_eq!(CHECK, 2); // 2, dtor of Y is called
     }
 }
diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs
index 6f2caf8dc5b..eb169c516d2 100644
--- a/src/test/ui/union/union-generic-rpass.rs
+++ b/src/test/ui/union/union-generic-rpass.rs
@@ -1,37 +1,33 @@
 // run-pass
 #![allow(dead_code)]
-#![allow(unions_with_drop_fields)]
 
 #![feature(untagged_unions)]
 
+use std::mem::ManuallyDrop;
+
 union MaybeItem<T: Iterator> {
-    elem: T::Item,
+    elem: ManuallyDrop<T::Item>,
     none: (),
 }
 
-union U<A, B> {
+union U<A, B> where A: Copy, B: Copy {
     a: A,
     b: B,
 }
 
-unsafe fn union_transmute<A, B>(a: A) -> B {
+unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy {
     U { a: a }.b
 }
 
 fn main() {
     unsafe {
-        let u = U::<String, Vec<u8>> { a: String::from("abcd") };
-
-        assert_eq!(u.b.len(), 4);
-        assert_eq!(u.b[0], b'a');
-
         let b = union_transmute::<(u8, u8), u16>((1, 1));
         assert_eq!(b, (1 << 8) + 1);
 
         let v: Vec<u8> = vec![1, 2, 3];
         let mut i = v.iter();
         i.next();
-        let mi = MaybeItem::<std::slice::Iter<_>> { elem: i.next().unwrap() };
-        assert_eq!(*mi.elem, 2);
+        let mi = MaybeItem::<std::slice::Iter<_>> { elem: ManuallyDrop::new(i.next().unwrap()) };
+        assert_eq!(**mi.elem, 2);
     }
 }
diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs
new file mode 100644
index 00000000000..a43a5050865
--- /dev/null
+++ b/src/test/ui/union/union-manuallydrop-rpass.rs
@@ -0,0 +1,42 @@
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+// run-pass
+
+use std::mem::needs_drop;
+use std::mem::ManuallyDrop;
+
+struct NeedDrop;
+
+impl Drop for NeedDrop {
+    fn drop(&mut self) {}
+}
+
+union UnionOk1<T> {
+    empty: (),
+    value: ManuallyDrop<T>,
+}
+
+union UnionOk2 {
+    value: ManuallyDrop<NeedDrop>,
+}
+
+#[allow(dead_code)]
+union UnionOk3<T: Copy> {
+    empty: (),
+    value: T,
+}
+
+trait Foo { }
+
+trait ImpliesCopy : Copy { }
+
+#[allow(dead_code)]
+union UnionOk4<T: ImpliesCopy> {
+    value: T,
+}
+
+fn main() {
+    // NeedDrop should not make needs_drop true
+    assert!(!needs_drop::<UnionOk1<NeedDrop>>());
+    assert!(!needs_drop::<UnionOk3<&dyn Foo>>());
+}
diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs
index 4cd64ddb5d6..59282bec59b 100644
--- a/src/test/ui/union/union-nodrop.rs
+++ b/src/test/ui/union/union-nodrop.rs
@@ -1,12 +1,11 @@
 // run-pass
 
-#![feature(core_intrinsics)]
 #![feature(untagged_unions)]
 
-#![allow(unions_with_drop_fields)]
 #![allow(dead_code)]
 
-use std::intrinsics::needs_drop;
+use std::mem::needs_drop;
+use std::mem::ManuallyDrop;
 
 struct NeedDrop;
 
@@ -16,10 +15,14 @@ impl Drop for NeedDrop {
 
 // Constant expressios allow `NoDrop` to go out of scope,
 // unlike a value of the interior type implementing `Drop`.
-static X: () = (NoDrop { inner: NeedDrop }, ()).1;
+static X: () = (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1;
+
+const Y: () = (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1;
+
+const fn _f() { (NoDrop { inner: ManuallyDrop::new(NeedDrop) }, ()).1 }
 
 // A union that scrubs the drop glue from its inner type
-union NoDrop<T> {inner: T}
+union NoDrop<T> { inner: ManuallyDrop<T> }
 
 // Copy currently can't be implemented on drop-containing unions,
 // this may change later
@@ -40,7 +43,7 @@ struct Baz {
     y: Box<u8>,
 }
 
-union ActuallyDrop<T> {inner: T}
+union ActuallyDrop<T> { inner: ManuallyDrop<T> }
 
 impl<T> Drop for ActuallyDrop<T> {
     fn drop(&mut self) {}
diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs
index 64c60604ba9..8234beb74a8 100644
--- a/src/test/ui/union/union-overwrite.rs
+++ b/src/test/ui/union/union-overwrite.rs
@@ -1,21 +1,27 @@
 // run-pass
-#![allow(unions_with_drop_fields)]
-
 #![feature(untagged_unions)]
 
 #[repr(C)]
+#[derive(Copy, Clone)]
 struct Pair<T, U>(T, U);
 #[repr(C)]
+#[derive(Copy, Clone)]
 struct Triple<T>(T, T, T);
 
 #[repr(C)]
-union U<A, B> {
+union U<A, B>
+where
+    A: Copy, B: Copy
+{
     a: Pair<A, A>,
     b: B,
 }
 
 #[repr(C)]
-union W<A, B> {
+union W<A, B>
+where
+    A: Copy, B: Copy
+{
     a: A,
     b: B,
 }
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
index 89140030683..c9fec1d21d1 100644
--- a/src/test/ui/union/union-sized-field.stderr
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -1,34 +1,37 @@
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:4:5
    |
+LL | union Foo<T: ?Sized> {
+   |           -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     value: T,
    |     ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: no field of a union may have a dynamically sized type
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:9:5
    |
+LL | struct Foo2<T: ?Sized> {
+   |             -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     value: T,
    |     ^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: only the last field of a struct may have a dynamically sized type
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:15:11
    |
+LL | enum Foo3<T: ?Sized> {
+   |           -- help: consider further restricting this bound: `T: std::marker::Sized +`
 LL |     Value(T),
    |           ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs
index 6cfde35fe4c..8535cbd019c 100644
--- a/src/test/ui/union/union-unsafe.rs
+++ b/src/test/ui/union/union-unsafe.rs
@@ -1,15 +1,16 @@
 #![feature(untagged_unions)]
+use std::mem::ManuallyDrop;
 
 union U1 {
     a: u8
 }
 
 union U2 {
-    a: String
+    a: ManuallyDrop<String>
 }
 
 union U3<T> {
-    a: T
+    a: ManuallyDrop<T>
 }
 
 union U4<T: Copy> {
@@ -17,13 +18,16 @@ union U4<T: Copy> {
 }
 
 fn generic_noncopy<T: Default>() {
-    let mut u3 = U3 { a: T::default() };
-    u3.a = T::default(); //~ ERROR assignment to non-`Copy` union field is unsafe
+    let mut u3 = U3 { a: ManuallyDrop::new(T::default()) };
+    u3.a = ManuallyDrop::new(T::default()); //~ ERROR assignment to non-`Copy` union field is unsafe
+    *u3.a = T::default(); //~ ERROR access to union field is unsafe
 }
 
 fn generic_copy<T: Copy + Default>() {
-    let mut u3 = U3 { a: T::default() };
-    u3.a = T::default(); // OK
+    let mut u3 = U3 { a: ManuallyDrop::new(T::default()) };
+    u3.a = ManuallyDrop::new(T::default()); // OK
+    *u3.a = T::default(); //~ ERROR access to union field is unsafe
+
     let mut u4 = U4 { a: T::default() };
     u4.a = T::default(); // OK
 }
@@ -32,14 +36,20 @@ fn main() {
     let mut u1 = U1 { a: 10 }; // OK
     let a = u1.a; //~ ERROR access to union field is unsafe
     u1.a = 11; // OK
+
     let U1 { a } = u1; //~ ERROR access to union field is unsafe
     if let U1 { a: 12 } = u1 {} //~ ERROR access to union field is unsafe
     // let U1 { .. } = u1; // OK
 
-    let mut u2 = U2 { a: String::from("old") }; // OK
-    u2.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe
-    let mut u3 = U3 { a: 0 }; // OK
-    u3.a = 1; // OK
-    let mut u3 = U3 { a: String::from("old") }; // OK
-    u3.a = String::from("new"); //~ ERROR assignment to non-`Copy` union field is unsafe
+    let mut u2 = U2 { a: ManuallyDrop::new(String::from("old")) }; // OK
+    u2.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union
+    *u2.a = String::from("new"); //~ ERROR access to union field is unsafe
+
+    let mut u3 = U3 { a: ManuallyDrop::new(0) }; // OK
+    u3.a = ManuallyDrop::new(1); // OK
+    *u3.a = 1; //~ ERROR access to union field is unsafe
+
+    let mut u3 = U3 { a: ManuallyDrop::new(String::from("old")) }; // OK
+    u3.a = ManuallyDrop::new(String::from("new")); //~ ERROR assignment to non-`Copy` union
+    *u3.a = String::from("new"); //~ ERROR access to union field is unsafe
 }
diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr
index ab62508fcf6..e020dab63f8 100644
--- a/src/test/ui/union/union-unsafe.stderr
+++ b/src/test/ui/union/union-unsafe.stderr
@@ -1,13 +1,29 @@
 error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:21:5
+  --> $DIR/union-unsafe.rs:22:5
    |
-LL |     u3.a = T::default();
-   |     ^^^^ assignment to non-`Copy` union field
+LL |     u3.a = ManuallyDrop::new(T::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
    |
    = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:33:13
+  --> $DIR/union-unsafe.rs:23:6
+   |
+LL |     *u3.a = T::default();
+   |      ^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:29:6
+   |
+LL |     *u3.a = T::default();
+   |      ^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:37:13
    |
 LL |     let a = u1.a;
    |             ^^^^ access to union field
@@ -15,7 +31,7 @@ LL |     let a = u1.a;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:35:14
+  --> $DIR/union-unsafe.rs:40:14
    |
 LL |     let U1 { a } = u1;
    |              ^ access to union field
@@ -23,7 +39,7 @@ LL |     let U1 { a } = u1;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:36:20
+  --> $DIR/union-unsafe.rs:41:20
    |
 LL |     if let U1 { a: 12 } = u1 {}
    |                    ^^ access to union field
@@ -31,21 +47,45 @@ LL |     if let U1 { a: 12 } = u1 {}
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:40:5
+  --> $DIR/union-unsafe.rs:45:5
    |
-LL |     u2.a = String::from("new");
-   |     ^^^^ assignment to non-`Copy` union field
+LL |     u2.a = ManuallyDrop::new(String::from("new"));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
    |
    = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
 
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:46:6
+   |
+LL |     *u2.a = String::from("new");
+   |      ^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:50:6
+   |
+LL |     *u3.a = 1;
+   |      ^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
 error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:44:5
+  --> $DIR/union-unsafe.rs:53:5
    |
-LL |     u3.a = String::from("new");
-   |     ^^^^ assignment to non-`Copy` union field
+LL |     u3.a = ManuallyDrop::new(String::from("new"));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field
    |
    = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
 
-error: aborting due to 6 previous errors
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-unsafe.rs:54:6
+   |
+LL |     *u3.a = String::from("new");
+   |      ^^^^ access to union field
+   |
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
+
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/union/union-with-drop-fields-lint-rpass.rs b/src/test/ui/union/union-with-drop-fields-lint-rpass.rs
deleted file mode 100644
index 4dbeb7c1e7e..00000000000
--- a/src/test/ui/union/union-with-drop-fields-lint-rpass.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-
-#![feature(untagged_unions)]
-#![allow(dead_code)]
-#![allow(unions_with_drop_fields)]
-
-union U {
-    a: u8, // OK
-}
-
-union W {
-    a: String, // OK
-    b: String, // OK
-}
-
-struct S(String);
-
-// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
-union Y {
-    a: S, // OK
-}
-
-// We don't know if `T` is trivially-destructable or not until trans
-union J<T> {
-    a: T, // OK
-}
-
-union H<T: Copy> {
-    a: T, // OK
-}
-
-fn main() {}
diff --git a/src/test/ui/union/union-with-drop-fields-lint.stderr b/src/test/ui/union/union-with-drop-fields-lint.stderr
deleted file mode 100644
index 2f90f240d2e..00000000000
--- a/src/test/ui/union/union-with-drop-fields-lint.stderr
+++ /dev/null
@@ -1,26 +0,0 @@
-error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
-  --> $DIR/union-with-drop-fields-lint.rs:10:5
-   |
-LL |     a: String,
-   |     ^^^^^^^^^
-   |
-note: lint level defined here
-  --> $DIR/union-with-drop-fields-lint.rs:3:9
-   |
-LL | #![deny(unions_with_drop_fields)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
-  --> $DIR/union-with-drop-fields-lint.rs:18:5
-   |
-LL |     a: S,
-   |     ^^^^
-
-error: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union
-  --> $DIR/union-with-drop-fields-lint.rs:23:5
-   |
-LL |     a: T,
-   |     ^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/union/union-with-drop-fields-lint.rs b/src/test/ui/union/union-with-drop-fields.rs
index 8e502aa55f9..e3c63a6d5b5 100644
--- a/src/test/ui/union/union-with-drop-fields-lint.rs
+++ b/src/test/ui/union/union-with-drop-fields.rs
@@ -1,13 +1,12 @@
 #![feature(untagged_unions)]
 #![allow(dead_code)]
-#![deny(unions_with_drop_fields)]
 
 union U {
     a: u8, // OK
 }
 
 union W {
-    a: String, //~ ERROR union contains a field with possibly non-trivial drop code
+    a: String, //~ ERROR unions may not contain fields that need dropping
     b: String, // OK, only one field is reported
 }
 
@@ -15,12 +14,12 @@ struct S(String);
 
 // `S` doesn't implement `Drop` trait, but still has non-trivial destructor
 union Y {
-    a: S, //~ ERROR union contains a field with possibly non-trivial drop code
+    a: S, //~ ERROR unions may not contain fields that need dropping
 }
 
 // We don't know if `T` is trivially-destructable or not until trans
 union J<T> {
-    a: T, //~ ERROR union contains a field with possibly non-trivial drop code
+    a: T, //~ ERROR unions may not contain fields that need dropping
 }
 
 union H<T: Copy> {
diff --git a/src/test/ui/union/union-with-drop-fields.stderr b/src/test/ui/union/union-with-drop-fields.stderr
new file mode 100644
index 00000000000..0e77279be61
--- /dev/null
+++ b/src/test/ui/union/union-with-drop-fields.stderr
@@ -0,0 +1,39 @@
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/union-with-drop-fields.rs:9:5
+   |
+LL |     a: String,
+   |     ^^^^^^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/union-with-drop-fields.rs:9:5
+   |
+LL |     a: String,
+   |     ^^^^^^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/union-with-drop-fields.rs:17:5
+   |
+LL |     a: S,
+   |     ^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/union-with-drop-fields.rs:17:5
+   |
+LL |     a: S,
+   |     ^^^^
+
+error[E0740]: unions may not contain fields that need dropping
+  --> $DIR/union-with-drop-fields.rs:22:5
+   |
+LL |     a: T,
+   |     ^^^^
+   |
+note: `std::mem::ManuallyDrop` can be used to wrap the type
+  --> $DIR/union-with-drop-fields.rs:22:5
+   |
+LL |     a: T,
+   |     ^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr
index e56176690a1..bd97b0203b5 100644
--- a/src/test/ui/unsized/unsized-bare-typaram.stderr
+++ b/src/test/ui/unsized/unsized-bare-typaram.stderr
@@ -4,11 +4,12 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim
 LL | fn bar<T: Sized>() { }
    |    --- - required by this bound in `bar`
 LL | fn foo<T: ?Sized>() { bar::<T>() }
-   |                             ^ doesn't have a size known at compile-time
+   |        --                   ^ doesn't have a size known at compile-time
+   |        |
+   |        help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr
index dff934834ef..341d3e4cc2d 100644
--- a/src/test/ui/unsized/unsized-enum.stderr
+++ b/src/test/ui/unsized/unsized-enum.stderr
@@ -5,11 +5,12 @@ LL | enum Foo<U> { FooSome(U), FooNone }
    | ----------- required by `Foo`
 LL | fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
 LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
-   |                                    ^^^^^^ doesn't have a size known at compile-time
+   |         --                         ^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr
index cdd5747d86b..e85b6d662f9 100644
--- a/src/test/ui/unsized/unsized-enum2.stderr
+++ b/src/test/ui/unsized/unsized-enum2.stderr
@@ -1,45 +1,53 @@
 error[E0277]: the size for values of type `W` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:23:8
    |
+LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
+   |        -- help: consider further restricting this bound: `W: std::marker::Sized +`
+LL |     // parameter
 LL |     VA(W),
    |        ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `W`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where W: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:25:8
    |
+LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
+   |                   -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     VB{x: X},
    |        ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:27:15
    |
+LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
+   |                              -- help: consider further restricting this bound: `Y: std::marker::Sized +`
+...
 LL |     VC(isize, Y),
    |               ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Y: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
   --> $DIR/unsized-enum2.rs:29:18
    |
+LL | enum E<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized> {
+   |                                         -- help: consider further restricting this bound: `Z: std::marker::Sized +`
+...
 LL |     VD{u: isize, x: Z},
    |                  ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Z`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Z: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
index 1a726bb089f..280b8fd43ca 100644
--- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
@@ -5,11 +5,12 @@ LL | struct S5<Y>(Y);
    | ---------------- required by `S5`
 LL | 
 LL | impl<X: ?Sized> S5<X> {
-   |                 ^^^^^ doesn't have a size known at compile-time
+   |      --         ^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr
index 0d4776ff6c2..2894d5d5671 100644
--- a/src/test/ui/unsized/unsized-struct.stderr
+++ b/src/test/ui/unsized/unsized-struct.stderr
@@ -5,11 +5,12 @@ LL | struct Foo<T> { data: T }
    | ------------- required by `Foo`
 LL | fn foo1<T>() { not_sized::<Foo<T>>() } // Hunky dory.
 LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
-   |                                    ^^^^^^ doesn't have a size known at compile-time
+   |         --                         ^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/unsized-struct.rs:13:24
@@ -18,11 +19,12 @@ LL | fn is_sized<T:Sized>() { }
    |    -------- - required by this bound in `is_sized`
 ...
 LL | fn bar2<T: ?Sized>() { is_sized::<Bar<T>>() }
-   |                        ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         --             ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |         |
+   |         help: consider further restricting this bound: `T: std::marker::Sized +`
    |
    = help: within `Bar<T>`, the trait `std::marker::Sized` is not implemented for `T`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where T: std::marker::Sized` bound
    = note: required because it appears within the type `Bar<T>`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
index f399f8ded10..ba1550439c0 100644
--- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr
@@ -5,11 +5,12 @@ LL | struct S5<Y>(Y);
    | ---------------- required by `S5`
 LL | 
 LL | impl<X: ?Sized> T3<X> for S5<X> {
-   |                 ^^^^^ doesn't have a size known at compile-time
+   |      --         ^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
index ee0d5ccccfe..41371d63f9e 100644
--- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
+++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr
@@ -2,11 +2,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
   --> $DIR/unsized-trait-impl-trait-arg.rs:8:17
    |
 LL | impl<X: ?Sized> T2<X> for S4<X> {
-   |                 ^^^^^ doesn't have a size known at compile-time
+   |      --         ^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr
index c821a08f6b5..232296ad091 100644
--- a/src/test/ui/unsized3.stderr
+++ b/src/test/ui/unsized3.stderr
@@ -1,6 +1,8 @@
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:7:13
    |
+LL | fn f1<X: ?Sized>(x: &X) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f2::<X>(x);
    |             ^ doesn't have a size known at compile-time
 ...
@@ -9,11 +11,12 @@ LL | fn f2<X>(x: &X) {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:18:13
    |
+LL | fn f3<X: ?Sized + T>(x: &X) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f4::<X>(x);
    |             ^ doesn't have a size known at compile-time
 ...
@@ -22,7 +25,6 @@ LL | fn f4<X: T>(x: &X) {
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:33:8
@@ -30,35 +32,38 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
 LL | fn f5<Y>(x: &Y) {}
    |    -- - required by this bound in `f5`
 ...
+LL | fn f8<X: ?Sized>(x1: &S<X>, x2: &S<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(x1);
    |        ^^ doesn't have a size known at compile-time
    |
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:40:8
    |
+LL | fn f9<X: ?Sized>(x1: Box<S<X>>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(&(*x1, 34));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:45:9
    |
+LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
+   |        -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(&(32, *x1));
    |         ^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
    = note: tuples must have a statically known size to be initialized
@@ -69,12 +74,13 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
 LL | fn f5<Y>(x: &Y) {}
    |    -- - required by this bound in `f5`
 ...
+LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
+   |        -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f5(&(32, *x1));
    |        ^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `({integer}, S<X>)`, the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: required because it appears within the type `S<X>`
    = note: required because it appears within the type `({integer}, S<X>)`
 
diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr
index 6dce9a04606..bfd3f4aa691 100644
--- a/src/test/ui/unsized5.stderr
+++ b/src/test/ui/unsized5.stderr
@@ -1,23 +1,26 @@
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized5.rs:4:5
    |
+LL | struct S1<X: ?Sized> {
+   |           -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     f1: X,
    |     ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: only the last field of a struct may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized5.rs:10:5
    |
+LL | struct S2<X: ?Sized> {
+   |           -- help: consider further restricting this bound: `X: std::marker::Sized +`
+LL |     f: isize,
 LL |     g: X,
    |     ^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: only the last field of a struct may have a dynamically sized type
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
@@ -43,23 +46,25 @@ LL |     f: [u8],
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized5.rs:25:8
    |
+LL | enum E<X: ?Sized> {
+   |        -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     V1(X, isize),
    |        ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized5.rs:29:8
    |
+LL | enum F<X: ?Sized> {
+   |        -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     V2{f1: X, f: isize},
    |        ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: no field of an enum variant may have a dynamically sized type
 
 error: aborting due to 6 previous errors
diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr
index a6a26573e7c..95acd987a5a 100644
--- a/src/test/ui/unsized6.stderr
+++ b/src/test/ui/unsized6.stderr
@@ -1,129 +1,148 @@
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized6.rs:9:9
    |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                             -- help: consider further restricting this bound: `Y: std::marker::Sized +`
+...
 LL |     let y: Y;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Y: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:7:12
    |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                  -- help: consider further restricting this bound: `X: std::marker::Sized +`
+LL |     let _: W; // <-- this is OK, no bindings created, no initializer.
 LL |     let _: (isize, (X, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `Z` cannot be known at compilation time
   --> $DIR/unsized6.rs:11:12
    |
+LL | fn f1<W: ?Sized, X: ?Sized, Y: ?Sized, Z: ?Sized>(x: &X) {
+   |                                        -- help: consider further restricting this bound: `Z: std::marker::Sized +`
+...
 LL |     let y: (isize, (Z, usize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Z`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Z: std::marker::Sized` bound
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:15:9
    |
+LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     let y: X;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `Y` cannot be known at compilation time
   --> $DIR/unsized6.rs:17:12
    |
+LL | fn f2<X: ?Sized, Y: ?Sized>(x: &X) {
+   |                  -- help: consider further restricting this bound: `Y: std::marker::Sized +`
+...
 LL |     let y: (isize, (Y, isize));
    |            ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `Y`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where Y: std::marker::Sized` bound
    = note: only the last element of a tuple may have a dynamically sized type
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:22:9
    |
+LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:24:9
    |
+LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:26:10
    |
+LL | fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:30:9
    |
+LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
 LL |     let y: X = *x1;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:32:9
    |
+LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let y = *x2;
    |         ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:34:10
    |
+LL | fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
+   |       -- help: consider further restricting this bound: `X: std::marker::Sized +`
+...
 LL |     let (y, z) = (*x3, 4);
    |          ^ doesn't have a size known at compile-time
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -131,11 +150,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
   --> $DIR/unsized6.rs:38:18
    |
 LL | fn g1<X: ?Sized>(x: X) {}
-   |                  ^ doesn't have a size known at compile-time
+   |       --         ^ doesn't have a size known at compile-time
+   |       |
+   |       help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
@@ -143,11 +163,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
   --> $DIR/unsized6.rs:40:22
    |
 LL | fn g2<X: ?Sized + T>(x: X) {}
-   |                      ^ doesn't have a size known at compile-time
+   |       --             ^ doesn't have a size known at compile-time
+   |       |
+   |       help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
 
diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr
index bb83b181184..c77503a6f87 100644
--- a/src/test/ui/unsized7.stderr
+++ b/src/test/ui/unsized7.stderr
@@ -2,11 +2,12 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim
   --> $DIR/unsized7.rs:12:21
    |
 LL | impl<X: ?Sized + T> T1<X> for S3<X> {
-   |                     ^^^^^ doesn't have a size known at compile-time
+   |      --             ^^^^^ doesn't have a size known at compile-time
+   |      |
+   |      help: consider further restricting this bound: `X: std::marker::Sized +`
    |
    = help: the trait `std::marker::Sized` is not implemented for `X`
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
-   = help: consider adding a `where X: std::marker::Sized` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/use/issue-18986.stderr b/src/test/ui/use/issue-18986.stderr
index 14e1bb62403..6c23178c700 100644
--- a/src/test/ui/use/issue-18986.stderr
+++ b/src/test/ui/use/issue-18986.stderr
@@ -6,3 +6,4 @@ LL |         Trait { x: 42 } => ()
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0574`.
diff --git a/src/test/ui/variance/variance-btree-invariant-types.stderr b/src/test/ui/variance/variance-btree-invariant-types.stderr
index 49222fc7fa6..0f93927683e 100644
--- a/src/test/ui/variance/variance-btree-invariant-types.stderr
+++ b/src/test/ui/variance/variance-btree-invariant-types.stderr
@@ -6,7 +6,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::IterMut<'_, &'new (), _>`
               found type `std::collections::btree_map::IterMut<'_, &'static (), _>`
-note: the lifetime 'new as defined on the function body at 3:21...
+note: the lifetime `'new` as defined on the function body at 3:21...
   --> $DIR/variance-btree-invariant-types.rs:3:21
    |
 LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> {
@@ -21,7 +21,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::IterMut<'_, _, &'new ()>`
               found type `std::collections::btree_map::IterMut<'_, _, &'static ()>`
-note: the lifetime 'new as defined on the function body at 6:21...
+note: the lifetime `'new` as defined on the function body at 6:21...
   --> $DIR/variance-btree-invariant-types.rs:6:21
    |
 LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> {
@@ -36,7 +36,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::IterMut<'_, &'static (), _>`
               found type `std::collections::btree_map::IterMut<'_, &'new (), _>`
-note: the lifetime 'new as defined on the function body at 9:24...
+note: the lifetime `'new` as defined on the function body at 9:24...
   --> $DIR/variance-btree-invariant-types.rs:9:24
    |
 LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> {
@@ -51,7 +51,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::IterMut<'_, _, &'static ()>`
               found type `std::collections::btree_map::IterMut<'_, _, &'new ()>`
-note: the lifetime 'new as defined on the function body at 12:24...
+note: the lifetime `'new` as defined on the function body at 12:24...
   --> $DIR/variance-btree-invariant-types.rs:12:24
    |
 LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> {
@@ -66,7 +66,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::OccupiedEntry<'_, &'new (), _>`
               found type `std::collections::btree_map::OccupiedEntry<'_, &'static (), _>`
-note: the lifetime 'new as defined on the function body at 16:20...
+note: the lifetime `'new` as defined on the function body at 16:20...
   --> $DIR/variance-btree-invariant-types.rs:16:20
    |
 LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>)
@@ -81,7 +81,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::OccupiedEntry<'_, _, &'new ()>`
               found type `std::collections::btree_map::OccupiedEntry<'_, _, &'static ()>`
-note: the lifetime 'new as defined on the function body at 20:20...
+note: the lifetime `'new` as defined on the function body at 20:20...
   --> $DIR/variance-btree-invariant-types.rs:20:20
    |
 LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>)
@@ -96,7 +96,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::OccupiedEntry<'_, &'static (), _>`
               found type `std::collections::btree_map::OccupiedEntry<'_, &'new (), _>`
-note: the lifetime 'new as defined on the function body at 24:23...
+note: the lifetime `'new` as defined on the function body at 24:23...
   --> $DIR/variance-btree-invariant-types.rs:24:23
    |
 LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>)
@@ -111,7 +111,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::OccupiedEntry<'_, _, &'static ()>`
               found type `std::collections::btree_map::OccupiedEntry<'_, _, &'new ()>`
-note: the lifetime 'new as defined on the function body at 28:23...
+note: the lifetime `'new` as defined on the function body at 28:23...
   --> $DIR/variance-btree-invariant-types.rs:28:23
    |
 LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>)
@@ -126,7 +126,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::VacantEntry<'_, &'new (), _>`
               found type `std::collections::btree_map::VacantEntry<'_, &'static (), _>`
-note: the lifetime 'new as defined on the function body at 33:20...
+note: the lifetime `'new` as defined on the function body at 33:20...
   --> $DIR/variance-btree-invariant-types.rs:33:20
    |
 LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>)
@@ -141,7 +141,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::VacantEntry<'_, _, &'new ()>`
               found type `std::collections::btree_map::VacantEntry<'_, _, &'static ()>`
-note: the lifetime 'new as defined on the function body at 37:20...
+note: the lifetime `'new` as defined on the function body at 37:20...
   --> $DIR/variance-btree-invariant-types.rs:37:20
    |
 LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>)
@@ -156,7 +156,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::VacantEntry<'_, &'static (), _>`
               found type `std::collections::btree_map::VacantEntry<'_, &'new (), _>`
-note: the lifetime 'new as defined on the function body at 41:23...
+note: the lifetime `'new` as defined on the function body at 41:23...
   --> $DIR/variance-btree-invariant-types.rs:41:23
    |
 LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>)
@@ -171,7 +171,7 @@ LL |     v
    |
    = note: expected type `std::collections::btree_map::VacantEntry<'_, _, &'static ()>`
               found type `std::collections::btree_map::VacantEntry<'_, _, &'new ()>`
-note: the lifetime 'new as defined on the function body at 45:23...
+note: the lifetime `'new` as defined on the function body at 45:23...
   --> $DIR/variance-btree-invariant-types.rs:45:23
    |
 LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>)
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.stderr b/src/test/ui/variance/variance-contravariant-arg-object.stderr
index 263c849e199..27017e5dc47 100644
--- a/src/test/ui/variance/variance-contravariant-arg-object.stderr
+++ b/src/test/ui/variance/variance-contravariant-arg-object.stderr
@@ -6,12 +6,12 @@ LL |     v
    |
    = note: expected type `dyn Get<&'min i32>`
               found type `dyn Get<&'max i32>`
-note: the lifetime 'min as defined on the function body at 10:21...
+note: the lifetime `'min` as defined on the function body at 10:21...
   --> $DIR/variance-contravariant-arg-object.rs:10:21
    |
 LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27
   --> $DIR/variance-contravariant-arg-object.rs:10:27
    |
 LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
@@ -25,12 +25,12 @@ LL |     v
    |
    = note: expected type `dyn Get<&'max i32>`
               found type `dyn Get<&'min i32>`
-note: the lifetime 'min as defined on the function body at 17:21...
+note: the lifetime `'min` as defined on the function body at 17:21...
   --> $DIR/variance-contravariant-arg-object.rs:17:21
    |
 LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 17:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 17:27
   --> $DIR/variance-contravariant-arg-object.rs:17:27
    |
 LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr
index ffe690dd220..1752b3b36a4 100644
--- a/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr
+++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr
@@ -6,12 +6,12 @@ LL |     impls_get::<G,&'min i32>()
    |
    = note: expected type `Get<&'min i32>`
               found type `Get<&'max i32>`
-note: the lifetime 'min as defined on the function body at 10:21...
+note: the lifetime `'min` as defined on the function body at 10:21...
   --> $DIR/variance-contravariant-arg-trait-match.rs:10:21
    |
 LL | fn get_min_from_max<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27
   --> $DIR/variance-contravariant-arg-trait-match.rs:10:27
    |
 LL | fn get_min_from_max<'min, 'max, G>()
@@ -25,12 +25,12 @@ LL |     impls_get::<G,&'max i32>()
    |
    = note: expected type `Get<&'max i32>`
               found type `Get<&'min i32>`
-note: the lifetime 'min as defined on the function body at 16:21...
+note: the lifetime `'min` as defined on the function body at 16:21...
   --> $DIR/variance-contravariant-arg-trait-match.rs:16:21
    |
 LL | fn get_max_from_min<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 16:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 16:27
   --> $DIR/variance-contravariant-arg-trait-match.rs:16:27
    |
 LL | fn get_max_from_min<'min, 'max, G>()
diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.stderr b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr
index 6f445d79bf5..e35aec4c0ce 100644
--- a/src/test/ui/variance/variance-contravariant-self-trait-match.stderr
+++ b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr
@@ -6,12 +6,12 @@ LL |     impls_get::<&'min G>();
    |
    = note: expected type `Get`
               found type `Get`
-note: the lifetime 'min as defined on the function body at 10:21...
+note: the lifetime `'min` as defined on the function body at 10:21...
   --> $DIR/variance-contravariant-self-trait-match.rs:10:21
    |
 LL | fn get_min_from_max<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27
   --> $DIR/variance-contravariant-self-trait-match.rs:10:27
    |
 LL | fn get_min_from_max<'min, 'max, G>()
@@ -25,12 +25,12 @@ LL |     impls_get::<&'max G>();
    |
    = note: expected type `Get`
               found type `Get`
-note: the lifetime 'min as defined on the function body at 16:21...
+note: the lifetime `'min` as defined on the function body at 16:21...
   --> $DIR/variance-contravariant-self-trait-match.rs:16:21
    |
 LL | fn get_max_from_min<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 16:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 16:27
   --> $DIR/variance-contravariant-self-trait-match.rs:16:27
    |
 LL | fn get_max_from_min<'min, 'max, G>()
diff --git a/src/test/ui/variance/variance-covariant-arg-object.stderr b/src/test/ui/variance/variance-covariant-arg-object.stderr
index 94f80c2b657..b986edb809f 100644
--- a/src/test/ui/variance/variance-covariant-arg-object.stderr
+++ b/src/test/ui/variance/variance-covariant-arg-object.stderr
@@ -6,12 +6,12 @@ LL |     v
    |
    = note: expected type `dyn Get<&'min i32>`
               found type `dyn Get<&'max i32>`
-note: the lifetime 'min as defined on the function body at 10:21...
+note: the lifetime `'min` as defined on the function body at 10:21...
   --> $DIR/variance-covariant-arg-object.rs:10:21
    |
 LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27
   --> $DIR/variance-covariant-arg-object.rs:10:27
    |
 LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
@@ -25,12 +25,12 @@ LL |     v
    |
    = note: expected type `dyn Get<&'max i32>`
               found type `dyn Get<&'min i32>`
-note: the lifetime 'min as defined on the function body at 18:21...
+note: the lifetime `'min` as defined on the function body at 18:21...
   --> $DIR/variance-covariant-arg-object.rs:18:21
    |
 LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 18:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 18:27
   --> $DIR/variance-covariant-arg-object.rs:18:27
    |
 LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.stderr b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr
index c0209edc915..aa383fcc262 100644
--- a/src/test/ui/variance/variance-covariant-arg-trait-match.stderr
+++ b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr
@@ -6,12 +6,12 @@ LL |     impls_get::<G,&'min i32>()
    |
    = note: expected type `Get<&'min i32>`
               found type `Get<&'max i32>`
-note: the lifetime 'min as defined on the function body at 10:21...
+note: the lifetime `'min` as defined on the function body at 10:21...
   --> $DIR/variance-covariant-arg-trait-match.rs:10:21
    |
 LL | fn get_min_from_max<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27
   --> $DIR/variance-covariant-arg-trait-match.rs:10:27
    |
 LL | fn get_min_from_max<'min, 'max, G>()
@@ -25,12 +25,12 @@ LL |     impls_get::<G,&'max i32>()
    |
    = note: expected type `Get<&'max i32>`
               found type `Get<&'min i32>`
-note: the lifetime 'min as defined on the function body at 17:21...
+note: the lifetime `'min` as defined on the function body at 17:21...
   --> $DIR/variance-covariant-arg-trait-match.rs:17:21
    |
 LL | fn get_max_from_min<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 17:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 17:27
   --> $DIR/variance-covariant-arg-trait-match.rs:17:27
    |
 LL | fn get_max_from_min<'min, 'max, G>()
diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.stderr b/src/test/ui/variance/variance-covariant-self-trait-match.stderr
index fe5fe105c6b..a25d1044d42 100644
--- a/src/test/ui/variance/variance-covariant-self-trait-match.stderr
+++ b/src/test/ui/variance/variance-covariant-self-trait-match.stderr
@@ -6,12 +6,12 @@ LL |     impls_get::<&'min G>();
    |
    = note: expected type `Get`
               found type `Get`
-note: the lifetime 'min as defined on the function body at 10:21...
+note: the lifetime `'min` as defined on the function body at 10:21...
   --> $DIR/variance-covariant-self-trait-match.rs:10:21
    |
 LL | fn get_min_from_max<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 10:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 10:27
   --> $DIR/variance-covariant-self-trait-match.rs:10:27
    |
 LL | fn get_min_from_max<'min, 'max, G>()
@@ -25,12 +25,12 @@ LL |     impls_get::<&'max G>();
    |
    = note: expected type `Get`
               found type `Get`
-note: the lifetime 'min as defined on the function body at 17:21...
+note: the lifetime `'min` as defined on the function body at 17:21...
   --> $DIR/variance-covariant-self-trait-match.rs:17:21
    |
 LL | fn get_max_from_min<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 17:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 17:27
   --> $DIR/variance-covariant-self-trait-match.rs:17:27
    |
 LL | fn get_max_from_min<'min, 'max, G>()
diff --git a/src/test/ui/variance/variance-invariant-arg-object.stderr b/src/test/ui/variance/variance-invariant-arg-object.stderr
index 50a8697d439..8ff1e23e8ad 100644
--- a/src/test/ui/variance/variance-invariant-arg-object.stderr
+++ b/src/test/ui/variance/variance-invariant-arg-object.stderr
@@ -6,12 +6,12 @@ LL |     v
    |
    = note: expected type `dyn Get<&'min i32>`
               found type `dyn Get<&'max i32>`
-note: the lifetime 'min as defined on the function body at 7:21...
+note: the lifetime `'min` as defined on the function body at 7:21...
   --> $DIR/variance-invariant-arg-object.rs:7:21
    |
 LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 7:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 7:27
   --> $DIR/variance-invariant-arg-object.rs:7:27
    |
 LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
@@ -25,12 +25,12 @@ LL |     v
    |
    = note: expected type `dyn Get<&'max i32>`
               found type `dyn Get<&'min i32>`
-note: the lifetime 'min as defined on the function body at 14:21...
+note: the lifetime `'min` as defined on the function body at 14:21...
   --> $DIR/variance-invariant-arg-object.rs:14:21
    |
 LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 14:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 14:27
   --> $DIR/variance-invariant-arg-object.rs:14:27
    |
 LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.stderr b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr
index c8a1111e623..b58993737c7 100644
--- a/src/test/ui/variance/variance-invariant-arg-trait-match.stderr
+++ b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr
@@ -6,12 +6,12 @@ LL |     impls_get::<G,&'min i32>()
    |
    = note: expected type `Get<&'min i32>`
               found type `Get<&'max i32>`
-note: the lifetime 'min as defined on the function body at 7:21...
+note: the lifetime `'min` as defined on the function body at 7:21...
   --> $DIR/variance-invariant-arg-trait-match.rs:7:21
    |
 LL | fn get_min_from_max<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 7:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 7:27
   --> $DIR/variance-invariant-arg-trait-match.rs:7:27
    |
 LL | fn get_min_from_max<'min, 'max, G>()
@@ -25,12 +25,12 @@ LL |     impls_get::<G,&'max i32>()
    |
    = note: expected type `Get<&'max i32>`
               found type `Get<&'min i32>`
-note: the lifetime 'min as defined on the function body at 13:21...
+note: the lifetime `'min` as defined on the function body at 13:21...
   --> $DIR/variance-invariant-arg-trait-match.rs:13:21
    |
 LL | fn get_max_from_min<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 13:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 13:27
   --> $DIR/variance-invariant-arg-trait-match.rs:13:27
    |
 LL | fn get_max_from_min<'min, 'max, G>()
diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.stderr b/src/test/ui/variance/variance-invariant-self-trait-match.stderr
index cb03d95f771..4a1d4d28b48 100644
--- a/src/test/ui/variance/variance-invariant-self-trait-match.stderr
+++ b/src/test/ui/variance/variance-invariant-self-trait-match.stderr
@@ -6,12 +6,12 @@ LL |     impls_get::<&'min G>();
    |
    = note: expected type `Get`
               found type `Get`
-note: the lifetime 'min as defined on the function body at 7:21...
+note: the lifetime `'min` as defined on the function body at 7:21...
   --> $DIR/variance-invariant-self-trait-match.rs:7:21
    |
 LL | fn get_min_from_max<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 7:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 7:27
   --> $DIR/variance-invariant-self-trait-match.rs:7:27
    |
 LL | fn get_min_from_max<'min, 'max, G>()
@@ -25,12 +25,12 @@ LL |     impls_get::<&'max G>();
    |
    = note: expected type `Get`
               found type `Get`
-note: the lifetime 'min as defined on the function body at 13:21...
+note: the lifetime `'min` as defined on the function body at 13:21...
   --> $DIR/variance-invariant-self-trait-match.rs:13:21
    |
 LL | fn get_max_from_min<'min, 'max, G>()
    |                     ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 13:27
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 13:27
   --> $DIR/variance-invariant-self-trait-match.rs:13:27
    |
 LL | fn get_max_from_min<'min, 'max, G>()
diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr
index 7c433378df5..618f56da512 100644
--- a/src/test/ui/variance/variance-use-contravariant-struct-1.stderr
+++ b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr
@@ -6,12 +6,12 @@ LL |     v
    |
    = note: expected type `SomeStruct<&'min ()>`
               found type `SomeStruct<&'max ()>`
-note: the lifetime 'min as defined on the function body at 8:8...
+note: the lifetime `'min` as defined on the function body at 8:8...
   --> $DIR/variance-use-contravariant-struct-1.rs:8:8
    |
 LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
    |        ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 8:13
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 8:13
   --> $DIR/variance-use-contravariant-struct-1.rs:8:13
    |
 LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.stderr
index 6ae7d12c463..0b3a8dcfc86 100644
--- a/src/test/ui/variance/variance-use-covariant-struct-1.stderr
+++ b/src/test/ui/variance/variance-use-covariant-struct-1.stderr
@@ -6,12 +6,12 @@ LL |     v
    |
    = note: expected type `SomeStruct<&'max ()>`
               found type `SomeStruct<&'min ()>`
-note: the lifetime 'min as defined on the function body at 6:8...
+note: the lifetime `'min` as defined on the function body at 6:8...
   --> $DIR/variance-use-covariant-struct-1.rs:6:8
    |
 LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>)
    |        ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 6:13
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 6:13
   --> $DIR/variance-use-covariant-struct-1.rs:6:13
    |
 LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>)
diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.stderr
index 793954e3a1f..31deefb535e 100644
--- a/src/test/ui/variance/variance-use-invariant-struct-1.stderr
+++ b/src/test/ui/variance/variance-use-invariant-struct-1.stderr
@@ -6,12 +6,12 @@ LL |     v
    |
    = note: expected type `SomeStruct<&'min ()>`
               found type `SomeStruct<&'max ()>`
-note: the lifetime 'min as defined on the function body at 8:8...
+note: the lifetime `'min` as defined on the function body at 8:8...
   --> $DIR/variance-use-invariant-struct-1.rs:8:8
    |
 LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
    |        ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 8:13
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 8:13
   --> $DIR/variance-use-invariant-struct-1.rs:8:13
    |
 LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
@@ -25,12 +25,12 @@ LL |     v
    |
    = note: expected type `SomeStruct<&'max ()>`
               found type `SomeStruct<&'min ()>`
-note: the lifetime 'min as defined on the function body at 15:8...
+note: the lifetime `'min` as defined on the function body at 15:8...
   --> $DIR/variance-use-invariant-struct-1.rs:15:8
    |
 LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>)
    |        ^^^^
-note: ...does not necessarily outlive the lifetime 'max as defined on the function body at 15:13
+note: ...does not necessarily outlive the lifetime `'max` as defined on the function body at 15:13
   --> $DIR/variance-use-invariant-struct-1.rs:15:13
    |
 LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>)
diff --git a/src/test/ui/variants/variant-used-as-type.stderr b/src/test/ui/variants/variant-used-as-type.stderr
index 1138b69ae3b..fdfc044d81f 100644
--- a/src/test/ui/variants/variant-used-as-type.stderr
+++ b/src/test/ui/variants/variant-used-as-type.stderr
@@ -24,3 +24,4 @@ LL | impl Ty {}
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/wf/issue-48638.rs b/src/test/ui/wf/issue-48638.rs
new file mode 100644
index 00000000000..f0784310332
--- /dev/null
+++ b/src/test/ui/wf/issue-48638.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait D {}
+pub struct DT;
+impl D for DT {}
+
+pub trait A<R: D>: Sized {
+    type AS;
+}
+
+pub struct As<R: D>(R);
+
+pub struct AT;
+impl<R: D> A<R> for AT {
+    type AS = As<R>;
+}
+
+#[repr(packed)]
+struct S(<AT as A<DT>>::AS);
+
+fn main() {}
diff --git a/src/test/ui/wf/wf-enum-bound.stderr b/src/test/ui/wf/wf-enum-bound.stderr
index d5632f4a9c2..eaacd6b6881 100644
--- a/src/test/ui/wf/wf-enum-bound.stderr
+++ b/src/test/ui/wf/wf-enum-bound.stderr
@@ -6,12 +6,11 @@ LL |   trait ExtraCopy<T:Copy> { }
 LL | 
 LL | / enum SomeEnum<T,U>
 LL | |     where T: ExtraCopy<U>
+   | |                          - help: consider further restricting type parameter `U`: `, U: std::marker::Copy`
 LL | | {
 LL | |     SomeVariant(T,U)
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr
index 51ee23fc5aa..52882c460d2 100644
--- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr
+++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr
@@ -4,10 +4,11 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
 LL | struct IsCopy<T:Copy> {
    | --------------------- required by `IsCopy`
 ...
+LL | enum AnotherEnum<A> {
+   |                  - help: consider restricting this bound: `A: std::marker::Copy`
+LL |     AnotherVariant {
 LL |         f: IsCopy<A>
    |         ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
-   |
-   = help: consider adding a `where A: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-enum-fields.stderr b/src/test/ui/wf/wf-enum-fields.stderr
index 5f4e7c66f54..0fea35d68ea 100644
--- a/src/test/ui/wf/wf-enum-fields.stderr
+++ b/src/test/ui/wf/wf-enum-fields.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
 LL | struct IsCopy<T:Copy> {
    | --------------------- required by `IsCopy`
 ...
+LL | enum SomeEnum<A> {
+   |               - help: consider restricting this bound: `A: std::marker::Copy`
 LL |     SomeVariant(IsCopy<A>)
    |                 ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
-   |
-   = help: consider adding a `where A: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr
index 4bc2e370f29..9b8b04a7b86 100644
--- a/src/test/ui/wf/wf-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-fn-where-clause.stderr
@@ -4,12 +4,13 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied
 LL |   trait ExtraCopy<T:Copy> { }
    |   ----------------------- required by `ExtraCopy`
 LL | 
-LL | / fn foo<T,U>() where T: ExtraCopy<U>
+LL |   fn foo<T,U>() where T: ExtraCopy<U>
+   |   ^                                  - help: consider further restricting type parameter `U`: `, U: std::marker::Copy`
+   |  _|
+   | |
 LL | | {
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time
   --> $DIR/wf-fn-where-clause.rs:12:1
diff --git a/src/test/ui/wf/wf-impl-associated-type-trait.stderr b/src/test/ui/wf/wf-impl-associated-type-trait.stderr
index ceafb4f6157..6d71670e6a8 100644
--- a/src/test/ui/wf/wf-impl-associated-type-trait.stderr
+++ b/src/test/ui/wf/wf-impl-associated-type-trait.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `T: MyHash` is not satisfied
 LL | pub struct MySet<T:MyHash> {
    | -------------------------- required by `MySet`
 ...
+LL | impl<T> Foo for T {
+   |      - help: consider restricting this bound: `T: MyHash`
 LL |     type Bar = MySet<T>;
    |     ^^^^^^^^^^^^^^^^^^^^ the trait `MyHash` is not implemented for `T`
-   |
-   = help: consider adding a `where T: MyHash` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr
index e7432f81987..3798ba1ec6e 100644
--- a/src/test/ui/wf/wf-in-fn-arg.stderr
+++ b/src/test/ui/wf/wf-in-fn-arg.stderr
@@ -4,12 +4,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL |   struct MustBeCopy<T:Copy> {
    |   ------------------------- required by `MustBeCopy`
 ...
-LL | / fn bar<T>(_: &MustBeCopy<T>)
+LL |   fn bar<T>(_: &MustBeCopy<T>)
+   |   ^      - help: consider restricting this bound: `T: std::marker::Copy`
+   |  _|
+   | |
 LL | | {
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-fn-ret.stderr b/src/test/ui/wf/wf-in-fn-ret.stderr
index 005ffe84502..2e46ce49000 100644
--- a/src/test/ui/wf/wf-in-fn-ret.stderr
+++ b/src/test/ui/wf/wf-in-fn-ret.stderr
@@ -4,12 +4,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL |   struct MustBeCopy<T:Copy> {
    |   ------------------------- required by `MustBeCopy`
 ...
-LL | / fn bar<T>() -> MustBeCopy<T>
+LL |   fn bar<T>() -> MustBeCopy<T>
+   |   ^      - help: consider restricting this bound: `T: std::marker::Copy`
+   |  _|
+   | |
 LL | | {
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr
index b4cd9210402..db4fb9f97f5 100644
--- a/src/test/ui/wf/wf-in-fn-type-arg.stderr
+++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr
@@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL | struct MustBeCopy<T:Copy> {
    | ------------------------- required by `MustBeCopy`
 ...
+LL | struct Bar<T> {
+   |            - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     // needs T: Copy
 LL |     x: fn(MustBeCopy<T>)
    |     ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr
index 988fbed8e91..09f8aa2a201 100644
--- a/src/test/ui/wf/wf-in-fn-type-ret.stderr
+++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr
@@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL | struct MustBeCopy<T:Copy> {
    | ------------------------- required by `MustBeCopy`
 ...
+LL | struct Foo<T> {
+   |            - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     // needs T: 'static
 LL |     x: fn() -> MustBeCopy<T>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-fn-where-clause.stderr b/src/test/ui/wf/wf-in-fn-where-clause.stderr
index 0af38ddcffe..979802dec49 100644
--- a/src/test/ui/wf/wf-in-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-in-fn-where-clause.stderr
@@ -6,11 +6,10 @@ LL |   trait MustBeCopy<T:Copy> {
 ...
 LL | / fn bar<T,U>()
 LL | |     where T: MustBeCopy<U>
+   | |                           - help: consider further restricting type parameter `U`: `, U: std::marker::Copy`
 LL | | {
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr
index 0f4b4e417ca..2711820d82c 100644
--- a/src/test/ui/wf/wf-in-obj-type-trait.stderr
+++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr
@@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL | struct MustBeCopy<T:Copy> {
    | ------------------------- required by `MustBeCopy`
 ...
+LL | struct Bar<T> {
+   |            - help: consider restricting this bound: `T: std::marker::Copy`
+LL |     // needs T: Copy
 LL |     x: dyn Object<MustBeCopy<T>>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr
index 1e258864d03..21f825ac9ef 100644
--- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr
+++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr
@@ -4,11 +4,11 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied
 LL |   trait ExtraCopy<T:Copy> { }
    |   ----------------------- required by `ExtraCopy`
 ...
+LL |   impl<T,U> Foo<T,U> {
+   |          - help: consider restricting this bound: `U: std::marker::Copy`
 LL | /     fn foo(self) where T: ExtraCopy<U>
 LL | |     {}
    | |______^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr
index 4c389b3ef3e..35b90933813 100644
--- a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr
+++ b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr
@@ -4,12 +4,13 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied
 LL |   trait ExtraCopy<T:Copy> { }
    |   ----------------------- required by `ExtraCopy`
 ...
-LL | / impl<T,U> Foo<T,U> where T: ExtraCopy<U>
+LL |   impl<T,U> Foo<T,U> where T: ExtraCopy<U>
+   |   ^                                       - help: consider further restricting type parameter `U`: `, U: std::marker::Copy`
+   |  _|
+   | |
 LL | | {
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr
index da4e8ebf9c0..93d16514a50 100644
--- a/src/test/ui/wf/wf-static-method.stderr
+++ b/src/test/ui/wf/wf-static-method.stderr
@@ -4,12 +4,12 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |         u
    |         ^
    |
-note: ...the reference is valid for the lifetime 'a as defined on the impl at 14:6...
+note: ...the reference is valid for the lifetime `'a` as defined on the impl at 14:6...
   --> $DIR/wf-static-method.rs:14:6
    |
 LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
    |      ^^
-note: ...but the borrowed content is only valid for the lifetime 'b as defined on the impl at 14:10
+note: ...but the borrowed content is only valid for the lifetime `'b` as defined on the impl at 14:10
   --> $DIR/wf-static-method.rs:14:10
    |
 LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
@@ -21,12 +21,12 @@ error[E0478]: lifetime bound not satisfied
 LL |         let me = Self::make_me();
    |                  ^^^^^^^^^^^^^
    |
-note: lifetime parameter instantiated with the lifetime 'b as defined on the impl at 23:10
+note: lifetime parameter instantiated with the lifetime `'b` as defined on the impl at 23:10
   --> $DIR/wf-static-method.rs:23:10
    |
 LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
    |          ^^
-note: but lifetime parameter must outlive the lifetime 'a as defined on the impl at 23:6
+note: but lifetime parameter must outlive the lifetime `'a` as defined on the impl at 23:6
   --> $DIR/wf-static-method.rs:23:6
    |
 LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
@@ -38,12 +38,12 @@ error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 LL |         u
    |         ^
    |
-note: ...the reference is valid for the lifetime 'a as defined on the impl at 31:6...
+note: ...the reference is valid for the lifetime `'a` as defined on the impl at 31:6...
   --> $DIR/wf-static-method.rs:31:6
    |
 LL | impl<'a, 'b> Evil<'a, 'b> {
    |      ^^
-note: ...but the borrowed content is only valid for the lifetime 'b as defined on the impl at 31:10
+note: ...but the borrowed content is only valid for the lifetime `'b` as defined on the impl at 31:10
   --> $DIR/wf-static-method.rs:31:10
    |
 LL | impl<'a, 'b> Evil<'a, 'b> {
@@ -55,7 +55,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` d
 LL |     <()>::static_evil(b)
    |     ^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'b as defined on the function body at 40:13...
+note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 40:13...
   --> $DIR/wf-static-method.rs:40:13
    |
 LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
@@ -65,7 +65,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |     <()>::static_evil(b)
    |                       ^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the function body at 40:9...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 40:9...
   --> $DIR/wf-static-method.rs:40:9
    |
 LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
@@ -82,7 +82,7 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` d
 LL |     <IndirectEvil>::static_evil(b)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'b as defined on the function body at 44:22...
+note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 44:22...
   --> $DIR/wf-static-method.rs:44:22
    |
 LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
@@ -92,7 +92,7 @@ note: ...so that reference does not outlive borrowed content
    |
 LL |     <IndirectEvil>::static_evil(b)
    |                                 ^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the function body at 44:18...
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 44:18...
   --> $DIR/wf-static-method.rs:44:18
    |
 LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
diff --git a/src/test/ui/wf/wf-struct-bound.stderr b/src/test/ui/wf/wf-struct-bound.stderr
index 2028a0baa17..21559773492 100644
--- a/src/test/ui/wf/wf-struct-bound.stderr
+++ b/src/test/ui/wf/wf-struct-bound.stderr
@@ -6,12 +6,11 @@ LL |   trait ExtraCopy<T:Copy> { }
 LL | 
 LL | / struct SomeStruct<T,U>
 LL | |     where T: ExtraCopy<U>
+   | |                          - help: consider further restricting type parameter `U`: `, U: std::marker::Copy`
 LL | | {
 LL | |     data: (T,U)
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr
index d2bff253678..6ac4f1e2da8 100644
--- a/src/test/ui/wf/wf-struct-field.stderr
+++ b/src/test/ui/wf/wf-struct-field.stderr
@@ -4,10 +4,10 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied
 LL | struct IsCopy<T:Copy> {
    | --------------------- required by `IsCopy`
 ...
+LL | struct SomeStruct<A> {
+   |                   - help: consider restricting this bound: `A: std::marker::Copy`
 LL |     data: IsCopy<A>
    |     ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A`
-   |
-   = help: consider adding a `where A: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-associated-type-bound.stderr b/src/test/ui/wf/wf-trait-associated-type-bound.stderr
index d5b2b5762a4..af0433fd22f 100644
--- a/src/test/ui/wf/wf-trait-associated-type-bound.stderr
+++ b/src/test/ui/wf/wf-trait-associated-type-bound.stderr
@@ -4,12 +4,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL |   trait ExtraCopy<T:Copy> { }
    |   ----------------------- required by `ExtraCopy`
 LL | 
-LL | / trait SomeTrait<T> {
+LL |   trait SomeTrait<T> {
+   |   ^               - help: consider restricting this bound: `T: std::marker::Copy`
+   |  _|
+   | |
 LL | |     type Type1: ExtraCopy<T>;
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-associated-type-trait.stderr b/src/test/ui/wf/wf-trait-associated-type-trait.stderr
index d8ab9550482..93cb948cdbf 100644
--- a/src/test/ui/wf/wf-trait-associated-type-trait.stderr
+++ b/src/test/ui/wf/wf-trait-associated-type-trait.stderr
@@ -3,11 +3,12 @@ error[E0277]: the trait bound `<Self as SomeTrait>::Type1: std::marker::Copy` is
    |
 LL | struct IsCopy<T:Copy> { x: T }
    | --------------------- required by `IsCopy`
-...
+LL | 
+LL | trait SomeTrait {
+   |                - help: consider further restricting the associated type: `where <Self as SomeTrait>::Type1: std::marker::Copy`
+LL |     type Type1;
 LL |     type Type2 = IsCopy<Self::Type1>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `<Self as SomeTrait>::Type1`
-   |
-   = help: consider adding a `where <Self as SomeTrait>::Type1: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-bound.stderr b/src/test/ui/wf/wf-trait-bound.stderr
index 85f12b2de54..13e2f8f5901 100644
--- a/src/test/ui/wf/wf-trait-bound.stderr
+++ b/src/test/ui/wf/wf-trait-bound.stderr
@@ -6,11 +6,10 @@ LL |   trait ExtraCopy<T:Copy> { }
 LL | 
 LL | / trait SomeTrait<T,U>
 LL | |     where T: ExtraCopy<U>
+   | |                          - help: consider further restricting type parameter `U`: `, U: std::marker::Copy`
 LL | | {
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `U`
-   |
-   = help: consider adding a `where U: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr
index 4d0e1f2f0f4..9f3545b9c6a 100644
--- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr
+++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr
@@ -4,14 +4,15 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied
 LL |   struct Bar<T:Eq+?Sized> { value: Box<T> }
    |   ----------------------- required by `Bar`
 ...
-LL | /     fn bar(&self, x: &Bar<Self>) {
+LL |       fn bar(&self, x: &Bar<Self>) {
+   |       ^                           - help: consider further restricting `Self`: `where Self: std::cmp::Eq`
+   |  _____|
+   | |
 LL | |
 LL | |         //
 LL | |         // Here, Eq ought to be implemented.
 LL | |     }
    | |_____^ the trait `std::cmp::Eq` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: std::cmp::Eq` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr
index e82b76b61c4..e32630a5a4a 100644
--- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr
+++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr
@@ -4,15 +4,16 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied
 LL |   struct Bar<T:Eq+?Sized> { value: Box<T> }
    |   ----------------------- required by `Bar`
 ...
-LL | /     fn bar(&self) -> Bar<Self> {
+LL |       fn bar(&self) -> Bar<Self> {
+   |       ^                         - help: consider further restricting `Self`: `where Self: std::cmp::Eq`
+   |  _____|
+   | |
 LL | |
 LL | |         //
 LL | |         // Here, Eq ought to be implemented.
 LL | |         loop { }
 LL | |     }
    | |_____^ the trait `std::cmp::Eq` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: std::cmp::Eq` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr
index 6504f6698d9..a443ff1bb63 100644
--- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr
@@ -4,14 +4,15 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied
 LL |   trait Bar<T:Eq+?Sized> { }
    |   ---------------------- required by `Bar`
 ...
-LL | /     fn bar<A>(&self) where A: Bar<Self> {
+LL |       fn bar<A>(&self) where A: Bar<Self> {
+   |       ^                                  - help: consider further restricting `Self`: `, Self: std::cmp::Eq`
+   |  _____|
+   | |
 LL | |
 LL | |         //
 LL | |         // Here, Eq ought to be implemented.
 LL | |     }
    | |_____^ the trait `std::cmp::Eq` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: std::cmp::Eq` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr
index 0887d4b2fcd..42a28ee6763 100644
--- a/src/test/ui/wf/wf-trait-fn-arg.stderr
+++ b/src/test/ui/wf/wf-trait-fn-arg.stderr
@@ -5,9 +5,10 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    | ----------------------- required by `Bar`
 ...
 LL |     fn bar(&self, x: &Bar<Self>);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: std::cmp::Eq` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |                           |
+   |     |                           help: consider further restricting `Self`: `where Self: std::cmp::Eq`
+   |     the trait `std::cmp::Eq` is not implemented for `Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-fn-ret.stderr b/src/test/ui/wf/wf-trait-fn-ret.stderr
index 5555081498c..7ec4dbe0056 100644
--- a/src/test/ui/wf/wf-trait-fn-ret.stderr
+++ b/src/test/ui/wf/wf-trait-fn-ret.stderr
@@ -5,9 +5,10 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    | ----------------------- required by `Bar`
 ...
 LL |     fn bar(&self) -> &Bar<Self>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: std::cmp::Eq` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |                          |
+   |     |                          help: consider further restricting `Self`: `where Self: std::cmp::Eq`
+   |     the trait `std::cmp::Eq` is not implemented for `Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-fn-where-clause.stderr
index 5e8fd898239..256edb5b2ca 100644
--- a/src/test/ui/wf/wf-trait-fn-where-clause.stderr
+++ b/src/test/ui/wf/wf-trait-fn-where-clause.stderr
@@ -5,9 +5,10 @@ LL | struct Bar<T:Eq+?Sized> { value: Box<T> }
    | ----------------------- required by `Bar`
 ...
 LL |     fn bar(&self) where Self: Sized, Bar<Self>: Copy;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self`
-   |
-   = help: consider adding a `where Self: std::cmp::Eq` bound
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |     |                                               |
+   |     |                                               help: consider further restricting `Self`: `, Self: std::cmp::Eq`
+   |     the trait `std::cmp::Eq` is not implemented for `Self`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/wf/wf-trait-superbound.stderr b/src/test/ui/wf/wf-trait-superbound.stderr
index 377ca640536..a61b8dd3a38 100644
--- a/src/test/ui/wf/wf-trait-superbound.stderr
+++ b/src/test/ui/wf/wf-trait-superbound.stderr
@@ -4,11 +4,12 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL |   trait ExtraCopy<T:Copy> { }
    |   ----------------------- required by `ExtraCopy`
 LL | 
-LL | / trait SomeTrait<T>: ExtraCopy<T> {
+LL |   trait SomeTrait<T>: ExtraCopy<T> {
+   |   ^               - help: consider restricting this bound: `T: std::marker::Copy`
+   |  _|
+   | |
 LL | | }
    | |_^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
index 727c9b8e067..995b5446003 100644
--- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
+++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr
@@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL | fn require_copy<T: Copy>(x: T) {}
    |    ------------    ---- required by this bound in `require_copy`
 ...
+LL | impl<T> Foo<T> {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+...
 LL |         require_copy(self.x);
    |                      ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
index 1c1937c3074..fe575f3a28a 100644
--- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
+++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr
@@ -4,10 +4,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
 LL | fn require_copy<T: Copy>(x: T) {}
    |    ------------    ---- required by this bound in `require_copy`
 ...
+LL | impl<T> Foo<T> for Bar<T> {
+   |      - help: consider restricting this bound: `T: std::marker::Copy`
+...
 LL |         require_copy(self.x);
    |                      ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
-   |
-   = help: consider adding a `where T: std::marker::Copy` bound
 
 error: aborting due to previous error
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject a429e8cc4614a46a86322a0777a477e2baa83f1
+Subproject 3a9abe3f065554a7fbc59f440df2baba4a6e47e
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject 5cb983338e924ec85898880d60e65f2a1291b7b
+Subproject e8d5a9e95c145a3a9be89c582d8a6f88d4ea703
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index df56448dd22..03094885065 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -141,7 +141,10 @@ impl EarlyProps {
                 if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
                     props.ignore = Ignore::Ignore;
                 }
-
+                // FIXME: Re-enable run-fail once panics are handled correctly
+                if config.target.contains("emscripten") && config.mode == common::RunFail {
+                    props.ignore = Ignore::Ignore;
+                }
             }
 
             if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) &&
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 07ac10277ea5ad42efbb914da5844e0ab08efbf
+Subproject fccb2398248802a268fcda544ff3945247ef211
diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs
new file mode 100644
index 00000000000..ee555a3e5bd
--- /dev/null
+++ b/src/tools/tidy/src/debug_artifacts.rs
@@ -0,0 +1,24 @@
+//! Tidy check to prevent creation of unnecessary debug artifacts.
+
+use std::path::{Path, PathBuf};
+
+const GRAPHVIZ_POSTFLOW_MSG: &'static str =
+    "`borrowck_graphviz_postflow` attribute in test";
+
+pub fn check(path: &Path, bad: &mut bool) {
+    let test_dir: PathBuf = path.join("test");
+
+    super::walk(&test_dir, &mut super::filter_dirs, &mut |entry, contents| {
+        let filename = entry.path();
+        let is_rust = filename.extension().map_or(false, |ext| ext == "rs");
+        if !is_rust {
+            return;
+        }
+
+        for (i, line) in contents.lines().enumerate() {
+            if line.contains("borrowck_graphviz_postflow") {
+                tidy_error!(bad, "{}:{}: {}", filename.display(), i + 1, GRAPHVIZ_POSTFLOW_MSG);
+            }
+        }
+    });
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index eb93eb29747..d9db68ff66e 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -31,6 +31,7 @@ macro_rules! tidy_error {
 
 pub mod bins;
 pub mod style;
+pub mod debug_artifacts;
 pub mod errors;
 pub mod features;
 pub mod cargo;
@@ -45,7 +46,6 @@ pub mod error_codes_check;
 
 fn filter_dirs(path: &Path) -> bool {
     let skip = [
-        "src/llvm-emscripten",
         "src/llvm-project",
         "src/stdarch",
         "src/tools/cargo",
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index e08c23c01fe..de6b0c5b28d 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -22,6 +22,7 @@ fn main() {
     let verbose = args.iter().any(|s| *s == "--verbose");
     bins::check(&path, &mut bad);
     style::check(&path, &mut bad);
+    debug_artifacts::check(&path, &mut bad);
     errors::check(&path, &mut bad);
     cargo::check(&path, &mut bad);
     edition::check(&path, &mut bad);
diff --git a/triagebot.toml b/triagebot.toml
index d87c5b64c21..f0e3a99037b 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -8,3 +8,14 @@ allow-unauthenticated = [
 ]
 
 [assign]
+
+[ping.icebreakers-llvm]
+message = """\
+Hey LLVM ICE-breakers! This bug has been identified as a good
+"LLVM ICE-breaking candidate". In case it's useful, here are some
+[instructions] for tackling these sorts of bugs. Maybe take a look?
+Thanks! <3
+
+[instructions]: https://rust-lang.github.io/rustc-guide/ice-breaker/llvm.html
+"""
+label = "ICEBreaker-LLVM"