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.lock10
-rw-r--r--config.toml.example5
-rw-r--r--src/bootstrap/bootstrap.py4
-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.rs7
-rw-r--r--src/bootstrap/native.rs75
-rw-r--r--src/bootstrap/test.rs13
-rw-r--r--src/ci/docker/README.md9
-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
-rwxr-xr-xsrc/ci/init_repo.sh2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/codegen-options/index.md2
-rw-r--r--src/doc/rustc/src/command-line-arguments.md2
-rw-r--r--src/doc/rustc/src/lints/listing/warn-by-default.md24
-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/borrow.rs41
-rw-r--r--src/liballoc/collections/vec_deque.rs2
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/str.rs2
-rw-r--r--src/liballoc/sync.rs2
-rw-r--r--src/libcore/fmt/mod.rs2
-rw-r--r--src/libcore/iter/traits/collect.rs2
-rw-r--r--src/libcore/macros.rs27
-rw-r--r--src/libcore/num/dec2flt/algorithm.rs9
-rw-r--r--src/libcore/num/mod.rs4
-rw-r--r--src/libcore/ops/unsize.rs2
-rw-r--r--src/libcore/option.rs13
-rw-r--r--src/libcore/ptr/mod.rs4
-rw-r--r--src/libcore/str/mod.rs4
-rw-r--r--src/libpanic_unwind/gcc.rs12
-rw-r--r--src/libpanic_unwind/seh64_gnu.rs2
-rw-r--r--src/librustc/Cargo.toml2
-rw-r--r--src/librustc/dep_graph/graph.rs2
-rw-r--r--src/librustc/error_codes.rs83
-rw-r--r--src/librustc/hir/map/definitions.rs1
-rw-r--r--src/librustc/hir/mod.rs10
-rw-r--r--src/librustc/hir/ptr.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.rs24
-rw-r--r--src/librustc/infer/freshen.rs2
-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.rs1
-rw-r--r--src/librustc/lint/builtin.rs169
-rw-r--r--src/librustc/lint/context.rs238
-rw-r--r--src/librustc/lint/levels.rs22
-rw-r--r--src/librustc/lint/mod.rs103
-rw-r--r--src/librustc/middle/cstore.rs2
-rw-r--r--src/librustc/middle/mem_categorization.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/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.rs2
-rw-r--r--src/librustc/session/config.rs76
-rw-r--r--src/librustc/session/mod.rs11
-rw-r--r--src/librustc/session/search_paths.rs3
-rw-r--r--src/librustc/traits/error_reporting.rs32
-rw-r--r--src/librustc/traits/mod.rs3
-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/select.rs8
-rw-r--r--src/librustc/traits/structural_impls.rs4
-rw-r--r--src/librustc/ty/binding.rs2
-rw-r--r--src/librustc/ty/context.rs10
-rw-r--r--src/librustc/ty/error.rs4
-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/mod.rs8
-rw-r--r--src/librustc/ty/query/keys.rs9
-rw-r--r--src/librustc/ty/query/plumbing.rs4
-rw-r--r--src/librustc/ty/structural_impls.rs16
-rw-r--r--src/librustc/ty/sty.rs10
-rw-r--r--src/librustc/ty/subst.rs6
-rw-r--r--src/librustc/ty/util.rs2
-rw-r--r--src/librustc/ty/wf.rs25
-rw-r--r--src/librustc_codegen_llvm/Cargo.toml6
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs4
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs4
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs3
-rw-r--r--src/librustc_codegen_ssa/back/write.rs12
-rw-r--r--src/librustc_codegen_ssa/base.rs37
-rw-r--r--src/librustc_codegen_ssa/mir/operand.rs1
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs9
-rw-r--r--src/librustc_data_structures/graph/dominators/mod.rs27
-rw-r--r--src/librustc_data_structures/graph/implementation/mod.rs4
-rw-r--r--src/librustc_data_structures/sharded.rs2
-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.rs2
-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/Cargo.toml1
-rw-r--r--src/librustc_driver/lib.rs29
-rw-r--r--src/librustc_errors/diagnostic.rs26
-rw-r--r--src/librustc_errors/diagnostic_builder.rs5
-rw-r--r--src/librustc_errors/emitter.rs5
-rw-r--r--src/librustc_interface/Cargo.toml1
-rw-r--r--src/librustc_interface/interface.rs72
-rw-r--r--src/librustc_interface/lib.rs3
-rw-r--r--src/librustc_interface/passes.rs44
-rw-r--r--src/librustc_interface/queries.rs28
-rw-r--r--src/librustc_interface/tests.rs (renamed from src/librustc/session/config/tests.rs)78
-rw-r--r--src/librustc_interface/util.rs6
-rw-r--r--src/librustc_lint/builtin.rs47
-rw-r--r--src/librustc_lint/lib.rs239
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_metadata/creader.rs2
-rw-r--r--src/librustc_metadata/decoder.rs31
-rw-r--r--src/librustc_metadata/encoder.rs84
-rw-r--r--src/librustc_metadata/native_libs.rs4
-rw-r--r--src/librustc_metadata/schema.rs52
-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/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/universal_regions.rs2
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs4
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs6
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs6
-rw-r--r--src/librustc_mir/interpret/eval_context.rs4
-rw-r--r--src/librustc_mir/interpret/memory.rs23
-rw-r--r--src/librustc_mir/interpret/operand.rs10
-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.rs47
-rw-r--r--src/librustc_mir/transform/simplify.rs76
-rw-r--r--src/librustc_plugin/registry.rs42
-rw-r--r--src/librustc_resolve/error_codes.rs2
-rw-r--r--src/librustc_resolve/resolve_imports.rs3
-rw-r--r--src/librustc_target/spec/mod.rs6
-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_typeck/astconv.rs7
-rw-r--r--src/librustc_typeck/check/cast.rs43
-rw-r--r--src/librustc_typeck/check/coercion.rs41
-rw-r--r--src/librustc_typeck/check/demand.rs4
-rw-r--r--src/librustc_typeck/check/expr.rs16
-rw-r--r--src/librustc_typeck/check/method/suggest.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs62
-rw-r--r--src/librustc_typeck/check/op.rs4
-rw-r--r--src/librustc_typeck/check/pat.rs2
-rw-r--r--src/librustc_typeck/coherence/mod.rs5
-rw-r--r--src/librustc_typeck/error_codes.rs46
-rw-r--r--src/librustdoc/clean/mod.rs7
-rw-r--r--src/librustdoc/config.rs4
-rw-r--r--src/librustdoc/core.rs10
-rw-r--r--src/librustdoc/doctree.rs2
-rw-r--r--src/librustdoc/html/render.rs1
-rw-r--r--src/librustdoc/html/static/main.js3
-rw-r--r--src/librustdoc/test.rs6
-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.rs4
-rw-r--r--src/libstd/net/udp.rs2
-rw-r--r--src/libstd/panic.rs2
-rw-r--r--src/libstd/panicking.rs19
-rw-r--r--src/libstd/process.rs12
-rw-r--r--src/libstd/sys/unix/fd.rs34
-rw-r--r--src/libstd/sys/unix/fs.rs229
-rw-r--r--src/libstd/sys/unix/rand.rs2
-rw-r--r--src/libstd/sys/wasi/thread.rs8
-rw-r--r--src/libstd/sys/windows/handle.rs2
-rw-r--r--src/libstd/sys/windows/mutex.rs2
-rw-r--r--src/libstd/sys/windows/process.rs5
-rw-r--r--src/libstd/sys/windows/rand.rs2
-rw-r--r--src/libstd/sys/windows/thread_local.rs2
-rw-r--r--src/libstd/sys/windows/time.rs4
-rw-r--r--src/libstd/thread/local.rs5
-rw-r--r--src/libsyntax/ast.rs3
-rw-r--r--src/libsyntax/attr/builtin.rs9
-rw-r--r--src/libsyntax/feature_gate/active.rs3
-rw-r--r--src/libsyntax/lib.rs2
-rw-r--r--src/libsyntax/parse/parser.rs7
-rw-r--r--src/libsyntax/parse/parser/item.rs10
-rw-r--r--src/libsyntax/ptr.rs1
-rw-r--r--src/libsyntax/source_map.rs2
-rw-r--r--src/libsyntax/tokenstream.rs17
-rw-r--r--src/libsyntax_expand/base.rs15
-rw-r--r--src/libsyntax_expand/expand.rs9
-rw-r--r--src/libsyntax_expand/mbe.rs2
-rw-r--r--src/libsyntax_ext/source_util.rs24
-rw-r--r--src/libsyntax_pos/lib.rs2
-rw-r--r--src/libsyntax_pos/symbol.rs1
-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.rs1847
-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.rs64
-rw-r--r--src/libtest/time.rs206
-rw-r--r--src/libtest/types.rs145
m---------src/llvm-emscripten0
-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/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-make-fulldeps/issue-19371/foo.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/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/sanitizer-option.rs17
-rw-r--r--src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs7
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs24
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-for-crate.rs5
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs8
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs6
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-tool-test.rs8
-rw-r--r--src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs10
-rw-r--r--src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr2
-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/issue-63496.rs9
-rw-r--r--src/test/ui/associated-const/issue-63496.stderr21
-rw-r--r--src/test/ui/associated-type-bounds/union-bounds.rs15
-rw-r--r--src/test/ui/ast-json/ast-json-output.stdout2
-rw-r--r--src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr3
-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/non-async-enclosing-span.stderr1
-rw-r--r--src/test/ui/break-outside-loop.rs8
-rw-r--r--src/test/ui/break-outside-loop.stderr10
-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/coherence/coherence-unsafe-trait-object-impl.rs18
-rw-r--r--src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr12
-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/const-argument-cross-crate-mismatch.stderr16
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.rs3
-rw-r--r--src/test/ui/consts/const-eval/issue-65394.stderr6
-rw-r--r--src/test/ui/consts/const-int-pow-rpass.rs11
-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/drop/dynamic-drop.rs12
-rw-r--r--src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs41
-rw-r--r--src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr46
-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/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/issues/issue-17546.stderr4
-rw-r--r--src/test/ui/issues/issue-19538.stderr1
-rw-r--r--src/test/ui/issues/issue-20692.stderr1
-rw-r--r--src/test/ui/issues/issue-38604.stderr1
-rw-r--r--src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr (renamed from src/test/ui/kindck/kindck-inherited-copy-bound.stderr)7
-rw-r--r--src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr25
-rw-r--r--src/test/ui/kindck/kindck-inherited-copy-bound.rs11
-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/object-safety/object-safety-associated-consts.curr.stderr (renamed from src/test/ui/object-safety/object-safety-associated-consts.stderr)2
-rw-r--r--src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr15
-rw-r--r--src/test/ui/object-safety/object-safety-associated-consts.rs6
-rw-r--r--src/test/ui/object-safety/object-safety-generics.curr.stderr (renamed from src/test/ui/object-safety/object-safety-generics.stderr)4
-rw-r--r--src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr27
-rw-r--r--src/test/ui/object-safety/object-safety-generics.rs10
-rw-r--r--src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr (renamed from src/test/ui/object-safety/object-safety-mentions-Self.stderr)8
-rw-r--r--src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr27
-rw-r--r--src/test/ui/object-safety/object-safety-mentions-Self.rs20
-rw-r--r--src/test/ui/object-safety/object-safety-no-static.curr.stderr12
-rw-r--r--src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr15
-rw-r--r--src/test/ui/object-safety/object-safety-no-static.rs16
-rw-r--r--src/test/ui/object-safety/object-safety-sized-2.curr.stderr (renamed from src/test/ui/object-safety/object-safety-sized-2.stderr)2
-rw-r--r--src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr13
-rw-r--r--src/test/ui/object-safety/object-safety-sized-2.rs9
-rw-r--r--src/test/ui/object-safety/object-safety-sized.curr.stderr (renamed from src/test/ui/object-safety/object-safety-sized.stderr)2
-rw-r--r--src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr13
-rw-r--r--src/test/ui/object-safety/object-safety-sized.rs7
-rw-r--r--src/test/ui/repr/repr-packed-contains-align.stderr1
-rw-r--r--src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs23
-rw-r--r--src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs69
-rw-r--r--src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs37
-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/self/arbitrary-self-types-not-object-safe.curr.stderr24
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr15
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.rs8
-rw-r--r--src/test/ui/self/self-in-typedefs.rs11
-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/traits/trait-object-safety.stderr1
-rw-r--r--src/test/ui/traits/trait-test-2.stderr1
-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-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/wf/wf-convert-unsafe-trait-obj-box.rs18
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr33
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj.rs18
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr33
-rw-r--r--src/test/ui/wf/wf-unsafe-trait-obj-match.rs29
-rw-r--r--src/test/ui/wf/wf-unsafe-trait-obj-match.stderr38
m---------src/tools/clippy36
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
392 files changed, 6606 insertions, 4757 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 a5a7521abde..efcbd7b6794 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -556,9 +556,9 @@ dependencies = [
 
 [[package]]
 name = "compiletest_rs"
-version = "0.3.24"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "676a74b493d50ac33cacd83fd536597e6b52c0b46b9856f7b9c809d82fef4ac0"
+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",
 ]
@@ -3483,6 +3483,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_interface",
+ "rustc_lint",
  "rustc_metadata",
  "rustc_mir",
  "rustc_plugin",
@@ -3556,6 +3557,7 @@ dependencies = [
  "rustc_plugin_impl",
  "rustc_privacy",
  "rustc_resolve",
+ "rustc_target",
  "rustc_traits",
  "rustc_typeck",
  "serialize",
diff --git a/config.toml.example b/config.toml.example
index 2e3b714f922..be977024426 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -374,10 +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)
-# FIXME: remove the obsolete emscripten backend option.
+# 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/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 6fc72fa0b2a..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")
     }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index fb308bc35eb..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"};
@@ -163,25 +142,23 @@ impl Step for Llvm {
            .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");
             }
         }
 
-        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++");
@@ -209,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.
@@ -234,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
@@ -481,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 e09e25de64a..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()
             };
 
@@ -1165,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 {
@@ -1234,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/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/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/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/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index d5564fd798f..b603c7b231e 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -14,6 +14,7 @@
 - [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 b2cc65c11fd..bdb3c519658 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -145,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
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/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/borrow.rs b/src/liballoc/borrow.rs
index a9c5bce4c25..d2bdda83fa9 100644
--- a/src/liballoc/borrow.rs
+++ b/src/liballoc/borrow.rs
@@ -207,6 +207,47 @@ impl<B: ?Sized + ToOwned> Clone for Cow<'_, B> {
 }
 
 impl<B: ?Sized + ToOwned> Cow<'_, B> {
+    /// Returns true if the data is borrowed, i.e. if `to_mut` would require additional work.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cow_is_borrowed)]
+    /// use std::borrow::Cow;
+    ///
+    /// let cow = Cow::Borrowed("moo");
+    /// assert!(cow.is_borrowed());
+    ///
+    /// let bull: Cow<'_, str> = Cow::Owned("...moo?".to_string());
+    /// assert!(!bull.is_borrowed());
+    /// ```
+    #[unstable(feature = "cow_is_borrowed", issue = "65143")]
+    pub fn is_borrowed(&self) -> bool {
+        match *self {
+            Borrowed(_) => true,
+            Owned(_) => false,
+        }
+    }
+
+    /// Returns true if the data is owned, i.e. if `to_mut` would be a no-op.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(cow_is_borrowed)]
+    /// use std::borrow::Cow;
+    ///
+    /// let cow: Cow<'_, str> = Cow::Owned("moo".to_string());
+    /// assert!(cow.is_owned());
+    ///
+    /// let bull = Cow::Borrowed("...moo?");
+    /// assert!(!bull.is_owned());
+    /// ```
+    #[unstable(feature = "cow_is_borrowed", issue = "65143")]
+    pub fn is_owned(&self) -> bool {
+        !self.is_borrowed()
+    }
+
     /// Acquires a mutable reference to the owned form of the data.
     ///
     /// Clones the data if it is not already owned.
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 0bf573f5e25..8f3dfabd888 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -1817,7 +1817,7 @@ impl<T> VecDeque<T> {
             }
         }
 
-        return elem;
+        elem
     }
 
     /// Splits the `VecDeque` into two at the given index.
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 3684162d8b1..94379afc2bd 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -85,6 +85,7 @@
 #![feature(const_generic_impls_guard)]
 #![feature(const_generics)]
 #![feature(const_in_array_repeat_expressions)]
+#![feature(cow_is_borrowed)]
 #![feature(dispatch_from_dyn)]
 #![feature(core_intrinsics)]
 #![feature(container_error_extra)]
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index 9231c2d3f1d..83816d8b954 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -456,7 +456,7 @@ impl str {
                 }
             }
         }
-        return s;
+        s
     }
 
     /// Converts a [`Box<str>`] into a [`String`] without copying or allocating.
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 69f8f71197c..80d6c6e0d43 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -1638,7 +1638,7 @@ impl<T: ?Sized> Clone for Weak<T> {
             }
         }
 
-        return Weak { ptr: self.ptr };
+        Weak { ptr: self.ptr }
     }
 }
 
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 8413b2e0ac4..0e83a282b18 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -2025,7 +2025,7 @@ impl<T: ?Sized> Pointer for *const T {
         if f.alternate() {
             f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
 
-            if let None = f.width {
+            if f.width.is_none() {
                 f.width = Some(((mem::size_of::<usize>() * 8) / 4) + 2);
             }
         }
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/macros.rs b/src/libcore/macros.rs
index 1320e63df06..35558e3abcd 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -238,6 +238,33 @@ macro_rules! debug_assert_ne {
     ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
 }
 
+/// Returns whether the given expression matches any of the given patterns.
+///
+/// Like in a `match` expression, the pattern can be optionally followed by `if`
+/// and a guard expression that has access to names bound by the pattern.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(matches_macro)]
+///
+/// let foo = 'f';
+/// assert!(matches!(foo, 'A'..='Z' | 'a'..='z'));
+///
+/// let bar = Some(4);
+/// assert!(matches!(bar, Some(x) if x > 2));
+/// ```
+#[macro_export]
+#[unstable(feature = "matches_macro", issue = "65721")]
+macro_rules! matches {
+    ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => {
+        match $expression {
+            $( $pattern )|+ $( if $guard )? => true,
+            _ => false
+        }
+    }
+}
+
 /// Unwraps a result or propagates its error.
 ///
 /// The `?` operator was added to replace `try!` and should be used instead.
diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs
index fa3c8075378..ed89852dc48 100644
--- a/src/libcore/num/dec2flt/algorithm.rs
+++ b/src/libcore/num/dec2flt/algorithm.rs
@@ -143,13 +143,12 @@ pub fn fast_path<T: RawFloat>(integral: &[u8], fractional: &[u8], e: i64) -> Opt
 /// > not a bound for the true error, but bounds the difference between the approximation z and
 /// > the best possible approximation that uses p bits of significand.)
 pub fn bellerophon<T: RawFloat>(f: &Big, e: i16) -> T {
-    let slop;
-    if f <= &Big::from_u64(T::MAX_SIG) {
+    let slop = if f <= &Big::from_u64(T::MAX_SIG) {
         // The cases abs(e) < log5(2^N) are in fast_path()
-        slop = if e >= 0 { 0 } else { 3 };
+        if e >= 0 { 0 } else { 3 }
     } else {
-        slop = if e >= 0 { 1 } else { 4 };
-    }
+        if e >= 0 { 1 } else { 4 }
+    };
     let z = rawfp::big_to_fp(f).mul(&power_of_ten(e)).normalize();
     let exp_p_n = 1 << (P - T::SIG_BITS as u32);
     let lowbits: i64 = (z.f % exp_p_n) as i64;
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 8f4ade377e3..b4ade704144 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -3757,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/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..89f2d7ab29c 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,
         }
     }
 
@@ -837,9 +837,8 @@ impl<T> Option<T> {
     #[inline]
     #[stable(feature = "option_entry", since = "1.20.0")]
     pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
-        match *self {
-            None => *self = Some(f()),
-            _ => (),
+        if let None = *self {
+            *self = Some(f());
         }
 
         match *self {
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/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs
index 236ed150505..a35847c85fc 100644
--- a/src/libpanic_unwind/gcc.rs
+++ b/src/libpanic_unwind/gcc.rs
@@ -156,21 +156,21 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,
     if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
         match eh_action {
             EHAction::None |
-            EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND,
-            EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
-            EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR,
+            EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
+            EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
+            EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
         }
     } else {
         match eh_action {
-            EHAction::None => return uw::_URC_CONTINUE_UNWIND,
+            EHAction::None => uw::_URC_CONTINUE_UNWIND,
             EHAction::Cleanup(lpad) |
             EHAction::Catch(lpad) => {
                 uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
                 uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
                 uw::_Unwind_SetIP(context, lpad);
-                return uw::_URC_INSTALL_CONTEXT;
+                uw::_URC_INSTALL_CONTEXT
             }
-            EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR,
+            EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
         }
     }
 }
diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs
index 457ffcd34f9..16b699a4437 100644
--- a/src/libpanic_unwind/seh64_gnu.rs
+++ b/src/libpanic_unwind/seh64_gnu.rs
@@ -46,7 +46,7 @@ pub fn payload() -> *mut u8 {
 
 pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
     let panic_ctx = Box::from_raw(ptr as *mut PanicData);
-    return panic_ctx.data;
+    panic_ctx.data
 }
 
 // SEH doesn't support resuming unwinds after calling a landing pad like
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index cf9f36ca37c..93274ef0c92 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -36,5 +36,5 @@ 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/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 337cdddc432..0104507f702 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -35,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)
diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs
index 3d501cacf6f..122ae4a6cf6 100644
--- a/src/librustc/error_codes.rs
+++ b/src/librustc/error_codes.rs
@@ -2045,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
 }
 ```
 "##,
@@ -2126,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.
 
@@ -2218,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/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 893b295c60a..5993a97c40d 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -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/mod.rs b/src/librustc/hir/mod.rs
index cd111ab9f94..38c84ad3347 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1077,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,
@@ -1211,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,
@@ -1388,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),
@@ -1412,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/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/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 7e1dcdfe18f..a50cc86862e 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -1146,10 +1146,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         let span = cause.span(self.tcx);
 
-        diag.span_label(span, terr.to_string());
-        if let Some((sp, msg)) = secondary_span {
-            diag.span_label(sp, msg);
-        }
+        // Ignore msg for object safe coercion
+        // since E0038 message will be printed
+        match terr {
+            TypeError::ObjectUnsafeCoercion(_) => {}
+            _ => {
+                diag.span_label(span, terr.to_string());
+                if let Some((sp, msg)) = secondary_span {
+                    diag.span_label(sp, msg);
+                }
+            }
+        };
 
         if let Some((expected, found)) = expected_found {
             match (terr, is_simple_error, expected == found) {
@@ -1169,6 +1176,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         &sort_string(values.found),
                     );
                 }
+                (TypeError::ObjectUnsafeCoercion(_), ..) => {
+                    diag.note_unsuccessfull_coercion(found, expected);
+                }
                 (_, false, _) => {
                     if let Some(exp_found) = exp_found {
                         self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
@@ -1267,6 +1277,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let span = trace.cause.span(self.tcx);
         let failure_code = trace.cause.as_failure_code(terr);
         let mut diag = match failure_code {
+            FailureCode::Error0038(did) => {
+                let violations = self.tcx.object_safety_violations(did);
+                self.tcx.report_object_safety_error(span, did, violations)
+            }
             FailureCode::Error0317(failure_str) => {
                 struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
             }
@@ -1628,6 +1642,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 }
 
 enum FailureCode {
+    Error0038(DefId),
     Error0317(&'static str),
     Error0580(&'static str),
     Error0308(&'static str),
@@ -1666,6 +1681,7 @@ impl<'tcx> ObligationCause<'tcx> {
                 TypeError::IntrinsicCast => {
                     Error0308("cannot coerce intrinsics to function pointers")
                 }
+                TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
                 _ => Error0308("mismatched types"),
             },
         }
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/mod.rs b/src/librustc/infer/mod.rs
index 61e49d32fcd..e385d576b8c 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 8943fc342c0..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)]
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 4c28f6372fe..15598b60f5c 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -4,11 +4,12 @@
 //! compiler code, rather than using their own custom pass. Those
 //! lints are all available in `rustc_lint::builtin`.
 
-use crate::lint::{LintPass, LateLintPass, LintArray};
+use crate::lint::{LintPass, LateLintPass, LintArray, FutureIncompatibleInfo};
 use crate::middle::stability;
 use crate::session::Session;
 use errors::{Applicability, DiagnosticBuilder, pluralise};
 use syntax::ast;
+use syntax::edition::Edition;
 use syntax::source_map::Span;
 use syntax::symbol::Symbol;
 
@@ -22,7 +23,7 @@ declare_lint! {
     pub CONST_ERR,
     Deny,
     "constant evaluation detected erroneous expression",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 declare_lint! {
@@ -71,7 +72,7 @@ declare_lint! {
     pub UNREACHABLE_CODE,
     Warn,
     "detects unreachable code paths",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 declare_lint! {
@@ -131,7 +132,11 @@ declare_lint! {
 declare_lint! {
     pub PRIVATE_IN_PUBLIC,
     Warn,
-    "detect private items in public interfaces not caught by the old implementation"
+    "detect private items in public interfaces not caught by the old implementation",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+        edition: None,
+    };
 }
 
 declare_lint! {
@@ -143,13 +148,21 @@ declare_lint! {
 declare_lint! {
     pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
     Deny,
-    "detect public re-exports of private extern crates"
+    "detect public re-exports of private extern crates",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub INVALID_TYPE_PARAM_DEFAULT,
     Deny,
-    "type parameter default erroneously allowed in invalid location"
+    "type parameter default erroneously allowed in invalid location",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
+        edition: None,
+    };
 }
 
 declare_lint! {
@@ -161,63 +174,99 @@ declare_lint! {
 declare_lint! {
     pub SAFE_EXTERN_STATICS,
     Deny,
-    "safe access to extern statics was erroneously allowed"
+    "safe access to extern statics was erroneously allowed",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub SAFE_PACKED_BORROWS,
     Warn,
-    "safe borrows of fields of packed structs were was erroneously allowed"
+    "safe borrows of fields of packed structs were was erroneously allowed",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub PATTERNS_IN_FNS_WITHOUT_BODY,
     Warn,
-    "patterns in functions without body were erroneously allowed"
+    "patterns in functions without body were erroneously allowed",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub LEGACY_DIRECTORY_OWNERSHIP,
     Deny,
     "non-inline, non-`#[path]` modules (e.g., `mod foo;`) were erroneously allowed in some files \
-     not named `mod.rs`"
+     not named `mod.rs`",
+     @future_incompatible = FutureIncompatibleInfo {
+         reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
+         edition: None,
+     };
 }
 
 declare_lint! {
     pub LEGACY_CONSTRUCTOR_VISIBILITY,
     Deny,
-    "detects use of struct constructors that would be invisible with new visibility rules"
+    "detects use of struct constructors that would be invisible with new visibility rules",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub MISSING_FRAGMENT_SPECIFIER,
     Deny,
-    "detects missing fragment specifiers in unused `macro_rules!` patterns"
+    "detects missing fragment specifiers in unused `macro_rules!` patterns",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
     Deny,
-    "detects parenthesized generic parameters in type and module names"
+    "detects parenthesized generic parameters in type and module names",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub LATE_BOUND_LIFETIME_ARGUMENTS,
     Warn,
-    "detects generic lifetime arguments in path segments with late bound lifetime parameters"
+    "detects generic lifetime arguments in path segments with late bound lifetime parameters",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub ORDER_DEPENDENT_TRAIT_OBJECTS,
     Deny,
-    "trait-object types were treated as different depending on marker-trait order"
+    "trait-object types were treated as different depending on marker-trait order",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub DEPRECATED,
     Warn,
     "detects use of deprecated items",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 declare_lint! {
@@ -253,7 +302,11 @@ declare_lint! {
 declare_lint! {
     pub TYVAR_BEHIND_RAW_POINTER,
     Warn,
-    "raw pointer to an inference variable"
+    "raw pointer to an inference variable",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
+        edition: Some(Edition::Edition2018),
+    };
 }
 
 declare_lint! {
@@ -272,19 +325,33 @@ declare_lint! {
     pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
     Allow,
     "fully qualified paths that start with a module name \
-     instead of `crate`, `self`, or an extern crate name"
+     instead of `crate`, `self`, or an extern crate name",
+     @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>",
+        edition: Some(Edition::Edition2018),
+     };
 }
 
 declare_lint! {
     pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
     Warn,
-    "floating-point literals cannot be used in patterns"
+    "floating-point literals cannot be used in patterns",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub UNSTABLE_NAME_COLLISIONS,
     Warn,
-    "detects name collision with an existing but unstable method"
+    "detects name collision with an existing but unstable method",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>",
+        edition: None,
+        // Note: this item represents future incompatibility of all unstable functions in the
+        //       standard library, and thus should never be removed or changed to an error.
+    };
 }
 
 declare_lint! {
@@ -302,7 +369,11 @@ declare_lint! {
 declare_lint! {
     pub DUPLICATE_MACRO_EXPORTS,
     Deny,
-    "detects duplicate macro exports"
+    "detects duplicate macro exports",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #35896 <https://github.com/rust-lang/rust/issues/35896>",
+        edition: Some(Edition::Edition2018),
+    };
 }
 
 declare_lint! {
@@ -326,13 +397,21 @@ declare_lint! {
 declare_lint! {
     pub WHERE_CLAUSES_OBJECT_SAFETY,
     Warn,
-    "checks the object safety of where clauses"
+    "checks the object safety of where clauses",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
     Warn,
-    "detects proc macro derives using inaccessible names from parent modules"
+    "detects proc macro derives using inaccessible names from parent modules",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
+        edition: None,
+    };
 }
 
 declare_lint! {
@@ -346,7 +425,11 @@ declare_lint! {
     pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
     Deny,
     "macro-expanded `macro_export` macros from the current crate \
-     cannot be referred to by absolute paths"
+     cannot be referred to by absolute paths",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
+        edition: None,
+    };
 }
 
 declare_lint! {
@@ -359,7 +442,11 @@ declare_lint! {
     pub INDIRECT_STRUCTURAL_MATCH,
     // defaulting to allow until rust-lang/rust#62614 is fixed.
     Allow,
-    "pattern with const indirectly referencing non-`#[structural_match]` type"
+    "pattern with const indirectly referencing non-`#[structural_match]` type",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
+        edition: None,
+    };
 }
 
 /// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`.
@@ -367,7 +454,11 @@ pub mod parser {
     declare_lint! {
         pub ILL_FORMED_ATTRIBUTE_INPUT,
         Warn,
-        "ill-formed attribute inputs that were previously accepted and used in practice"
+        "ill-formed attribute inputs that were previously accepted and used in practice",
+        @future_incompatible = super::FutureIncompatibleInfo {
+            reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
+            edition: None,
+        };
     }
 
     declare_lint! {
@@ -387,31 +478,47 @@ declare_lint! {
     pub DEPRECATED_IN_FUTURE,
     Allow,
     "detects use of items that will be deprecated in a future version",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 declare_lint! {
     pub AMBIGUOUS_ASSOCIATED_ITEMS,
     Deny,
-    "ambiguous associated items"
+    "ambiguous associated items",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub NESTED_IMPL_TRAIT,
     Warn,
-    "nested occurrence of `impl Trait` type"
+    "nested occurrence of `impl Trait` type",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub MUTABLE_BORROW_RESERVATION_CONFLICT,
     Warn,
-    "reservation of a two-phased borrow conflicts with other shared borrows"
+    "reservation of a two-phased borrow conflicts with other shared borrows",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>",
+        edition: None,
+    };
 }
 
 declare_lint! {
     pub SOFT_UNSTABLE,
     Deny,
-    "a feature gate that doesn't break dependent crates"
+    "a feature gate that doesn't break dependent crates",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>",
+        edition: None,
+    };
 }
 
 declare_lint_pass! {
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 1b38c908917..1cb53d754dc 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -22,11 +22,11 @@ use crate::hir::intravisit as hir_visit;
 use crate::hir::intravisit::Visitor;
 use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
 use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject};
-use crate::lint::{LintArray, Level, Lint, LintId, LintPass, LintBuffer};
+use crate::lint::{Level, Lint, LintId, LintPass, LintBuffer, FutureIncompatibleInfo};
 use crate::lint::builtin::BuiltinLintDiagnostics;
 use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
 use crate::middle::privacy::AccessLevels;
-use crate::session::{config, early_error, Session};
+use crate::session::Session;
 use crate::ty::{self, print::Printer, subst::GenericArg, TyCtxt, Ty};
 use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
 use crate::util::nodemap::FxHashMap;
@@ -35,10 +35,9 @@ use crate::util::common::time;
 use errors::DiagnosticBuilder;
 use std::slice;
 use std::default::Default as StdDefault;
-use rustc_data_structures::sync::{ReadGuard, Lock, ParallelIterator, join, par_iter};
+use rustc_data_structures::sync::{self, ParallelIterator, join, par_iter};
 use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
 use syntax::ast;
-use syntax::edition;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::visit as ast_visit;
 use syntax_pos::{MultiSpan, Span, symbol::Symbol};
@@ -50,24 +49,25 @@ use syntax_pos::{MultiSpan, Span, symbol::Symbol};
 pub struct LintStore {
     /// Registered lints. The bool is true if the lint was
     /// added by a plugin.
-    lints: Vec<(&'static Lint, bool)>,
+    lints: Vec<&'static Lint>,
 
-    /// Trait objects for each lint pass.
-    /// This is only `None` while performing a lint pass.
-    pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
-    early_passes: Option<Vec<EarlyLintPassObject>>,
-    late_passes: Lock<Option<Vec<LateLintPassObject>>>,
-    late_module_passes: Vec<LateLintPassObject>,
+    /// Constructor functions for each variety of lint pass.
+    ///
+    /// These should only be called once, but since we want to avoid locks or
+    /// interior mutability, we don't enforce this (and lints should, in theory,
+    /// be compatible with being constructed more than once, though not
+    /// necessarily in a sane manner. This is safe though.)
+    pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
+    early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
+    late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+    /// This is unique in that we construct them per-module, so not once.
+    late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
 
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
 
     /// Map of registered lint groups to what lints they expand to.
     lint_groups: FxHashMap<&'static str, LintGroup>,
-
-    /// Extra info for future incompatibility lints, describing the
-    /// issue or RFC that caused the incompatibility.
-    future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
 }
 
 /// Lints that are buffered up early on in the `Session` before the
@@ -81,18 +81,6 @@ pub struct BufferedEarlyLint {
     pub diagnostic: BuiltinLintDiagnostics,
 }
 
-/// Extra information for a future incompatibility lint. See the call
-/// to `register_future_incompatible` in `librustc_lint/lib.rs` for
-/// guidelines.
-pub struct FutureIncompatibleInfo {
-    pub id: LintId,
-    /// e.g., a URL for an issue/PR/RFC or error code
-    pub reference: &'static str,
-    /// If this is an edition fixing lint, the edition in which
-    /// this lint becomes obsolete
-    pub edition: Option<edition::Edition>,
-}
-
 /// The target of the `by_name` map, which accounts for renaming/deprecation.
 enum TargetLint {
     /// A direct lint target
@@ -142,17 +130,16 @@ impl LintStore {
     pub fn new() -> LintStore {
         LintStore {
             lints: vec![],
-            pre_expansion_passes: Some(vec![]),
-            early_passes: Some(vec![]),
-            late_passes: Lock::new(Some(vec![])),
+            pre_expansion_passes: vec![],
+            early_passes: vec![],
+            late_passes: vec![],
             late_module_passes: vec![],
             by_name: Default::default(),
-            future_incompatible: Default::default(),
             lint_groups: Default::default(),
         }
     }
 
-    pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
+    pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] {
         &self.lints
     }
 
@@ -168,99 +155,64 @@ impl LintStore {
             .collect()
     }
 
-    pub fn register_early_pass(&mut self,
-                               sess: Option<&Session>,
-                               from_plugin: bool,
-                               register_only: bool,
-                               pass: EarlyLintPassObject) {
-        self.push_pass(sess, from_plugin, &pass);
-        if !register_only {
-            self.early_passes.as_mut().unwrap().push(pass);
-        }
+    pub fn register_early_pass(
+        &mut self,
+        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync
+    ) {
+        self.early_passes.push(Box::new(pass));
     }
 
     pub fn register_pre_expansion_pass(
         &mut self,
-        sess: Option<&Session>,
-        from_plugin: bool,
-        register_only: bool,
-        pass: EarlyLintPassObject,
+        pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
     ) {
-        self.push_pass(sess, from_plugin, &pass);
-        if !register_only {
-            self.pre_expansion_passes.as_mut().unwrap().push(pass);
-        }
+        self.pre_expansion_passes.push(Box::new(pass));
     }
 
-    pub fn register_late_pass(&mut self,
-                              sess: Option<&Session>,
-                              from_plugin: bool,
-                              register_only: bool,
-                              per_module: bool,
-                              pass: LateLintPassObject) {
-        self.push_pass(sess, from_plugin, &pass);
-        if !register_only {
-            if per_module {
-                self.late_module_passes.push(pass);
-            } else {
-                self.late_passes.lock().as_mut().unwrap().push(pass);
-            }
-        }
+    pub fn register_late_pass(
+        &mut self,
+        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+    ) {
+        self.late_passes.push(Box::new(pass));
+    }
+
+    pub fn register_late_mod_pass(
+        &mut self,
+        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+    ) {
+        self.late_module_passes.push(Box::new(pass));
     }
 
     // Helper method for register_early/late_pass
-    fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
-                                        sess: Option<&Session>,
-                                        from_plugin: bool,
-                                        pass: &Box<P>) {
-        for lint in pass.get_lints() {
-            self.lints.push((lint, from_plugin));
+    pub fn register_lints(&mut self, lints: &[&'static Lint]) {
+        for lint in lints {
+            self.lints.push(lint);
 
             let id = LintId::of(lint);
             if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
-                let msg = format!("duplicate specification of lint {}", lint.name_lower());
-                match (sess, from_plugin) {
-                    // We load builtin lints first, so a duplicate is a compiler bug.
-                    // Use early_error when handling -W help with no crate.
-                    (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
-                    (Some(_), false) => bug!("{}", msg),
-
-                    // A duplicate name from a plugin is a user error.
-                    (Some(sess), true)  => sess.err(&msg[..]),
-                }
+                bug!("duplicate specification of lint {}", lint.name_lower())
             }
-        }
-    }
 
-    pub fn register_future_incompatible(&mut self,
-                                        sess: Option<&Session>,
-                                        lints: Vec<FutureIncompatibleInfo>) {
+            if let Some(FutureIncompatibleInfo { edition, .. }) = lint.future_incompatible {
+                if let Some(edition) = edition {
+                    self.lint_groups.entry(edition.lint_name())
+                        .or_insert(LintGroup {
+                            lint_ids: vec![],
+                            from_plugin: lint.is_plugin,
+                            depr: None,
+                        })
+                        .lint_ids.push(id);
+                }
 
-        for edition in edition::ALL_EDITIONS {
-            let lints = lints.iter().filter(|f| f.edition == Some(*edition)).map(|f| f.id)
-                             .collect::<Vec<_>>();
-            if !lints.is_empty() {
-                self.register_group(sess, false, edition.lint_name(), None, lints)
+                self.lint_groups.entry("future_incompatible")
+                    .or_insert(LintGroup {
+                        lint_ids: vec![],
+                        from_plugin: lint.is_plugin,
+                        depr: None,
+                    })
+                    .lint_ids.push(id);
             }
         }
-
-        let mut future_incompatible = Vec::with_capacity(lints.len());
-        for lint in lints {
-            future_incompatible.push(lint.id);
-            self.future_incompatible.insert(lint.id, lint);
-        }
-
-        self.register_group(
-            sess,
-            false,
-            "future_incompatible",
-            None,
-            future_incompatible,
-        );
-    }
-
-    pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
-        self.future_incompatible.get(&id)
     }
 
     pub fn register_group_alias(
@@ -277,7 +229,6 @@ impl LintStore {
 
     pub fn register_group(
         &mut self,
-        sess: Option<&Session>,
         from_plugin: bool,
         name: &'static str,
         deprecated_name: Option<&'static str>,
@@ -300,16 +251,7 @@ impl LintStore {
         }
 
         if !new {
-            let msg = format!("duplicate specification of lint group {}", name);
-            match (sess, from_plugin) {
-                // We load builtin lints first, so a duplicate is a compiler bug.
-                // Use early_error when handling -W help with no crate.
-                (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
-                (Some(_), false) => bug!("{}", msg),
-
-                // A duplicate name from a plugin is a user error.
-                (Some(sess), true)  => sess.err(&msg[..]),
-            }
+            bug!("duplicate specification of lint group {}", name);
         }
     }
 
@@ -522,7 +464,7 @@ pub struct LateContext<'a, 'tcx> {
     pub access_levels: &'a AccessLevels,
 
     /// The store of registered lints and the lint levels.
-    lint_store: ReadGuard<'a, LintStore>,
+    lint_store: &'tcx LintStore,
 
     last_node_with_lint_attrs: hir::HirId,
 
@@ -550,7 +492,7 @@ pub struct EarlyContext<'a> {
     builder: LintLevelsBuilder<'a>,
 
     /// The store of registered lints and the lint levels.
-    lint_store: ReadGuard<'a, LintStore>,
+    lint_store: &'a LintStore,
 
     buffered: LintBuffer,
 }
@@ -639,14 +581,15 @@ pub trait LintContext: Sized {
 impl<'a> EarlyContext<'a> {
     fn new(
         sess: &'a Session,
+        lint_store: &'a LintStore,
         krate: &'a ast::Crate,
         buffered: LintBuffer,
     ) -> EarlyContext<'a> {
         EarlyContext {
             sess,
             krate,
-            lint_store: sess.lint_store.borrow(),
-            builder: LintLevelSets::builder(sess),
+            lint_store,
+            builder: LintLevelSets::builder(sess, lint_store),
             buffered,
         }
     }
@@ -681,7 +624,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
                           f: F)
         where F: FnOnce(&mut Self)
     {
-        let push = self.context.builder.push(attrs);
+        let push = self.context.builder.push(attrs, &self.context.lint_store);
         self.check_id(id);
         self.enter_attrs(attrs);
         f(self);
@@ -1355,10 +1298,6 @@ impl LintPass for LateLintPassObjects<'_> {
     fn name(&self) -> &'static str {
         panic!()
     }
-
-    fn get_lints(&self) -> LintArray {
-        panic!()
-    }
 }
 
 macro_rules! expand_late_lint_pass_impl_methods {
@@ -1393,7 +1332,7 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
-        lint_store: tcx.sess.lint_store.borrow(),
+        lint_store: &tcx.lint_store,
         last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
         generics: None,
         only_module: true,
@@ -1425,8 +1364,8 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
 
     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
 
-    let mut passes: Vec<_> = tcx.sess.lint_store.borrow().late_module_passes
-                                .iter().map(|pass| pass.fresh_late_pass()).collect();
+    let mut passes: Vec<_> = tcx.lint_store.late_module_passes
+                                .iter().map(|pass| (pass)()).collect();
 
     if !passes.is_empty() {
         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
@@ -1443,7 +1382,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
         tables: &ty::TypeckTables::empty(None),
         param_env: ty::ParamEnv::empty(),
         access_levels,
-        lint_store: tcx.sess.lint_store.borrow(),
+        lint_store: &tcx.lint_store,
         last_node_with_lint_attrs: hir::CRATE_HIR_ID,
         generics: None,
         only_module: false,
@@ -1467,7 +1406,8 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
 }
 
 fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
-    let mut passes = tcx.sess.lint_store.borrow().late_passes.lock().take().unwrap();
+    let mut passes = tcx.lint_store
+        .late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
 
     if !tcx.sess.opts.debugging_opts.no_interleave_lints {
         if !passes.is_empty() {
@@ -1482,8 +1422,8 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b
             });
         }
 
-        let mut passes: Vec<_> = tcx.sess.lint_store.borrow().late_module_passes
-                                    .iter().map(|pass| pass.fresh_late_pass()).collect();
+        let mut passes: Vec<_> = tcx.lint_store.late_module_passes
+                                    .iter().map(|pass| (pass)()).collect();
 
         for pass in &mut passes {
             time(tcx.sess, &format!("running late module lint: {}", pass.name()), || {
@@ -1491,9 +1431,6 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b
             });
         }
     }
-
-    // Put the passes back in the session.
-    *tcx.sess.lint_store.borrow().late_passes.lock() = Some(passes);
 }
 
 /// Performs lint checking on a crate.
@@ -1525,10 +1462,6 @@ impl LintPass for EarlyLintPassObjects<'_> {
     fn name(&self) -> &'static str {
         panic!()
     }
-
-    fn get_lints(&self) -> LintArray {
-        panic!()
-    }
 }
 
 macro_rules! expand_early_lint_pass_impl_methods {
@@ -1553,12 +1486,13 @@ early_lint_methods!(early_lint_pass_impl, []);
 
 fn early_lint_crate<T: EarlyLintPass>(
     sess: &Session,
+    lint_store: &LintStore,
     krate: &ast::Crate,
     pass: T,
     buffered: LintBuffer,
 ) -> LintBuffer {
     let mut cx = EarlyContextAndPass {
-        context: EarlyContext::new(sess, krate, buffered),
+        context: EarlyContext::new(sess, lint_store, krate, buffered),
         pass,
     };
 
@@ -1577,28 +1511,30 @@ fn early_lint_crate<T: EarlyLintPass>(
 
 pub fn check_ast_crate<T: EarlyLintPass>(
     sess: &Session,
+    lint_store: &LintStore,
     krate: &ast::Crate,
     pre_expansion: bool,
     builtin_lints: T,
 ) {
-    let (mut passes, mut buffered) = if pre_expansion {
+    let (mut passes, mut buffered): (Vec<_>, _) = if pre_expansion {
         (
-            sess.lint_store.borrow_mut().pre_expansion_passes.take().unwrap(),
+            lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect(),
             LintBuffer::default(),
         )
     } else {
         (
-            sess.lint_store.borrow_mut().early_passes.take().unwrap(),
+            lint_store.early_passes.iter().map(|p| (p)()).collect(),
             sess.buffered_lints.borrow_mut().take().unwrap(),
         )
     };
 
     if !sess.opts.debugging_opts.no_interleave_lints {
-        buffered = early_lint_crate(sess, krate, builtin_lints, buffered);
+        buffered = early_lint_crate(sess, lint_store, krate, builtin_lints, buffered);
 
         if !passes.is_empty() {
             buffered = early_lint_crate(
                 sess,
+                lint_store,
                 krate,
                 EarlyLintPassObjects { lints: &mut passes[..] },
                 buffered,
@@ -1609,6 +1545,7 @@ pub fn check_ast_crate<T: EarlyLintPass>(
             buffered = time(sess, &format!("running lint: {}", pass.name()), || {
                 early_lint_crate(
                     sess,
+                    lint_store,
                     krate,
                     EarlyLintPassObjects { lints: slice::from_mut(pass) },
                     buffered,
@@ -1617,13 +1554,6 @@ pub fn check_ast_crate<T: EarlyLintPass>(
         }
     }
 
-    // Put the lint store levels and passes back in the session.
-    if pre_expansion {
-        sess.lint_store.borrow_mut().pre_expansion_passes = Some(passes);
-    } else {
-        sess.lint_store.borrow_mut().early_passes = Some(passes);
-    }
-
     // All of the buffered lints should have been emitted at this point.
     // If not, that means that we somehow buffered a lint for a node id
     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
@@ -1653,7 +1583,7 @@ impl Decodable for LintId {
     fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> {
         let s = d.read_str()?;
         ty::tls::with(|tcx| {
-            match tcx.sess.lint_store.borrow().find_lints(&s) {
+            match tcx.lint_store.find_lints(&s) {
                 Ok(ids) => {
                     if ids.len() != 0 {
                         panic!("invalid lint-id `{}`", s);
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 60b1b192d10..4c60492e470 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -3,7 +3,7 @@ use std::cmp;
 use crate::hir::HirId;
 use crate::ich::StableHashingContext;
 use crate::lint::builtin;
-use crate::lint::context::CheckLintNameResult;
+use crate::lint::context::{LintStore, CheckLintNameResult};
 use crate::lint::{self, Lint, LintId, Level, LintSource};
 use crate::session::Session;
 use crate::util::nodemap::FxHashMap;
@@ -35,21 +35,20 @@ enum LintSet {
 }
 
 impl LintLevelSets {
-    pub fn new(sess: &Session) -> LintLevelSets {
+    pub fn new(sess: &Session, lint_store: &LintStore) -> LintLevelSets {
         let mut me = LintLevelSets {
             list: Vec::new(),
             lint_cap: Level::Forbid,
         };
-        me.process_command_line(sess);
+        me.process_command_line(sess, lint_store);
         return me
     }
 
-    pub fn builder(sess: &Session) -> LintLevelsBuilder<'_> {
-        LintLevelsBuilder::new(sess, LintLevelSets::new(sess))
+    pub fn builder<'a>(sess: &'a Session, store: &LintStore) -> LintLevelsBuilder<'a> {
+        LintLevelsBuilder::new(sess, LintLevelSets::new(sess, store))
     }
 
-    fn process_command_line(&mut self, sess: &Session) {
-        let store = sess.lint_store.borrow();
+    fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
         let mut specs = FxHashMap::default();
         self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
@@ -186,9 +185,8 @@ impl<'a> LintLevelsBuilder<'a> {
     ///   #[allow]
     ///
     /// Don't forget to call `pop`!
-    pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
+    pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
         let mut specs = FxHashMap::default();
-        let store = self.sess.lint_store.borrow();
         let sess = self.sess;
         let bad_attr = |span| {
             struct_span_err!(sess, span, E0452, "malformed lint attribute input")
@@ -202,11 +200,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()]`
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 7443cca822a..3c35bdae66e 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -45,7 +45,7 @@ use syntax_pos::Span;
 
 pub use crate::lint::context::{LateContext, EarlyContext, LintContext, LintStore,
                         check_crate, check_ast_crate, late_lint_mod, CheckLintNameResult,
-                        FutureIncompatibleInfo, BufferedEarlyLint,};
+                        BufferedEarlyLint,};
 
 /// Specification of a single lint.
 #[derive(Copy, Clone, Debug)]
@@ -76,9 +76,35 @@ pub struct Lint {
 
     /// `true` if this lint is reported even inside expansions of external macros.
     pub report_in_external_macro: bool,
+
+    pub future_incompatible: Option<FutureIncompatibleInfo>,
+
+    pub is_plugin: bool,
+}
+
+/// Extra information for a future incompatibility lint.
+#[derive(Copy, Clone, Debug)]
+pub struct FutureIncompatibleInfo {
+    /// e.g., a URL for an issue/PR/RFC or error code
+    pub reference: &'static str,
+    /// If this is an edition fixing lint, the edition in which
+    /// this lint becomes obsolete
+    pub edition: Option<Edition>,
 }
 
 impl Lint {
+    pub const fn default_fields_for_macro() -> Self {
+        Lint {
+            name: "",
+            default_level: Level::Forbid,
+            desc: "",
+            edition_lint_opts: None,
+            is_plugin: false,
+            report_in_external_macro: false,
+            future_incompatible: None,
+        }
+    }
+
     /// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`.
     pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self {
         match lint_id {
@@ -105,18 +131,21 @@ impl Lint {
 #[macro_export]
 macro_rules! declare_lint {
     ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
-        declare_lint!{$vis $NAME, $Level, $desc, false}
-    );
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr, report_in_external_macro: $rep: expr) => (
-        declare_lint!{$vis $NAME, $Level, $desc, $rep}
+        declare_lint!(
+            $vis $NAME, $Level, $desc,
+        );
     );
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $external: expr) => (
+    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+     $(@future_incompatible = $fi:expr;)? $($v:ident),*) => (
         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
             name: stringify!($NAME),
             default_level: $crate::lint::$Level,
             desc: $desc,
             edition_lint_opts: None,
-            report_in_external_macro: $external,
+            is_plugin: false,
+            $($v: true,)*
+            $(future_incompatible: Some($fi),)*
+            ..$crate::lint::Lint::default_fields_for_macro()
         };
     );
     ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
@@ -128,6 +157,7 @@ macro_rules! declare_lint {
             desc: $desc,
             edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)),
             report_in_external_macro: false,
+            is_plugin: false,
         };
     );
 }
@@ -156,6 +186,8 @@ macro_rules! declare_tool_lint {
             desc: $desc,
             edition_lint_opts: None,
             report_in_external_macro: $external,
+            future_incompatible: None,
+            is_plugin: true,
         };
     );
 }
@@ -173,14 +205,6 @@ pub type LintArray = Vec<&'static Lint>;
 
 pub trait LintPass {
     fn name(&self) -> &'static str;
-
-    /// Gets descriptions of the lints this `LintPass` object can emit.
-    ///
-    /// N.B., there is no enforcement that the object only emits lints it registered.
-    /// And some `rustc` internal `LintPass`es register lints to be emitted by other
-    /// parts of the compiler. If you want enforced access restrictions for your
-    /// `Lint`, make it a private `static` item in its own module.
-    fn get_lints(&self) -> LintArray;
 }
 
 /// Implements `LintPass for $name` with the given list of `Lint` statics.
@@ -189,7 +213,9 @@ macro_rules! impl_lint_pass {
     ($name:ident => [$($lint:expr),* $(,)?]) => {
         impl LintPass for $name {
             fn name(&self) -> &'static str { stringify!($name) }
-            fn get_lints(&self) -> LintArray { $crate::lint_array!($($lint),*) }
+        }
+        impl $name {
+            pub fn get_lints() -> LintArray { $crate::lint_array!($($lint),*) }
         }
     };
 }
@@ -287,9 +313,6 @@ macro_rules! expand_lint_pass_methods {
 macro_rules! declare_late_lint_pass {
     ([], [$hir:tt], [$($methods:tt)*]) => (
         pub trait LateLintPass<'a, $hir>: LintPass {
-            fn fresh_late_pass(&self) -> LateLintPassObject {
-                panic!()
-            }
             expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]);
         }
     )
@@ -327,6 +350,12 @@ macro_rules! declare_combined_late_lint_pass {
                     $($passes: $constructor,)*
                 }
             }
+
+            $v fn get_lints() -> LintArray {
+                let mut lints = Vec::new();
+                $(lints.extend_from_slice(&$passes::get_lints());)*
+                lints
+            }
         }
 
         impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $name {
@@ -337,12 +366,6 @@ macro_rules! declare_combined_late_lint_pass {
             fn name(&self) -> &'static str {
                 panic!()
             }
-
-            fn get_lints(&self) -> LintArray {
-                let mut lints = Vec::new();
-                $(lints.extend_from_slice(&self.$passes.get_lints());)*
-                lints
-            }
         }
     )
 }
@@ -454,6 +477,12 @@ macro_rules! declare_combined_early_lint_pass {
                     $($passes: $constructor,)*
                 }
             }
+
+            $v fn get_lints() -> LintArray {
+                let mut lints = Vec::new();
+                $(lints.extend_from_slice(&$passes::get_lints());)*
+                lints
+            }
         }
 
         impl EarlyLintPass for $name {
@@ -464,12 +493,6 @@ macro_rules! declare_combined_early_lint_pass {
             fn name(&self) -> &'static str {
                 panic!()
             }
-
-            fn get_lints(&self) -> LintArray {
-                let mut lints = Vec::new();
-                $(lints.extend_from_slice(&self.$passes.get_lints());)*
-                lints
-            }
         }
     )
 }
@@ -649,9 +672,8 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
     };
 
     // Check for future incompatibility lints and issue a stronger warning.
-    let lints = sess.lint_store.borrow();
     let lint_id = LintId::of(lint);
-    let future_incompatible = lints.future_incompatible(lint_id);
+    let future_incompatible = lint.future_incompatible;
 
     // If this code originates in a foreign macro, aka something that this crate
     // did not itself author, then it's likely that there's nothing this crate
@@ -755,13 +777,15 @@ pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 
 fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
     assert_eq!(cnum, LOCAL_CRATE);
+    let store = &tcx.lint_store;
     let mut builder = LintLevelMapBuilder {
-        levels: LintLevelSets::builder(tcx.sess),
+        levels: LintLevelSets::builder(tcx.sess, &store),
         tcx: tcx,
+        store: store,
     };
     let krate = tcx.hir().krate();
 
-    let push = builder.levels.push(&krate.attrs);
+    let push = builder.levels.push(&krate.attrs, &store);
     builder.levels.register_id(hir::CRATE_HIR_ID);
     for macro_def in &krate.exported_macros {
        builder.levels.register_id(macro_def.hir_id);
@@ -772,19 +796,20 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
     tcx.arena.alloc(builder.levels.build_map())
 }
 
-struct LintLevelMapBuilder<'tcx> {
+struct LintLevelMapBuilder<'a, 'tcx> {
     levels: levels::LintLevelsBuilder<'tcx>,
     tcx: TyCtxt<'tcx>,
+    store: &'a LintStore,
 }
 
-impl LintLevelMapBuilder<'tcx> {
+impl LintLevelMapBuilder<'_, '_> {
     fn with_lint_attrs<F>(&mut self,
                           id: hir::HirId,
                           attrs: &[ast::Attribute],
                           f: F)
         where F: FnOnce(&mut Self)
     {
-        let push = self.levels.push(attrs);
+        let push = self.levels.push(attrs, self.store);
         if push.changed {
             self.levels.register_id(id);
         }
@@ -793,7 +818,7 @@ impl LintLevelMapBuilder<'tcx> {
     }
 }
 
-impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
+impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
         intravisit::NestedVisitorMap::All(&self.tcx.hir())
     }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 2170a288c92..ec1e32988a6 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -117,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,
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/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/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 b0830fb72eb..08e7001681c 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: Symbol,
@@ -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 9be741a1656..58f99667cb3 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 fef406e8987..427540d7275 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -947,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/session/config.rs b/src/librustc/session/config.rs
index 675e3bbd002..33b9ddaa622 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -7,24 +7,19 @@ 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::new_parser_from_source_str;
-use syntax::parse::token;
-use syntax::sess::ParseSess;
 use syntax::symbol::{sym, Symbol};
 use syntax::feature_gate::UnstableFeatures;
-use syntax::source_map::SourceMap;
 
 use errors::emitter::HumanReadableErrorType;
-use errors::{ColorConfig, FatalError, Handler, SourceMapperDyn};
+use errors::{ColorConfig, FatalError, Handler};
 
 use getopts;
 
@@ -67,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,
@@ -301,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
@@ -464,7 +459,7 @@ pub enum PrintRequest {
     NativeStaticLibs,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone)]
 pub enum BorrowckMode {
     Mir,
     Migrate,
@@ -1154,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],
@@ -1854,59 +1850,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
     opts
 }
 
-struct NullEmitter;
-
-impl errors::emitter::Emitter for NullEmitter {
-    fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {}
-    fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> { None }
-}
-
-// 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>) {
@@ -2877,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 b65bf2230b3..bd2460cfab1 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -14,7 +14,7 @@ use crate::util::common::{duration_to_secs_str, ErrorReported};
 
 use rustc_data_structures::base_n;
 use rustc_data_structures::sync::{
-    self, Lrc, Lock, OneThread, Once, RwLock, AtomicU64, AtomicUsize, Ordering,
+    self, Lrc, Lock, OneThread, Once, AtomicU64, AtomicUsize, Ordering,
     Ordering::SeqCst,
 };
 
@@ -77,9 +77,11 @@ pub struct Session {
     /// if the value stored here has been affected by path remapping.
     pub working_dir: (PathBuf, bool),
 
-    // FIXME: `lint_store` and `buffered_lints` are not thread-safe,
-    // but are only used in a single thread.
-    pub lint_store: RwLock<lint::LintStore>,
+    /// This is intended to be used from a single thread.
+    ///
+    /// FIXME: there was a previous comment about this not being thread safe,
+    /// but it's not clear how or why that's the case. The LintBuffer itself is certainly thread
+    /// safe at least from a "Rust safety" standpoint.
     pub buffered_lints: Lock<Option<lint::LintBuffer>>,
 
     /// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking
@@ -1213,7 +1215,6 @@ fn build_session_(
         sysroot,
         local_crate_source_file,
         working_dir,
-        lint_store: RwLock::new(lint::LintStore::new()),
         buffered_lints: Lock::new(Some(Default::default())),
         one_time_diagnostics: Default::default(),
         plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())),
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 ae604b9eb13..e684cdc0a38 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -793,15 +793,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
                     ty::Predicate::ObjectSafe(trait_def_id) => {
                         let violations = self.tcx.object_safety_violations(trait_def_id);
-                        if let Some(err) = self.tcx.report_object_safety_error(
+                        self.tcx.report_object_safety_error(
                             span,
                             trait_def_id,
                             violations,
-                        ) {
-                            err
-                        } else {
-                            return;
-                        }
+                        )
                     }
 
                     ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
@@ -937,11 +933,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
             TraitNotObjectSafe(did) => {
                 let violations = self.tcx.object_safety_violations(did);
-                if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) {
-                    err
-                } else {
-                    return;
-                }
+                self.tcx.report_object_safety_error(span, did, violations)
             }
 
             // already reported in the query
@@ -1665,11 +1657,7 @@ impl<'tcx> TyCtxt<'tcx> {
         span: Span,
         trait_def_id: DefId,
         violations: Vec<ObjectSafetyViolation>,
-    ) -> Option<DiagnosticBuilder<'tcx>> {
-        if self.sess.trait_methods_not_found.borrow().contains(&span) {
-            // Avoid emitting error caused by non-existing method (#58734)
-            return None;
-        }
+    ) -> DiagnosticBuilder<'tcx> {
         let trait_str = self.def_path_str(trait_def_id);
         let span = self.sess.source_map().def_span(span);
         let mut err = struct_span_err!(
@@ -1687,7 +1675,13 @@ impl<'tcx> TyCtxt<'tcx> {
                 };
             }
         }
-        Some(err)
+
+        if self.sess.trait_methods_not_found.borrow().contains(&span) {
+            // Avoid emitting error caused by non-existing method (#58734)
+            err.cancel();
+        }
+
+        err
     }
 }
 
@@ -2098,6 +2092,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 err.note(&format!("required for the cast to the object type `{}`",
                                   self.ty_to_string(object_ty)));
             }
+            ObligationCauseCode::Coercion { source: _, target } => {
+                err.note(&format!("required by cast to type `{}`",
+                                  self.ty_to_string(target)));
+            }
             ObligationCauseCode::RepeatVec => {
                 err.note("the `Copy` trait is required because the \
                           repeated element will be copied");
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index d96330bf0a9..eb4b114eb30 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -188,6 +188,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// Obligation incurred due to an object cast.
     ObjectCastObligation(/* Object type */ Ty<'tcx>),
 
+    /// Obligation incurred due to a coercion.
+    Coercion { source: Ty<'tcx>, target: Ty<'tcx> },
+
     // Various cases where expressions must be sized/copy/etc:
     /// L = X implies that L is Sized
     AssignmentLhsSized,
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/select.rs b/src/librustc/traits/select.rs
index 44d611ace77..d8a27f1e040 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -2246,7 +2246,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     if let Some(principal) = data.principal() {
-                        principal.with_self_ty(self.tcx(), self_ty)
+                        if !self.infcx.tcx.features().object_safe_for_dispatch {
+                            principal.with_self_ty(self.tcx(), self_ty)
+                        } else if self.tcx().is_object_safe(principal.def_id()) {
+                            principal.with_self_ty(self.tcx(), self_ty)
+                        } else {
+                            return;
+                        }
                     } else {
                         // Only auto-trait bounds exist.
                         return;
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 2a53dcab8a9..18db3c8d10b 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -481,6 +481,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
                    .and_then(|r| Some(super::ObjectTypeBound(ty, r)))
             ),
             super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
+            super::Coercion { source, target } => Some(super::Coercion {
+                source: tcx.lift(&source)?,
+                target: tcx.lift(&target)?,
+            }),
             super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
             super::TupleInitializerSized => Some(super::TupleInitializerSized),
             super::StructInitializerSized => Some(super::StructInitializerSized),
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/context.rs b/src/librustc/ty/context.rs
index d34e8d68720..d5a93e02905 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -827,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,
@@ -882,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
@@ -899,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>),
 
@@ -1031,6 +1031,8 @@ pub struct GlobalCtxt<'tcx> {
 
     pub sess: &'tcx Session,
 
+    pub lint_store: Lrc<lint::LintStore>,
+
     pub dep_graph: DepGraph,
 
     pub prof: SelfProfilerRef,
@@ -1192,6 +1194,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// reference to the context, to allow formatting values that need it.
     pub fn create_global_ctxt(
         s: &'tcx Session,
+        lint_store: Lrc<lint::LintStore>,
         cstore: &'tcx CrateStoreDyn,
         local_providers: ty::query::Providers<'tcx>,
         extern_providers: ty::query::Providers<'tcx>,
@@ -1255,6 +1258,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         GlobalCtxt {
             sess: s,
+            lint_store,
             cstore,
             arena: WorkerLocal::new(|_| Arena::default()),
             interners,
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 5851a48a8d3..77613b548cf 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -45,13 +45,12 @@ pub enum TypeError<'tcx> {
     ProjectionMismatched(ExpectedFound<DefId>),
     ProjectionBoundsLength(ExpectedFound<usize>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
-
+    ObjectUnsafeCoercion(DefId),
     ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
 
     IntrinsicCast,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
 pub enum UnconstrainedNumeric {
     UnconstrainedFloat,
     UnconstrainedInt,
@@ -179,6 +178,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
             IntrinsicCast => {
                 write!(f, "cannot coerce intrinsics to function pointers")
             }
+            ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
         }
     }
 }
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/mod.rs b/src/librustc/ty/mod.rs
index f72a221fe39..feede00fea1 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -159,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>,
@@ -195,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,
@@ -331,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
@@ -752,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,
diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs
index 0c48ae97178..0a217e9ae66 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::Symbol;
 
 /// 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 Symbol {
 
 /// 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/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 83ec98f9ddd..5d78d563e9a 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -749,6 +749,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
             ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
             IntrinsicCast => IntrinsicCast,
+            ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
         })
     }
 }
@@ -1350,6 +1351,7 @@ EnumTypeFoldableImpl! {
         (ty::error::TypeError::ExistentialMismatch)(x),
         (ty::error::TypeError::ConstMismatch)(x),
         (ty::error::TypeError::IntrinsicCast),
+        (ty::error::TypeError::ObjectUnsafeCoercion)(x),
     }
 }
 
@@ -1379,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 f4de0cd7b6b..3a9994ac64c 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 e1eab2c6579..5555dace45b 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -818,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
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index ecb075e30b1..b50e819c956 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -380,16 +380,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // obligations that don't refer to Self and
                     // checking those
 
-                    let cause = self.cause(traits::MiscObligation);
-                    let component_traits =
-                        data.auto_traits().chain(data.principal_def_id());
-                    self.out.extend(
-                        component_traits.map(|did| traits::Obligation::new(
-                            cause.clone(),
-                            param_env,
-                            ty::Predicate::ObjectSafe(did)
-                        ))
-                    );
+                    let defer_to_coercion =
+                        self.infcx.tcx.features().object_safe_for_dispatch;
+
+                    if !defer_to_coercion {
+                        let cause = self.cause(traits::MiscObligation);
+                        let component_traits =
+                            data.auto_traits().chain(data.principal_def_id());
+                        self.out.extend(
+                            component_traits.map(|did| traits::Obligation::new(
+                                cause.clone(),
+                                param_env,
+                                ty::Predicate::ObjectSafe(did)
+                            ))
+                        );
+                    }
                 }
 
                 // Inference variables are the complicated case, since we don't
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/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/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index d0bfbe05148..f0148a21ae6 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/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index a2313b933a6..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,
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 8bc815f2c62..762b50f1659 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -259,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());
@@ -674,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",
         }
     }
 }
@@ -1587,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()
         };
     });
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index 516fd5049f2..bf687f84635 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -406,6 +406,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
         rust_main_def_id: DefId,
         use_start_lang_item: bool,
     ) {
+        // 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 {
@@ -440,19 +442,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
 
         bx.insert_reference_to_gdb_debug_scripts_section_global();
 
-        let (arg_argc, arg_argv) = 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)
-        };
+        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);
@@ -477,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/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/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 27442bb6bff..7e662ea37db 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -556,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)
@@ -594,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_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs
index 29a8a98d229..444463c08e5 100644
--- a/src/librustc_data_structures/graph/dominators/mod.rs
+++ b/src/librustc_data_structures/graph/dominators/mod.rs
@@ -17,7 +17,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
     dominators_given_rpo(graph, &rpo)
 }
 
-pub fn dominators_given_rpo<G: ControlFlowGraph>(
+fn dominators_given_rpo<G: ControlFlowGraph>(
     graph: &G,
     rpo: &[G::Node],
 ) -> Dominators<G::Node> {
@@ -43,14 +43,12 @@ pub fn dominators_given_rpo<G: ControlFlowGraph>(
             let mut new_idom = None;
             for pred in graph.predecessors(node) {
                 if immediate_dominators[pred].is_some() {
-                    // (*)
                     // (*) dominators for `pred` have been calculated
-                    new_idom = intersect_opt(
-                        &post_order_rank,
-                        &immediate_dominators,
-                        new_idom,
-                        Some(pred),
-                    );
+                    new_idom = Some(if let Some(new_idom) = new_idom {
+                        intersect(&post_order_rank, &immediate_dominators, new_idom, pred)
+                    } else {
+                        pred
+                    });
                 }
             }
 
@@ -67,19 +65,6 @@ pub fn dominators_given_rpo<G: ControlFlowGraph>(
     }
 }
 
-fn intersect_opt<Node: Idx>(
-    post_order_rank: &IndexVec<Node, usize>,
-    immediate_dominators: &IndexVec<Node, Option<Node>>,
-    node1: Option<Node>,
-    node2: Option<Node>,
-) -> Option<Node> {
-    match (node1, node2) {
-        (None, None) => None,
-        (Some(n), None) | (None, Some(n)) => Some(n),
-        (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)),
-    }
-}
-
 fn intersect<Node: Idx>(
     post_order_rank: &IndexVec<Node, usize>,
     immediate_dominators: &IndexVec<Node, Option<Node>>,
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 d0ff6108d6e..2f972eeccdc 100644
--- a/src/librustc_data_structures/sharded.rs
+++ b/src/librustc_data_structures/sharded.rs
@@ -90,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 9622c290039..f09474ff4d3 100644
--- a/src/librustc_data_structures/sync.rs
+++ b/src/librustc_data_structures/sync.rs
@@ -738,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/Cargo.toml b/src/librustc_driver/Cargo.toml
index aa74966d0ab..a9e4e6db1c7 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -16,6 +16,7 @@ log = "0.4"
 env_logger = { version = "0.7", default-features = false }
 rustc = { path = "../librustc" }
 rustc_target = { path = "../librustc_target" }
+rustc_lint = { path = "../librustc_lint" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 errors = { path = "../librustc_errors", package = "rustc_errors" }
 rustc_metadata = { path = "../librustc_metadata" }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f33cb4e215d..5d9dec14c6c 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -106,6 +106,8 @@ pub fn abort_on_err<T>(result: Result<T, ErrorReported>, sess: &Session) -> T {
 pub trait Callbacks {
     /// Called before creating the compiler instance
     fn config(&mut self, _config: &mut interface::Config) {}
+    /// Called early during compilation to allow other drivers to easily register lints.
+    fn extra_lints(&mut self, _ls: &mut lint::LintStore) {}
     /// Called after parsing. Return value instructs the compiler whether to
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_parsing(&mut self, _compiler: &interface::Compiler) -> Compilation {
@@ -167,7 +169,7 @@ pub fn run_compiler(
     };
 
     let sopts = config::build_session_options(&matches);
-    let cfg = config::parse_cfgspecs(matches.opt_strs("cfg"));
+    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
 
     let mut dummy_config = |sopts, cfg, diagnostic_output| {
         let mut config = interface::Config {
@@ -182,6 +184,7 @@ pub fn run_compiler(
             stderr: None,
             crate_name: None,
             lint_caps: Default::default(),
+            register_lints: None,
         };
         callbacks.config(&mut config);
         config
@@ -202,9 +205,13 @@ pub fn run_compiler(
                     interface::run_compiler(config, |compiler| {
                         let sopts = &compiler.session().opts;
                         if sopts.describe_lints {
+                            let lint_store = rustc_lint::new_lint_store(
+                                sopts.debugging_opts.no_interleave_lints,
+                                compiler.session().unstable_options(),
+                            );
                             describe_lints(
                                 compiler.session(),
-                                &*compiler.session().lint_store.borrow(),
+                                &lint_store,
                                 false
                             );
                             return;
@@ -255,6 +262,7 @@ pub fn run_compiler(
         stderr: None,
         crate_name: None,
         lint_caps: Default::default(),
+        register_lints: None,
     };
 
     callbacks.config(&mut config);
@@ -321,12 +329,14 @@ pub fn run_compiler(
             return sess.compile_status();
         }
 
-        compiler.register_plugins()?;
+        {
+            let (_, _, lint_store) = &*compiler.register_plugins()?.peek();
 
-        // Lint plugins are registered; now we can process command line flags.
-        if sess.opts.describe_lints {
-            describe_lints(&sess, &sess.lint_store.borrow(), true);
-            return sess.compile_status();
+            // Lint plugins are registered; now we can process command line flags.
+            if sess.opts.describe_lints {
+                describe_lints(&sess, &lint_store, true);
+                return sess.compile_status();
+            }
         }
 
         compiler.expansion()?;
@@ -835,8 +845,7 @@ Available lint options:
 
 ");
 
-    fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
-        let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
+    fn sort_lints(sess: &Session, mut lints: Vec<&'static Lint>) -> Vec<&'static Lint> {
         // The sort doesn't case-fold but it's doubtful we care.
         lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess), x.name));
         lints
@@ -852,7 +861,7 @@ Available lint options:
     let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints()
                                                    .iter()
                                                    .cloned()
-                                                   .partition(|&(_, p)| p);
+                                                   .partition(|&lint| lint.is_plugin);
     let plugin = sort_lints(sess, plugin);
     let builtin = sort_lints(sess, builtin);
 
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index fd74d8673da..1781f2e1650 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -152,6 +152,32 @@ impl Diagnostic {
         self.note_expected_found_extra(label, expected, found, &"", &"")
     }
 
+    pub fn note_unsuccessfull_coercion(&mut self,
+                                       expected: DiagnosticStyledString,
+                                       found: DiagnosticStyledString)
+                                       -> &mut Self
+    {
+        let mut msg: Vec<_> =
+            vec![(format!("required when trying to coerce from type `"),
+                  Style::NoStyle)];
+        msg.extend(expected.0.iter()
+                   .map(|x| match *x {
+                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
+                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+                   }));
+        msg.push((format!("` to type '"), Style::NoStyle));
+        msg.extend(found.0.iter()
+                   .map(|x| match *x {
+                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
+                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+                   }));
+        msg.push((format!("`"), Style::NoStyle));
+
+        // For now, just attach these as notes
+        self.highlighted_note(msg);
+        self
+    }
+
     pub fn note_expected_found_extra(&mut self,
                                      label: &dyn fmt::Display,
                                      expected: DiagnosticStyledString,
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index cc60bf89c7e..40642dd14b8 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -209,6 +209,11 @@ impl<'a> DiagnosticBuilder<'a> {
                                               found_extra: &dyn fmt::Display,
                                               ) -> &mut Self);
 
+    forward!(pub fn note_unsuccessfull_coercion(&mut self,
+                                                expected: DiagnosticStyledString,
+                                                found: DiagnosticStyledString,
+                                                ) -> &mut Self);
+
     forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
     forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                                   sp: S,
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 1e486786f68..e3b55a14133 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -12,7 +12,7 @@ use Destination::*;
 use syntax_pos::{SourceFile, Span, MultiSpan};
 
 use crate::{
-    Level, CodeSuggestion, Diagnostic, SubDiagnostic,
+    Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralise,
     SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId,
 };
 use crate::Level::Error;
@@ -1572,7 +1572,8 @@ impl EmitterWriter {
             }
         }
         if suggestions.len() > MAX_SUGGESTIONS {
-            let msg = format!("and {} other candidates", suggestions.len() - MAX_SUGGESTIONS);
+            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";
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 7a0d931ca73..0d8d765a572 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -27,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..24ea0fc8bf6 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>;
 
@@ -34,6 +39,7 @@ pub struct Compiler {
     pub(crate) queries: Queries,
     pub(crate) cstore: Lrc<CStore>,
     pub(crate) crate_name: Option<String>,
+    pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
 }
 
 impl Compiler {
@@ -60,6 +66,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
@@ -80,6 +138,13 @@ pub struct Config {
 
     pub crate_name: Option<String>,
     pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
+
+    /// This is a callback from the driver that is called when we're registering lints;
+    /// it is called during plugin registration when we have the LintStore in a non-shared state.
+    ///
+    /// Note that if you find a Some here you probably want to call that function in the new
+    /// function being registered.
+    pub register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
 }
 
 pub fn run_compiler_in_existing_thread_pool<F, R>(config: Config, f: F) -> R
@@ -108,6 +173,7 @@ where
         output_file: config.output_file,
         queries: Default::default(),
         crate_name: config.crate_name,
+        register_lints: config.register_lints,
     };
 
     let _sess_abort_error = OnDrop(|| {
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 89de5714695..2044b73db8a 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -117,6 +117,7 @@ declare_box_region_type!(
 /// Returns `None` if we're aborting after handling -W help.
 pub fn configure_and_expand(
     sess: Lrc<Session>,
+    lint_store: Lrc<lint::LintStore>,
     cstore: Lrc<CStore>,
     krate: ast::Crate,
     crate_name: &str,
@@ -134,6 +135,7 @@ pub fn configure_and_expand(
         let resolver_arenas = Resolver::arenas();
         let res = configure_and_expand_inner(
             sess,
+            &lint_store,
             &*cstore,
             krate,
             &crate_name,
@@ -225,9 +227,10 @@ pub struct PluginInfo {
 pub fn register_plugins<'a>(
     sess: &'a Session,
     cstore: &'a CStore,
+    register_lints: impl Fn(&Session, &mut lint::LintStore),
     mut krate: ast::Crate,
     crate_name: &str,
-) -> Result<(ast::Crate, PluginInfo)> {
+) -> Result<(ast::Crate, PluginInfo, Lrc<lint::LintStore>)> {
     krate = time(sess, "attributes injection", || {
         syntax_ext::cmdline_attrs::inject(
             krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr
@@ -278,7 +281,14 @@ pub fn register_plugins<'a>(
         )
     });
 
-    let mut registry = Registry::new(sess, krate.span);
+    let mut lint_store = rustc_lint::new_lint_store(
+        sess.opts.debugging_opts.no_interleave_lints,
+        sess.unstable_options(),
+    );
+
+    (register_lints)(&sess, &mut lint_store);
+
+    let mut registry = Registry::new(sess, &mut lint_store, krate.span);
 
     time(sess, "plugin registration", || {
         for registrar in registrars {
@@ -289,34 +299,20 @@ pub fn register_plugins<'a>(
 
     let Registry {
         syntax_exts,
-        early_lint_passes,
-        late_lint_passes,
-        lint_groups,
         llvm_passes,
         attributes,
         ..
     } = registry;
 
-    let mut ls = sess.lint_store.borrow_mut();
-    for pass in early_lint_passes {
-        ls.register_early_pass(Some(sess), true, false, pass);
-    }
-    for pass in late_lint_passes {
-        ls.register_late_pass(Some(sess), true, false, false, pass);
-    }
-
-    for (name, (to, deprecated_name)) in lint_groups {
-        ls.register_group(Some(sess), true, name, deprecated_name, to);
-    }
-
     *sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
     *sess.plugin_attributes.borrow_mut() = attributes;
 
-    Ok((krate, PluginInfo { syntax_exts }))
+    Ok((krate, PluginInfo { syntax_exts }, Lrc::new(lint_store)))
 }
 
 fn configure_and_expand_inner<'a>(
     sess: &'a Session,
+    lint_store: &'a lint::LintStore,
     cstore: &'a CStore,
     mut krate: ast::Crate,
     crate_name: &str,
@@ -327,6 +323,7 @@ fn configure_and_expand_inner<'a>(
     time(sess, "pre-AST-expansion lint checks", || {
         lint::check_ast_crate(
             sess,
+            lint_store,
             &krate,
             true,
             rustc_lint::BuiltinCombinedPreExpansionLintPass::new());
@@ -536,6 +533,7 @@ fn configure_and_expand_inner<'a>(
 
 pub fn lower_to_hir(
     sess: &Session,
+    lint_store: &lint::LintStore,
     cstore: &CStore,
     resolver: &mut Resolver<'_>,
     dep_graph: &DepGraph,
@@ -554,7 +552,13 @@ pub fn lower_to_hir(
     });
 
     time(sess, "early lint checks", || {
-        lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new())
+        lint::check_ast_crate(
+            sess,
+            lint_store,
+            &krate,
+            false,
+            rustc_lint::BuiltinCombinedEarlyLintPass::new(),
+        )
     });
 
     // Discard hygiene data, which isn't required after lowering to HIR.
@@ -817,6 +821,7 @@ impl BoxedGlobalCtxt {
 
 pub fn create_global_ctxt(
     compiler: &Compiler,
+    lint_store: Lrc<lint::LintStore>,
     mut hir_forest: hir::map::Forest,
     defs: hir::map::Definitions,
     resolutions: Resolutions,
@@ -854,6 +859,7 @@ pub fn create_global_ctxt(
 
         let gcx = TyCtxt::create_global_ctxt(
             sess,
+            lint_store,
             cstore,
             local_providers,
             extern_providers,
diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs
index cd72dc9453c..84648ca8326 100644
--- a/src/librustc_interface/queries.rs
+++ b/src/librustc_interface/queries.rs
@@ -2,9 +2,13 @@ use crate::interface::{Compiler, Result};
 use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
 
 use rustc_incremental::DepGraphFuture;
+use rustc_data_structures::sync::Lrc;
 use rustc::session::config::{OutputFilenames, OutputType};
 use rustc::util::common::{time, ErrorReported};
 use rustc::hir;
+use rustc::lint;
+use rustc::session::Session;
+use rustc::lint::LintStore;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc::ty::steal::Steal;
 use rustc::dep_graph::DepGraph;
@@ -74,8 +78,8 @@ pub(crate) struct Queries {
     dep_graph_future: Query<Option<DepGraphFuture>>,
     parse: Query<ast::Crate>,
     crate_name: Query<String>,
-    register_plugins: Query<(ast::Crate, PluginInfo)>,
-    expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>)>,
+    register_plugins: Query<(ast::Crate, PluginInfo, Lrc<LintStore>)>,
+    expansion: Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
     lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
     prepare_outputs: Query<OutputFilenames>,
@@ -106,14 +110,19 @@ impl Compiler {
         })
     }
 
-    pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> {
+    pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo, Lrc<LintStore>)>> {
         self.queries.register_plugins.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let krate = self.parse()?.take();
 
+            let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {};
             let result = passes::register_plugins(
                 self.session(),
                 self.cstore(),
+                self.register_lints
+                    .as_ref()
+                    .map(|p| &**p)
+                    .unwrap_or_else(|| empty),
                 krate,
                 &crate_name,
             );
@@ -148,17 +157,20 @@ impl Compiler {
 
     pub fn expansion(
         &self
-    ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>)>> {
+    ) -> Result<&Query<(ast::Crate, Steal<Rc<RefCell<BoxedResolver>>>, Lrc<LintStore>)>> {
         self.queries.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
-            let (krate, plugin_info) = self.register_plugins()?.take();
+            let (krate, plugin_info, lint_store) = self.register_plugins()?.take();
             passes::configure_and_expand(
                 self.sess.clone(),
+                lint_store.clone(),
                 self.cstore().clone(),
                 krate,
                 &crate_name,
                 plugin_info,
-            ).map(|(krate, resolver)| (krate, Steal::new(Rc::new(RefCell::new(resolver)))))
+            ).map(|(krate, resolver)| {
+                (krate, Steal::new(Rc::new(RefCell::new(resolver))), lint_store)
+            })
         })
     }
 
@@ -185,9 +197,11 @@ impl Compiler {
             let peeked = expansion_result.peek();
             let krate = &peeked.0;
             let resolver = peeked.1.steal();
+            let lint_store = &peeked.2;
             let hir = Steal::new(resolver.borrow_mut().access(|resolver| {
                 passes::lower_to_hir(
                     self.session(),
+                    lint_store,
                     self.cstore(),
                     resolver,
                     &*self.dep_graph()?.peek(),
@@ -212,11 +226,13 @@ impl Compiler {
         self.queries.global_ctxt.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
             let outputs = self.prepare_outputs()?.peek().clone();
+            let lint_store = self.expansion()?.peek().2.clone();
             let hir = self.lower_to_hir()?;
             let hir = hir.peek();
             let (ref hir_forest, ref expansion) = *hir;
             Ok(passes::create_global_ctxt(
                 self,
+                lint_store,
                 hir_forest.steal(),
                 expansion.defs.steal(),
                 expansion.resolutions.steal(),
diff --git a/src/librustc/session/config/tests.rs b/src/librustc_interface/tests.rs
index 061bbdc307f..7a57605da58 100644
--- a/src/librustc/session/config/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -1,25 +1,24 @@
-use getopts;
-use crate::lint;
-use crate::middle::cstore;
-use crate::session::config::{
-    build_configuration,
-    build_session_options,
-    to_crate_config,
-    parse_cfgspecs,
-};
-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;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{ColorConfig, emitter::HumanReadableErrorType, registry};
 
 pub fn build_session_options_and_crate_config(
     matches: &getopts::Matches,
@@ -30,22 +29,23 @@ pub fn build_session_options_and_crate_config(
     )
 }
 
-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
-        }
+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;
@@ -63,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));
@@ -81,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));
@@ -95,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());
@@ -105,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());
@@ -113,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());
@@ -172,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")])
         ),
     ]));
 
@@ -282,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
@@ -455,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_interface/util.rs b/src/librustc_interface/util.rs
index 0c272f0c456..8f11dc93727 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -13,7 +13,6 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use rustc_errors::registry::Registry;
-use rustc_lint;
 use rustc_metadata::dynamic_lib::DynamicLibrary;
 use rustc_mir;
 use rustc_passes;
@@ -108,11 +107,6 @@ pub fn create_session(
 
     let codegen_backend = get_codegen_backend(&sess);
 
-    rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-    if sess.unstable_options() {
-        rustc_lint::register_internals(&mut sess.lint_store.borrow_mut(), Some(&sess));
-    }
-
     let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg));
     add_configuration(&mut cfg, &sess, &*codegen_backend);
     sess.parse_sess.config = cfg;
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 08f6f43ab0c..ad674911e6f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -27,6 +27,7 @@ use rustc::hir::def::{Res, DefKind};
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx};
 use rustc::{lint, util};
+use rustc::lint::FutureIncompatibleInfo;
 use hir::Node;
 use util::nodemap::HirIdSet;
 use lint::{LateContext, LintContext, LintArray};
@@ -280,7 +281,7 @@ declare_lint! {
     pub MISSING_DOCS,
     Allow,
     "detects missing documentation for public members",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 pub struct MissingDoc {
@@ -601,7 +602,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
 declare_lint! {
     pub ANONYMOUS_PARAMETERS,
     Allow,
-    "detects anonymous parameters"
+    "detects anonymous parameters",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
+        edition: Some(Edition::Edition2018),
+    };
 }
 
 declare_lint_pass!(
@@ -981,35 +986,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"
@@ -1288,7 +1264,6 @@ declare_lint_pass!(
         NO_MANGLE_GENERIC_ITEMS,
         MUTABLE_TRANSMUTES,
         UNSTABLE_FEATURES,
-        UNIONS_WITH_DROP_FIELDS,
         UNREACHABLE_PUB,
         TYPE_ALIAS_BOUNDS,
         TRIVIAL_BOUNDS
@@ -1374,7 +1349,7 @@ declare_lint! {
     UNNAMEABLE_TEST_ITEMS,
     Warn,
     "detects an item that cannot be named being marked as `#[test_case]`",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 pub struct UnnameableTestItems {
@@ -1423,7 +1398,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems {
 declare_lint! {
     pub KEYWORD_IDENTS,
     Allow,
-    "detects edition keywords being used as an identifier"
+    "detects edition keywords being used as an identifier",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
+        edition: Some(Edition::Edition2018),
+    };
 }
 
 declare_lint_pass!(
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index e3860e229d6..b1beef04c59 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -33,27 +33,21 @@ use rustc::lint;
 use rustc::lint::{EarlyContext, LateContext, LateLintPass, EarlyLintPass, LintPass, LintArray};
 use rustc::lint::builtin::{
     BARE_TRAIT_OBJECTS,
-    ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
     ELIDED_LIFETIMES_IN_PATHS,
     EXPLICIT_OUTLIVES_REQUIREMENTS,
     INTRA_DOC_LINK_RESOLUTION_FAILURE,
     MISSING_DOC_CODE_EXAMPLES,
     PRIVATE_DOC_TESTS,
-    parser::ILL_FORMED_ATTRIBUTE_INPUT,
 };
-use rustc::session;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
 
 use syntax::ast;
-use syntax::edition::Edition;
 use syntax_pos::Span;
 
-use session::Session;
 use lint::LintId;
-use lint::FutureIncompatibleInfo;
 
 use redundant_semicolon::*;
 use nonstandard_style::*;
@@ -164,9 +158,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,
@@ -195,59 +186,60 @@ late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass])
 
 late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
 
+pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore {
+    let mut lint_store = lint::LintStore::new();
+
+    register_builtins(&mut lint_store, no_interleave_lints);
+    if internal_lints {
+        register_internals(&mut lint_store);
+    }
+
+    lint_store
+}
+
 /// Tell the `LintStore` about all the built-in lints (the ones
 /// defined in this crate and the ones defined in
 /// `rustc::lint::builtin`).
-pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
+fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
     macro_rules! add_lint_group {
-        ($sess:ident, $name:expr, $($lint:ident),*) => (
-            store.register_group($sess, false, $name, None, vec![$(LintId::of($lint)),*]);
+        ($name:expr, $($lint:ident),*) => (
+            store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
         )
     }
 
     macro_rules! register_pass {
-        ($method:ident, $constructor:expr, [$($args:expr),*]) => (
-            store.$method(sess, false, false, $($args,)* box $constructor);
+        ($method:ident, $ty:ident, $constructor:expr) => (
+            store.register_lints(&$ty::get_lints());
+            store.$method(|| box $constructor);
         )
     }
 
     macro_rules! register_passes {
-        ([$method:ident, $args:tt], [$($passes:ident: $constructor:expr,)*]) => (
+        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
             $(
-                register_pass!($method, $constructor, $args);
+                register_pass!($method, $passes, $constructor);
             )*
         )
     }
 
-    if sess.map(|sess| sess.opts.debugging_opts.no_interleave_lints).unwrap_or(false) {
-        pre_expansion_lint_passes!(register_passes, [register_pre_expansion_pass, []]);
-        early_lint_passes!(register_passes, [register_early_pass, []]);
-        late_lint_passes!(register_passes, [register_late_pass, [false]]);
-        late_lint_mod_passes!(register_passes, [register_late_pass, [true]]);
+    if no_interleave_lints {
+        pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass);
+        early_lint_passes!(register_passes, register_early_pass);
+        late_lint_passes!(register_passes, register_late_pass);
+        late_lint_mod_passes!(register_passes, register_late_mod_pass);
     } else {
-        store.register_pre_expansion_pass(
-            sess,
-            false,
-            true,
-            box BuiltinCombinedPreExpansionLintPass::new()
-        );
-        store.register_early_pass(sess, false, true, box BuiltinCombinedEarlyLintPass::new());
-        store.register_late_pass(
-            sess, false, true, true, box BuiltinCombinedModuleLateLintPass::new()
-        );
-        store.register_late_pass(
-            sess, false, true, false, box BuiltinCombinedLateLintPass::new()
-        );
+        store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
+        store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
+        store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
+        store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
     }
 
-    add_lint_group!(sess,
-                    "nonstandard_style",
+    add_lint_group!("nonstandard_style",
                     NON_CAMEL_CASE_TYPES,
                     NON_SNAKE_CASE,
                     NON_UPPER_CASE_GLOBALS);
 
-    add_lint_group!(sess,
-                    "unused",
+    add_lint_group!("unused",
                     UNUSED_IMPORTS,
                     UNUSED_VARIABLES,
                     UNUSED_ASSIGNMENTS,
@@ -268,8 +260,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                     UNUSED_LABELS,
                     UNUSED_PARENS);
 
-    add_lint_group!(sess,
-                    "rust_2018_idioms",
+    add_lint_group!("rust_2018_idioms",
                     BARE_TRAIT_OBJECTS,
                     UNUSED_EXTERN_CRATES,
                     ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
@@ -285,165 +276,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                     // MACRO_USE_EXTERN_CRATE,
                     );
 
-    add_lint_group!(sess,
-                    "rustdoc",
+    add_lint_group!("rustdoc",
                     INTRA_DOC_LINK_RESOLUTION_FAILURE,
                     MISSING_DOC_CODE_EXAMPLES,
                     PRIVATE_DOC_TESTS);
 
-    // Guidelines for creating a future incompatibility lint:
-    //
-    // - Create a lint defaulting to warn as normal, with ideally the same error
-    //   message you would normally give
-    // - Add a suitable reference, typically an RFC or tracking issue. Go ahead
-    //   and include the full URL, sort items in ascending order of issue numbers.
-    // - Later, change lint to error
-    // - Eventually, remove lint
-    store.register_future_incompatible(sess, vec![
-        FutureIncompatibleInfo {
-            id: LintId::of(PRIVATE_IN_PUBLIC),
-            reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE),
-            reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
-            reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(DUPLICATE_MACRO_EXPORTS),
-            reference: "issue #35896 <https://github.com/rust-lang/rust/issues/35896>",
-            edition: Some(Edition::Edition2018),
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(KEYWORD_IDENTS),
-            reference: "issue #49716 <https://github.com/rust-lang/rust/issues/49716>",
-            edition: Some(Edition::Edition2018),
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(SAFE_EXTERN_STATICS),
-            reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
-            reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
-            reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
-            reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
-            reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
-            reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(ANONYMOUS_PARAMETERS),
-            reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
-            edition: Some(Edition::Edition2018),
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
-            reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
-            reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(SAFE_PACKED_BORROWS),
-            reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(ORDER_DEPENDENT_TRAIT_OBJECTS),
-            reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
-            reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
-            edition: Some(Edition::Edition2018),
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(UNSTABLE_NAME_COLLISIONS),
-            reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>",
-            edition: None,
-            // Note: this item represents future incompatibility of all unstable functions in the
-            //       standard library, and thus should never be removed or changed to an error.
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE),
-            reference: "issue #53130 <https://github.com/rust-lang/rust/issues/53130>",
-            edition: Some(Edition::Edition2018),
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(WHERE_CLAUSES_OBJECT_SAFETY),
-            reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(PROC_MACRO_DERIVE_RESOLUTION_FALLBACK),
-            reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS),
-            reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(ILL_FORMED_ATTRIBUTE_INPUT),
-            reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(AMBIGUOUS_ASSOCIATED_ITEMS),
-            reference: "issue #57644 <https://github.com/rust-lang/rust/issues/57644>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(NESTED_IMPL_TRAIT),
-            reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(MUTABLE_BORROW_RESERVATION_CONFLICT),
-            reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(INDIRECT_STRUCTURAL_MATCH),
-            reference: "issue #62411 <https://github.com/rust-lang/rust/issues/62411>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
-            id: LintId::of(SOFT_UNSTABLE),
-            reference: "issue #64266 <https://github.com/rust-lang/rust/issues/64266>",
-            edition: None,
-        },
-        ]);
-
     // Register renamed and removed lints.
     store.register_renamed("single_use_lifetime", "single_use_lifetimes");
     store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");
@@ -499,12 +336,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         "converted into hard error, see https://github.com/rust-lang/rust/issues/46205");
 }
 
-pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) {
-    store.register_early_pass(sess, false, false, box DefaultHashTypes::new());
-    store.register_early_pass(sess, false, false, box LintPassImpl);
-    store.register_late_pass(sess, false, false, false, box TyTyKind);
+fn register_internals(store: &mut lint::LintStore) {
+    store.register_lints(&DefaultHashTypes::get_lints());
+    store.register_early_pass(|| box DefaultHashTypes::new());
+    store.register_lints(&LintPassImpl::get_lints());
+    store.register_early_pass(|| box LintPassImpl);
+    store.register_lints(&TyTyKind::get_lints());
+    store.register_late_pass(|| box TyTyKind);
     store.register_group(
-        sess,
         false,
         "rustc::internal",
         None,
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index a93946df68f..61b8cbe369a 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -25,7 +25,7 @@ declare_lint! {
     pub UNUSED_MUST_USE,
     Warn,
     "unused result of a type flagged as `#[must_use]`",
-    report_in_external_macro: true
+    report_in_external_macro
 }
 
 declare_lint! {
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 6a2da5d4988..7412e8a2cb9 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -738,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 =>
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index c9851694d44..8c52168b418 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -448,7 +448,7 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::Mod(_) => DefKind::Mod,
             EntryKind::Variant(_) => DefKind::Variant,
             EntryKind::Trait(_) => DefKind::Trait,
-            EntryKind::TraitAlias(_) => DefKind::TraitAlias,
+            EntryKind::TraitAlias => DefKind::TraitAlias,
             EntryKind::Enum(..) => DefKind::Enum,
             EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang),
             EntryKind::ForeignType => DefKind::ForeignTy,
@@ -458,7 +458,7 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::Impl(_) |
             EntryKind::Field |
             EntryKind::Generator(_) |
-            EntryKind::Closure(_) => return None,
+            EntryKind::Closure => return None,
         })
     }
 }
@@ -574,7 +574,7 @@ impl<'a, 'tcx> CrateMetadata {
                                   data.is_marker,
                                   self.def_path_table.def_path_hash(item_id))
             },
-            EntryKind::TraitAlias(_) => {
+            EntryKind::TraitAlias => {
                 ty::TraitDef::new(self.local_def_id(item_id),
                                   hir::Unsafety::Normal,
                                   false,
@@ -679,13 +679,7 @@ impl<'a, 'tcx> CrateMetadata {
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
-        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"),
-        };
-
-        super_predicates.decode((self, tcx))
+        self.root.per_def.super_predicates.get(self, item_id).unwrap().decode((self, tcx))
     }
 
     crate fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
@@ -716,7 +710,7 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> {
+    fn get_impl_data(&self, id: DefIndex) -> ImplData {
         match self.kind(id) {
             EntryKind::Impl(data) => data.decode(self),
             _ => bug!(),
@@ -743,7 +737,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     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)))
+        self.root.per_def.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
     }
 
     /// Iterates over all the stability attributes in the given crate.
@@ -1117,7 +1111,7 @@ impl<'a, 'tcx> CrateMetadata {
         def_key.parent.and_then(|parent_index| {
             match self.kind(parent_index) {
                 EntryKind::Trait(_) |
-                EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)),
+                EntryKind::TraitAlias => Some(self.local_def_id(parent_index)),
                 _ => None,
             }
         })
@@ -1244,16 +1238,7 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     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,
-            EntryKind::Variant(data) |
-            EntryKind::Struct(data, _) => data.decode(self).ctor_sig.unwrap(),
-            EntryKind::Closure(data) => data.decode(self).sig,
-            _ => bug!(),
-        };
-        sig.decode((self, tcx))
+        self.root.per_def.fn_sig.get(self, id).unwrap().decode((self, tcx))
     }
 
     #[inline]
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 6ae8c2fc6c6..0dc9f91ae00 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -71,11 +71,14 @@ struct PerDefTables<'tcx> {
     deprecation: PerDefTable<Lazy<attr::Deprecation>>,
 
     ty: PerDefTable<Lazy<Ty<'tcx>>>,
+    fn_sig: PerDefTable<Lazy<ty::PolyFnSig<'tcx>>>,
+    impl_trait_ref: PerDefTable<Lazy<ty::TraitRef<'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>>>,
+    super_predicates: PerDefTable<Lazy<ty::GenericPredicates<'tcx>>>,
 
     mir: PerDefTable<Lazy<mir::Body<'tcx>>>,
     promoted_mir: PerDefTable<Lazy<IndexVec<mir::Promoted, mir::Body<'tcx>>>>,
@@ -508,11 +511,14 @@ impl<'tcx> EncodeContext<'tcx> {
             deprecation: self.per_def.deprecation.encode(&mut self.opaque),
 
             ty: self.per_def.ty.encode(&mut self.opaque),
+            fn_sig: self.per_def.fn_sig.encode(&mut self.opaque),
+            impl_trait_ref: self.per_def.impl_trait_ref.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),
+            super_predicates: self.per_def.super_predicates.encode(&mut self.opaque),
 
             mir: self.per_def.mir.encode(&mut self.opaque),
             promoted_mir: self.per_def.promoted_mir.encode(&mut self.opaque),
@@ -635,13 +641,7 @@ impl EncodeContext<'tcx> {
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
-            // FIXME(eddyb) deduplicate these with `encode_enum_variant_ctor`.
             ctor: variant.ctor_def_id.map(|did| did.index),
-            ctor_sig: if variant.ctor_kind == CtorKind::Fn {
-                variant.ctor_def_id.map(|ctor_def_id| self.lazy(&tcx.fn_sig(ctor_def_id)))
-            } else {
-                None
-            },
         };
 
         let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap();
@@ -660,6 +660,11 @@ impl EncodeContext<'tcx> {
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
+            // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
+            if let Some(ctor_def_id) = variant.ctor_def_id {
+                record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id));
+            }
+            // FIXME(eddyb) is this ever used?
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
@@ -679,15 +684,11 @@ impl EncodeContext<'tcx> {
         let def_id = variant.ctor_def_id.unwrap();
         debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id);
 
+        // FIXME(eddyb) encode only the `CtorKind` for constructors.
         let data = VariantData {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
             ctor: Some(def_id.index),
-            ctor_sig: if variant.ctor_kind == CtorKind::Fn {
-                Some(self.lazy(tcx.fn_sig(def_id)))
-            } else {
-                None
-            }
         };
 
         // Variant constructors have the same visibility as the parent enums, unless marked as
@@ -706,6 +707,7 @@ impl EncodeContext<'tcx> {
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
+            record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
@@ -780,11 +782,6 @@ impl EncodeContext<'tcx> {
             ctor_kind: variant.ctor_kind,
             discr: variant.discr,
             ctor: Some(def_id.index),
-            ctor_sig: if variant.ctor_kind == CtorKind::Fn {
-                Some(self.lazy(tcx.fn_sig(def_id)))
-            } else {
-                None
-            }
         };
 
         let struct_id = tcx.hir().as_local_hir_id(adt_def_id).unwrap();
@@ -811,6 +808,7 @@ impl EncodeContext<'tcx> {
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
+            record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
@@ -835,6 +833,11 @@ impl EncodeContext<'tcx> {
             self.tcx.predicates_defined_on(def_id))
     }
 
+    fn encode_super_predicates(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_super_predicates({:?})", def_id);
+        record!(self.per_def.super_predicates[def_id] <- self.tcx.super_predicates_of(def_id));
+    }
+
     fn encode_info_for_trait_item(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
         let tcx = self.tcx;
@@ -874,7 +877,6 @@ impl EncodeContext<'tcx> {
                         asyncness: m_sig.header.asyncness,
                         constness: hir::Constness::NotConst,
                         param_names,
-                        sig: self.lazy(tcx.fn_sig(def_id)),
                     }
                 } else {
                     bug!()
@@ -906,6 +908,7 @@ impl EncodeContext<'tcx> {
             ty::AssocKind::OpaqueTy => unreachable!(),
         }
         if trait_item.kind == ty::AssocKind::Method {
+            record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
@@ -952,7 +955,6 @@ 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)),
                     }
                 } else {
                     bug!()
@@ -973,6 +975,7 @@ impl EncodeContext<'tcx> {
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if impl_item.kind == ty::AssocKind::Method {
+            record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
@@ -1081,7 +1084,6 @@ impl EncodeContext<'tcx> {
                     asyncness: header.asyncness,
                     constness: header.constness,
                     param_names: self.encode_fn_param_names_for_body(body),
-                    sig: self.lazy(tcx.fn_sig(def_id)),
                 };
 
                 EntryKind::Fn(self.lazy(data))
@@ -1109,7 +1111,6 @@ impl EncodeContext<'tcx> {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
                     ctor,
-                    ctor_sig: None,
                 }), adt_def.repr)
             }
             hir::ItemKind::Union(..) => {
@@ -1120,7 +1121,6 @@ impl EncodeContext<'tcx> {
                     ctor_kind: variant.ctor_kind,
                     discr: variant.discr,
                     ctor: None,
-                    ctor_sig: None,
                 }), adt_def.repr)
             }
             hir::ItemKind::Impl(_, _, defaultness, ..) => {
@@ -1154,7 +1154,6 @@ impl EncodeContext<'tcx> {
                     defaultness,
                     parent_impl: parent,
                     coerce_unsized_info,
-                    trait_ref: trait_ref.map(|trait_ref| self.lazy(trait_ref)),
                 };
 
                 EntryKind::Impl(self.lazy(data))
@@ -1166,18 +1165,11 @@ impl EncodeContext<'tcx> {
                     paren_sugar: trait_def.paren_sugar,
                     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)),
                 };
 
                 EntryKind::Trait(self.lazy(data))
             }
-            hir::ItemKind::TraitAlias(..) => {
-                let data = TraitAliasData {
-                    super_predicates: self.lazy(tcx.super_predicates_of(def_id)),
-                };
-
-                EntryKind::TraitAlias(self.lazy(data))
-            }
+            hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias,
             hir::ItemKind::ExternCrate(_) |
             hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
         });
@@ -1232,6 +1224,14 @@ impl EncodeContext<'tcx> {
             hir::ItemKind::Impl(..) => self.encode_item_type(def_id),
             _ => {}
         }
+        if let hir::ItemKind::Fn(..) = item.kind {
+            record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
+        }
+        if let hir::ItemKind::Impl(..) = item.kind {
+            if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
+                record!(self.per_def.impl_trait_ref[def_id] <- trait_ref);
+            }
+        }
         self.encode_inherent_implementations(def_id);
         match item.kind {
             hir::ItemKind::Enum(..) |
@@ -1269,6 +1269,13 @@ impl EncodeContext<'tcx> {
             }
             _ => {} // not *wrong* for other kinds of items, but not needed
         }
+        match item.kind {
+            hir::ItemKind::Trait(..) |
+            hir::ItemKind::TraitAlias(..) => {
+                self.encode_super_predicates(def_id);
+            }
+            _ => {}
+        }
 
         let mir = match item.kind {
             hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
@@ -1321,10 +1328,12 @@ impl EncodeContext<'tcx> {
     fn encode_info_for_closure(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
 
-        let tables = self.tcx.typeck_tables_of(def_id);
+        // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
+        // including on the signature, which is inferred in `typeck_tables_of.
         let hir_id = self.tcx.hir().as_local_hir_id(def_id).unwrap();
+        let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id);
 
-        record!(self.per_def.kind[def_id] <- match tables.node_type(hir_id).kind {
+        record!(self.per_def.kind[def_id] <- match ty.kind {
             ty::Generator(def_id, ..) => {
                 let layout = self.tcx.generator_layout(def_id);
                 let data = GeneratorData {
@@ -1333,11 +1342,7 @@ impl EncodeContext<'tcx> {
                 EntryKind::Generator(self.lazy(data))
             }
 
-            ty::Closure(def_id, substs) => {
-                let sig = substs.as_closure().sig(def_id, self.tcx);
-                let data = ClosureData { sig: self.lazy(sig) };
-                EntryKind::Closure(self.lazy(data))
-            }
+            ty::Closure(..) => EntryKind::Closure,
 
             _ => bug!("closure that is neither generator nor closure"),
         });
@@ -1345,6 +1350,9 @@ impl EncodeContext<'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)[..]);
         self.encode_item_type(def_id);
+        if let ty::Closure(def_id, substs) = ty.kind {
+            record!(self.per_def.fn_sig[def_id] <- substs.as_closure().sig(def_id, self.tcx));
+        }
         self.encode_generics(def_id);
         self.encode_optimized_mir(def_id);
         self.encode_promoted_mir(def_id);
@@ -1553,7 +1561,6 @@ impl EncodeContext<'tcx> {
                     asyncness: hir::IsAsync::NotAsync,
                     constness: hir::Constness::NotConst,
                     param_names: self.encode_fn_param_names(names),
-                    sig: self.lazy(tcx.fn_sig(def_id)),
                 };
                 EntryKind::ForeignFn(self.lazy(data))
             }
@@ -1569,6 +1576,7 @@ impl EncodeContext<'tcx> {
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
+            record!(self.per_def.fn_sig[def_id] <- tcx.fn_sig(def_id));
             self.encode_variances_of(def_id);
         }
         self.encode_generics(def_id);
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index 9e4c2685f11..a58db6a903b 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -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 96f35783278..ad39aa34fd5 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -238,11 +238,14 @@ crate struct LazyPerDefTables<'tcx> {
     pub deprecation: Lazy!(PerDefTable<Lazy<attr::Deprecation>>),
 
     pub ty: Lazy!(PerDefTable<Lazy!(Ty<'tcx>)>),
+    pub fn_sig: Lazy!(PerDefTable<Lazy!(ty::PolyFnSig<'tcx>)>),
+    pub impl_trait_ref: Lazy!(PerDefTable<Lazy!(ty::TraitRef<'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 super_predicates: 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>>)>),
@@ -264,22 +267,22 @@ crate 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>),
+    Struct(Lazy<VariantData>, ReprOptions),
+    Union(Lazy<VariantData>, ReprOptions),
+    Fn(Lazy<FnData>),
+    ForeignFn(Lazy<FnData>),
     Mod(Lazy<ModData>),
     MacroDef(Lazy<MacroDef>),
-    Closure(Lazy!(ClosureData<'tcx>)),
+    Closure,
     Generator(Lazy!(GeneratorData<'tcx>)),
-    Trait(Lazy!(TraitData<'tcx>)),
-    Impl(Lazy!(ImplData<'tcx>)),
-    Method(Lazy!(MethodData<'tcx>)),
+    Trait(Lazy<TraitData>),
+    Impl(Lazy<ImplData>),
+    Method(Lazy<MethodData>),
     AssocType(AssocContainer),
     AssocOpaqueTy(AssocContainer),
     AssocConst(AssocContainer, ConstQualif, Lazy<RenderedConst>),
-    TraitAlias(Lazy!(TraitAliasData<'tcx>)),
+    TraitAlias,
 }
 
 /// Additional data for EntryKind::Const and EntryKind::AssocConst
@@ -305,47 +308,37 @@ crate struct MacroDef {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-crate struct FnData<'tcx> {
+crate struct FnData {
     pub asyncness: hir::IsAsync,
     pub constness: hir::Constness,
     pub param_names: Lazy<[ast::Name]>,
-    pub sig: Lazy!(ty::PolyFnSig<'tcx>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-crate struct VariantData<'tcx> {
+crate struct VariantData {
     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>)>,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-crate struct TraitData<'tcx> {
+crate struct TraitData {
     pub unsafety: hir::Unsafety,
     pub paren_sugar: bool,
     pub has_auto_impl: bool,
     pub is_marker: bool,
-    pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>),
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-crate struct TraitAliasData<'tcx> {
-    pub super_predicates: Lazy!(ty::GenericPredicates<'tcx>),
-}
-
-#[derive(RustcEncodable, RustcDecodable)]
-crate struct ImplData<'tcx> {
+crate struct ImplData {
     pub polarity: ty::ImplPolarity,
     pub defaultness: hir::Defaultness,
     pub parent_impl: Option<DefId>,
 
     /// This is `Some` only for impls of `CoerceUnsized`.
+    // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
     pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>,
-    pub trait_ref: Option<Lazy!(ty::TraitRef<'tcx>)>,
 }
 
 
@@ -388,18 +381,13 @@ impl AssocContainer {
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-crate struct MethodData<'tcx> {
-    pub fn_data: FnData<'tcx>,
+crate struct MethodData {
+    pub fn_data: FnData,
     pub container: AssocContainer,
     pub has_self: bool,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
-crate struct ClosureData<'tcx> {
-    pub sig: Lazy!(ty::PolyFnSig<'tcx>),
-}
-
-#[derive(RustcEncodable, RustcDecodable)]
 crate struct GeneratorData<'tcx> {
     pub layout: mir::GeneratorLayout<'tcx>,
 }
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/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/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index b39aa483a6a..b876fd83ec9 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/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 1d83b104177..dc6d4b27886 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -189,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> {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 7bc4bf291ee..77f3768172f 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -154,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;
@@ -253,8 +254,9 @@ 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, pat.hir_id) {
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 7e17162dfb3..58480912929 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -1214,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> {
@@ -1254,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 06fdd407951..d929e958f05 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -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,
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 4d9be55945e..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),
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 f0c0e573443..108c6c9786b 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -431,7 +431,7 @@ 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;
 
         let overflow_check = self.tcx.sess.overflow_checks();
@@ -518,39 +518,35 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 }
             }
 
-            // Work around: avoid ICE in miri.
-            // 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. The main
-            // issue is if an arg is a fat-pointer, miri `expects()` to be able to read the value
-            // of that pointer to get size info. However, since this is `ConstProp`, that argument
-            // doesn't actually have a backing value and so this causes an ICE.
+            // 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;
                 }
             }
 
-            // Work around: avoid extra unnecessary locals.
-            // FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
-            // `SimplifyLocals` doesn't know it can remove.
-            Rvalue::Aggregate(_, operands) if operands.len() == 0 => {
-                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(())
         })
     }
 
@@ -714,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,
@@ -731,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/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 606c1a3a1cc..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,9 +382,16 @@ 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
             }
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index b826dd91198..2e23b8c870c 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -1,8 +1,7 @@
 //! Used by plugin crates to tell `rustc` about the plugins they provide.
 
-use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
+use rustc::lint::LintStore;
 use rustc::session::Session;
-use rustc::util::nodemap::FxHashMap;
 
 use syntax_expand::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
 use syntax_expand::base::MacroExpanderFn;
@@ -26,6 +25,9 @@ pub struct Registry<'a> {
     /// from the plugin registrar.
     pub sess: &'a Session,
 
+    /// The `LintStore` allows plugins to register new lints.
+    pub lint_store: &'a mut LintStore,
+
     #[doc(hidden)]
     pub args_hidden: Option<Vec<ast::NestedMetaItem>>,
 
@@ -36,15 +38,6 @@ pub struct Registry<'a> {
     pub syntax_exts: Vec<NamedSyntaxExtension>,
 
     #[doc(hidden)]
-    pub early_lint_passes: Vec<EarlyLintPassObject>,
-
-    #[doc(hidden)]
-    pub late_lint_passes: Vec<LateLintPassObject>,
-
-    #[doc(hidden)]
-    pub lint_groups: FxHashMap<&'static str, (Vec<LintId>, Option<&'static str>)>,
-
-    #[doc(hidden)]
     pub llvm_passes: Vec<String>,
 
     #[doc(hidden)]
@@ -53,15 +46,13 @@ pub struct Registry<'a> {
 
 impl<'a> Registry<'a> {
     #[doc(hidden)]
-    pub fn new(sess: &'a Session, krate_span: Span) -> Registry<'a> {
+    pub fn new(sess: &'a Session, lint_store: &'a mut LintStore, krate_span: Span) -> Registry<'a> {
         Registry {
             sess,
+            lint_store,
             args_hidden: None,
             krate_span,
             syntax_exts: vec![],
-            early_lint_passes: vec![],
-            late_lint_passes: vec![],
-            lint_groups: FxHashMap::default(),
             llvm_passes: vec![],
             attributes: vec![],
         }
@@ -99,27 +90,6 @@ impl<'a> Registry<'a> {
         self.register_syntax_extension(Symbol::intern(name), ext);
     }
 
-    /// Register a compiler lint pass.
-    pub fn register_early_lint_pass(&mut self, lint_pass: EarlyLintPassObject) {
-        self.early_lint_passes.push(lint_pass);
-    }
-
-    /// Register a compiler lint pass.
-    pub fn register_late_lint_pass(&mut self, lint_pass: LateLintPassObject) {
-        self.late_lint_passes.push(lint_pass);
-    }
-    /// Register a lint group.
-    pub fn register_lint_group(
-        &mut self,
-        name: &'static str,
-        deprecated_name: Option<&'static str>,
-        to: Vec<&'static Lint>
-    ) {
-        self.lint_groups.insert(name,
-                                (to.into_iter().map(|x| LintId::of(x)).collect(),
-                                 deprecated_name));
-    }
-
     /// Register an LLVM pass.
     ///
     /// Registration with LLVM itself is handled through static C++ objects with
diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs
index cd6189c681d..b82cba8c83d 100644
--- a/src/librustc_resolve/error_codes.rs
+++ b/src/librustc_resolve/error_codes.rs
@@ -1682,7 +1682,7 @@ enum Wizard {
 }
 
 trait Isengard {
-    fn wizard(w: Wizard) { // error!
+    fn wizard(w: Wizard) { // ok!
         match w {
             Wizard::Saruman => {
                 // do something
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 424bf31a785..34edd5eaf4f 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -673,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;
                 }
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index c5277c4f90e..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,
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_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index f2502ab3648..79dc4f7e136 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -232,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();
@@ -1274,8 +1274,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     span,
                     item.trait_ref().def_id(),
                     object_safety_violations
-                )
-                    .map(|mut err| err.emit());
+                ).emit();
                 return tcx.types.err;
             }
         }
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index dfeb5fb958c..9cbde276ae9 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -428,21 +428,36 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             self.report_cast_to_unsized_type(fcx);
         } else if self.expr_ty.references_error() || self.cast_ty.references_error() {
             // No sense in giving duplicate error messages
-        } else if self.try_coercion_cast(fcx) {
-            self.trivial_cast_lint(fcx);
-            debug!(" -> CoercionCast");
-            fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
-
         } else {
-            match self.do_check(fcx) {
-                Ok(k) => {
-                    debug!(" -> {:?}", k);
+            match self.try_coercion_cast(fcx) {
+                Ok(()) => {
+                    self.trivial_cast_lint(fcx);
+                    debug!(" -> CoercionCast");
+                    fcx.tables.borrow_mut()
+                        .set_coercion_cast(self.expr.hir_id.local_id);
+                }
+                Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
+                    self.report_object_unsafe_cast(&fcx, did);
+                }
+                Err(_) => {
+                    match self.do_check(fcx) {
+                        Ok(k) => {
+                            debug!(" -> {:?}", k);
+                        }
+                        Err(e) => self.report_cast_error(fcx, e),
+                    };
                 }
-                Err(e) => self.report_cast_error(fcx, e),
             };
         }
     }
 
+    fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
+        let violations = fcx.tcx.object_safety_violations(did);
+        let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
+        err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
+        err.emit();
+    }
+
     /// Checks a cast, and report an error if one exists. In some cases, this
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
@@ -646,8 +661,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
-        fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
+    fn try_coercion_cast(
+        &self,
+        fcx: &FnCtxt<'a, 'tcx>,
+    ) -> Result<(), ty::error::TypeError<'_>> {
+        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
+            Ok(_) => Ok(()),
+            Err(err) => Err(err),
+        }
     }
 }
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 3a89cddda23..f79351dc903 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -61,10 +61,11 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{
     Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast
 };
-use rustc::ty::{self, TypeAndMut, Ty, subst::SubstsRef};
+use rustc::ty::{self, TypeAndMut, Ty};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::RelateResult;
+use rustc::ty::subst::SubstsRef;
 use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
 use syntax::feature_gate;
@@ -196,9 +197,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // a "spurious" type variable, and we don't want to have that
         // type variable in memory if the coercion fails.
         let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b));
-        if unsize.is_ok() {
-            debug!("coerce: unsize successful");
-            return unsize;
+        match unsize {
+            Ok(_) => {
+                debug!("coerce: unsize successful");
+                return unsize;
+            }
+            Err(TypeError::ObjectUnsafeCoercion(did)) => {
+                debug!("coerce: unsize not object safe");
+                return Err(TypeError::ObjectUnsafeCoercion(did));
+            }
+            Err(_) => {}
         }
         debug!("coerce: unsize failed");
 
@@ -539,7 +547,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let mut selcx = traits::SelectionContext::new(self);
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
-        let cause = ObligationCause::misc(self.cause.span, self.body_id);
+        let cause = ObligationCause::new(
+            self.cause.span,
+            self.body_id,
+            ObligationCauseCode::Coercion { source, target },
+        );
 
         // Use a FIFO queue for this custom fulfillment procedure.
         //
@@ -566,14 +578,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
             let trait_ref = match obligation.predicate {
-                ty::Predicate::Trait(ref t) if traits.contains(&t.def_id()) => {
-                    if unsize_did == t.def_id() {
-                        if let ty::Tuple(..) = &t.skip_binder().input_types().nth(1).unwrap().kind {
+                ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
+                    if unsize_did == tr.def_id() {
+                        let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind;
+                        if let ty::Tuple(..) = sty {
                             debug!("coerce_unsized: found unsized tuple coercion");
                             has_unsized_tuple_coercion = true;
                         }
                     }
-                    t.clone()
+                    tr.clone()
                 }
                 _ => {
                     coercion.obligations.push(obligation);
@@ -811,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);
@@ -829,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);
@@ -853,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:
@@ -1333,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 677e2ea3566..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) {
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index ad46a443b8f..8668dd99a8c 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -566,7 +566,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // the `enclosing_loops` field and let's coerce the
             // type of `expr_opt` into what is expected.
             let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            let ctxt = enclosing_breakables.find_breakable(target_id);
+            let ctxt = match enclosing_breakables.opt_find_breakable(target_id) {
+                Some(ctxt) => ctxt,
+                None => { // Avoid ICE when `break` is inside a closure (#65383).
+                    self.tcx.sess.delay_span_bug(
+                        expr.span,
+                        "break was outside loop, but no error was emitted",
+                    );
+                    return tcx.types.err;
+                }
+            };
+
             if let Some(ref mut coerce) = ctxt.coerce {
                 if let Some(ref e) = expr_opt {
                     coerce.coerce(self, &cause, e, e_ty);
@@ -592,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             } else {
                 // If `ctxt.coerce` is `None`, we can just ignore
-                // the type of the expresison.  This is because
+                // the type of the expression.  This is because
                 // either this was a break *without* a value, in
                 // which case it is always a legal type (`()`), or
                 // else an error would have been flagged by the
@@ -1010,7 +1020,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 f2d001eaded..d90ed2a790b 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -919,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 152edf8dd0e..d1a8a6f6026 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -536,10 +536,16 @@ pub struct EnclosingBreakables<'tcx> {
 
 impl<'tcx> EnclosingBreakables<'tcx> {
     fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> {
-        let ix = *self.by_id.get(&target_id).unwrap_or_else(|| {
+        self.opt_find_breakable(target_id).unwrap_or_else(|| {
             bug!("could not find enclosing breakable with id {}", target_id);
-        });
-        &mut self.stack[ix]
+        })
+    }
+
+    fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> {
+        match self.by_id.get(&target_id) {
+            Some(ix) => Some(&mut self.stack[*ix]),
+            None => None,
+        }
     }
 }
 
@@ -1387,9 +1393,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>(
@@ -2440,23 +2474,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;
         }
 
@@ -2467,7 +2501,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
     }
 
@@ -3668,7 +3702,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()
@@ -4517,7 +4551,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
             }
@@ -4993,7 +5027,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/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index a44c475e0f8..8adf4bb94a8 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -183,8 +183,11 @@ fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) {
 
         for component_def_id in component_def_ids {
             if !tcx.is_object_safe(component_def_id) {
-                // This is an error, but it will be reported by wfcheck.  Ignore it here.
+                // Without the 'object_safe_for_dispatch' feature this is an error
+                // which will be reported by wfcheck.  Ignore it here.
                 // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+                // With the feature enabled, the trait is not implemented automatically,
+                // so this is valid.
             } else {
                 let mut supertrait_def_ids =
                     traits::supertrait_def_ids(tcx, component_def_id);
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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b84540d899e..abc8b831449 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1306,7 +1306,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> },
@@ -1588,7 +1588,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>,
@@ -3839,7 +3839,7 @@ impl Clean<Mutability> for hir::Mutability {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Copy, Debug, Hash)]
+#[derive(Clone, PartialEq, Debug)]
 pub enum ImplPolarity {
     Positive,
     Negative,
@@ -4498,7 +4498,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..39ab30e8ecf 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -5,7 +5,7 @@ use rustc::hir::HirId;
 use rustc::middle::cstore::CrateStore;
 use rustc::middle::privacy::AccessLevels;
 use rustc::ty::{Ty, TyCtxt};
-use rustc::lint::{self, LintPass};
+use rustc::lint;
 use rustc::session::config::ErrorOutputType;
 use rustc::session::DiagnosticOutput;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -273,10 +273,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
     whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
 
     let lints = || {
-        lint::builtin::HardwiredLints
-            .get_lints()
+        lint::builtin::HardwiredLints::get_lints()
             .into_iter()
-            .chain(rustc_lint::SoftLints.get_lints().into_iter())
+            .chain(rustc_lint::SoftLints::get_lints().into_iter())
     };
 
     let lint_opts = lints().filter_map(|lint| {
@@ -329,7 +328,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,
@@ -339,6 +338,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
         stderr: None,
         crate_name,
         lint_caps,
+        register_lints: None,
     };
 
     interface::run_compiler_in_existing_thread_pool(config, |compiler| {
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 0dc094ae329..bbc00147ee1 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -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/render.rs b/src/librustdoc/html/render.rs
index 72a72e89281..414c3137376 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1241,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'>\
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/test.rs b/src/librustdoc/test.rs
index 0be6340df96..07dc1e4e915 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,
@@ -77,6 +77,7 @@ pub fn run(options: Options) -> i32 {
         stderr: None,
         crate_name: options.crate_name.clone(),
         lint_caps: Default::default(),
+        register_lints: None,
     };
 
     let mut test_args = options.test_args.clone();
@@ -280,6 +281,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");
     }
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..d0cb0104f6c 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -275,6 +275,8 @@
 #![feature(link_args)]
 #![feature(linkage)]
 #![feature(log_syntax)]
+#![feature(manually_drop_take)]
+#![feature(matches_macro)]
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(needs_panic_runtime)]
@@ -297,6 +299,7 @@
 #![feature(slice_concat_ext)]
 #![feature(slice_internals)]
 #![feature(slice_patterns)]
+#![feature(specialization)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stdsimd)]
@@ -525,6 +528,7 @@ pub use core::{
     writeln,
     // Unstable
     todo,
+    matches,
 };
 
 // Re-export built-in macros defined through libcore.
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..619b1820190 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;
@@ -218,7 +217,7 @@ pub fn update_panic_count(amt: isize) -> usize {
     PANIC_COUNT.with(|c| {
         let next = (c.get() as isize + amt) as usize;
         c.set(next);
-        return next
+        next
     })
 }
 
@@ -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/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/unix/rand.rs b/src/libstd/sys/unix/rand.rs
index c5be1763302..be112f6fc03 100644
--- a/src/libstd/sys/unix/rand.rs
+++ b/src/libstd/sys/unix/rand.rs
@@ -8,7 +8,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
                                              mem::size_of_val(&v));
         imp::fill_bytes(view);
     }
-    return v
+    v
 }
 
 #[cfg(all(unix,
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/handle.rs b/src/libstd/sys/windows/handle.rs
index 3e5aa693354..3986cda1a50 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -46,7 +46,7 @@ impl Handle {
     pub fn into_raw(self) -> c::HANDLE {
         let ret = self.raw();
         mem::forget(self);
-        return ret;
+        ret
     }
 }
 
diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs
index 37cbdcefced..79dec1adf4b 100644
--- a/src/libstd/sys/windows/mutex.rs
+++ b/src/libstd/sys/windows/mutex.rs
@@ -144,7 +144,7 @@ fn kind() -> Kind {
         Some(..) => Kind::SRWLock,
     };
     KIND.store(ret as usize, Ordering::SeqCst);
-    return ret;
+    ret
 }
 
 pub struct ReentrantMutex { inner: UnsafeCell<MaybeUninit<c::CRITICAL_SECTION>> }
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index 8658deb8546..096b7bea8a5 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -257,7 +257,7 @@ impl Stdio {
                         let ret = io.duplicate(0, true,
                                                c::DUPLICATE_SAME_ACCESS);
                         io.into_raw();
-                        return ret
+                        ret
                     }
                     Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
                 }
@@ -472,9 +472,8 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
             cmd.push('"' as u16);
         }
 
-        let mut iter = arg.encode_wide();
         let mut backslashes: usize = 0;
-        while let Some(x) = iter.next() {
+        for x in arg.encode_wide() {
             if x == '\\' as u16 {
                 backslashes += 1;
             } else {
diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs
index c9bcb5d7415..993831bec18 100644
--- a/src/libstd/sys/windows/rand.rs
+++ b/src/libstd/sys/windows/rand.rs
@@ -13,7 +13,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
         panic!("couldn't generate random bytes: {}",
                io::Error::last_os_error());
     }
-    return v
+    v
 }
 
 #[cfg(target_vendor = "uwp")]
diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs
index 4c9734fa0aa..728257cdd4b 100644
--- a/src/libstd/sys/windows/thread_local.rs
+++ b/src/libstd/sys/windows/thread_local.rs
@@ -52,7 +52,7 @@ pub unsafe fn create(dtor: Option<Dtor>) -> Key {
     if let Some(f) = dtor {
         register_dtor(key, f);
     }
-    return key;
+    key
 }
 
 #[inline]
diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs
index e0f0e3a1a45..bd533c93d43 100644
--- a/src/libstd/sys/windows/time.rs
+++ b/src/libstd/sys/windows/time.rs
@@ -80,7 +80,7 @@ impl SystemTime {
         unsafe {
             let mut t: SystemTime = mem::zeroed();
             c::GetSystemTimeAsFileTime(&mut t.t);
-            return t
+            t
         }
     }
 
@@ -228,7 +228,7 @@ mod perf_counter {
                 FREQUENCY = frequency;
                 STATE.store(2, SeqCst);
             }
-            return frequency;
+            frequency
         }
     }
 
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index e92c0d1c58e..cfaab4e22e9 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -509,9 +509,8 @@ pub mod os {
         pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> {
             let ptr = self.os.get() as *mut Value<T>;
             if ptr as usize > 1 {
-                match (*ptr).inner.get() {
-                    Some(ref value) => return Some(value),
-                    None => {},
+                if let Some(ref value) = (*ptr).inner.get() {
+                    return Some(value);
                 }
             }
             self.try_initialize(init)
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 0408d7d1bc2..51a62cd0658 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1305,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"`.
@@ -1327,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),
@@ -1337,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"`).
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 28b61c5aa77..84c86c9651f 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -84,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,
@@ -92,7 +92,7 @@ pub enum InlineAttr {
     Never,
 }
 
-#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -624,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>,
@@ -749,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)
diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs
index 94f0995566f..1386eac48da 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/libsyntax/feature_gate/active.rs
@@ -528,6 +528,9 @@ declare_features! (
     /// Enable accurate caller location reporting during panic (RFC 2091).
     (active, track_caller, "1.40.0", Some(47809), None),
 
+    /// Non-object safe trait objects safe to use but cannot be created in safe rust
+    (active, object_safe_for_dispatch, "1.40.0", Some(43561), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index a68b7fdf931..3fa13f08d3a 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -67,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()),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6bbd8be0cb9..2ce0046ca27 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -86,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,
diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs
index 0acfd1450d8..73bd80e2a21 100644
--- a/src/libsyntax/parse/parser/item.rs
+++ b/src/libsyntax/parse/parser/item.rs
@@ -10,7 +10,6 @@ use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem,
 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::tokenstream::{TokenTree, TokenStream};
 use crate::symbol::{kw, sym};
 use crate::source_map::{self, respan, Span};
@@ -416,10 +415,17 @@ 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 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.
     fn parse_macro_use_or_failure(
         &mut self,
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/source_map.rs b/src/libsyntax/source_map.rs
index 1501adc5971..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,
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index ac155556cda..0559f224f1f 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -19,7 +19,6 @@ use syntax_pos::{BytePos, Span, DUMMY_SP};
 #[cfg(target_arch = "x86_64")]
 use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::Lrc;
-use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
 use smallvec::{SmallVec, smallvec};
 
 use std::{iter, mem};
@@ -136,7 +135,7 @@ 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.
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug, Default, RustcEncodable, RustcDecodable)]
 pub struct TokenStream(pub Lrc<Vec<TreeAndJoint>>);
 
 pub type TreeAndJoint = (TokenTree, IsJoint);
@@ -145,7 +144,7 @@ pub type TreeAndJoint = (TokenTree, IsJoint);
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(TokenStream, 8);
 
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum IsJoint {
     Joint,
     NonJoint
@@ -460,18 +459,6 @@ impl Cursor {
     }
 }
 
-impl Encodable for TokenStream {
-    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
-        self.trees().collect::<Vec<_>>().encode(encoder)
-    }
-}
-
-impl Decodable for TokenStream {
-    fn decode<D: Decoder>(decoder: &mut D) -> Result<TokenStream, D::Error> {
-        Vec::<TokenTree>::decode(decoder).map(|vec| vec.into_iter().collect())
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
 pub struct DelimSpan {
     pub open: Span,
diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs
index c222e7357ac..58edf23a5b1 100644
--- a/src/libsyntax_expand/base.rs
+++ b/src/libsyntax_expand/base.rs
@@ -1072,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
@@ -1082,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_expand/expand.rs b/src/libsyntax_expand/expand.rs
index f03d464eafb..fc521e5edc0 100644
--- a/src/libsyntax_expand/expand.rs
+++ b/src/libsyntax_expand/expand.rs
@@ -1418,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/mbe.rs b/src/libsyntax_expand/mbe.rs
index 453fe94f1de..d0f790638ef 100644
--- a/src/libsyntax_expand/mbe.rs
+++ b/src/libsyntax_expand/mbe.rs
@@ -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/source_util.rs b/src/libsyntax_ext/source_util.rs
index 438e199ebdb..f6c58fcdfa1 100644
--- a/src/libsyntax_ext/source_util.rs
+++ b/src/libsyntax_ext/source_util.rs
@@ -76,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);
 
@@ -122,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) => {
@@ -147,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_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 7f7c5cb2e45..7e42b931961 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -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 4b947c5b857..377d2f877b3 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -459,6 +459,7 @@ symbols! {
         no_std,
         not,
         note,
+        object_safe_for_dispatch,
         Ok,
         omit_gdb_pretty_printer_section,
         on,
diff --git a/src/libtest/bench.rs b/src/libtest/bench.rs
new file mode 100644
index 00000000000..c86bfd16c21
--- /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);
+        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());
+    }
+    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..a34426305be
--- /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.
+            "
+        );
+    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..244cbd2cf5f
--- /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);
+
+    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 4c3cbeb4acc..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,7 +436,7 @@ 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;
@@ -1740,7 +446,8 @@ pub fn run_test(
         && (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 5f7150a8eeb..9de774555e9 100644
--- a/src/libtest/tests.rs
+++ b/src/libtest/tests.rs
@@ -1,11 +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,
-    ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts,
-    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;
@@ -74,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]
@@ -93,11 +101,11 @@ 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
+// FIXME: Re-enable emscripten once it can catch panics again (introduced by #65251)
 #[test]
 #[cfg(not(target_os = "emscripten"))]
 fn test_should_panic() {
@@ -116,11 +124,11 @@ 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
+// 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() {
@@ -139,11 +147,11 @@ 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
+// 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() {
@@ -165,11 +173,11 @@ 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
+// 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() {
@@ -186,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> {
@@ -214,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
 }
 
@@ -252,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
 }
@@ -658,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,
@@ -678,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/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/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-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs
index e290f7fa6b1..9582137eae9 100644
--- a/src/test/run-make-fulldeps/issue-19371/foo.rs
+++ b/src/test/run-make-fulldeps/issue-19371/foo.rs
@@ -59,6 +59,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         stderr: None,
         crate_name: None,
         lint_caps: Default::default(),
+        register_lints: None,
     };
 
     interface::run_compiler(config, |compiler| {
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/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/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/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
index bb0ebf693d0..6b914f501ca 100644
--- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
+++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
@@ -15,15 +15,14 @@ use syntax::symbol::Symbol;
 
 use rustc::hir;
 use rustc::hir::intravisit;
-use rustc::hir::map as hir_map;
 use hir::Node;
 use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
-use rustc::ty;
-use syntax::{ast, source_map};
+use syntax::source_map;
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_late_lint_pass(box MissingWhitelistedAttrPass);
+    reg.lint_store.register_lints(&[&MISSING_WHITELISTED_ATTR]);
+    reg.lint_store.register_late_pass(|| box MissingWhitelistedAttrPass);
     reg.register_attribute(Symbol::intern("whitelisted_attr"), Whitelisted);
 }
 
diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
index 17386d7e1aa..6874c921c1c 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
@@ -7,24 +7,20 @@
 extern crate rustc_driver;
 extern crate syntax;
 
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
+use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass};
 use rustc_driver::plugin::Registry;
 use rustc::hir;
 use syntax::attr;
 use syntax::symbol::Symbol;
 
 macro_rules! fake_lint_pass {
-    ($struct:ident, $lints:expr, $($attr:expr),*) => {
+    ($struct:ident, $($attr:expr),*) => {
         struct $struct;
 
         impl LintPass for $struct {
             fn name(&self) -> &'static str {
                 stringify!($struct)
             }
-
-            fn get_lints(&self) -> LintArray {
-                $lints
-            }
         }
 
         impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $struct {
@@ -49,25 +45,29 @@ declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]");
 
 fake_lint_pass! {
     PassOkay,
-    lint_array!(CRATE_NOT_OKAY), // Single lint
     Symbol::intern("rustc_crate_okay")
 }
 
 fake_lint_pass! {
     PassRedBlue,
-    lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints
     Symbol::intern("rustc_crate_red"), Symbol::intern("rustc_crate_blue")
 }
 
 fake_lint_pass! {
     PassGreyGreen,
-    lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma
     Symbol::intern("rustc_crate_grey"), Symbol::intern("rustc_crate_green")
 }
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_late_lint_pass(box PassOkay);
-    reg.register_late_lint_pass(box PassRedBlue);
-    reg.register_late_lint_pass(box PassGreyGreen);
+    reg.lint_store.register_lints(&[
+        &CRATE_NOT_OKAY,
+        &CRATE_NOT_RED,
+        &CRATE_NOT_BLUE,
+        &CRATE_NOT_GREY,
+        &CRATE_NOT_GREEN,
+    ]);
+    reg.lint_store.register_late_pass(|| box PassOkay);
+    reg.lint_store.register_late_pass(|| box PassRedBlue);
+    reg.lint_store.register_late_pass(|| box PassGreyGreen);
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
index 000e10392e8..1cd3e7b28db 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
@@ -7,7 +7,7 @@
 extern crate rustc_driver;
 extern crate syntax;
 
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
+use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
 use rustc_driver::plugin::Registry;
 use rustc::hir;
 use syntax::attr;
@@ -32,5 +32,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_late_lint_pass(box Pass);
+    reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]);
+    reg.lint_store.register_late_pass(|| box Pass);
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
index a377b07bd3d..cb793b43498 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
@@ -9,7 +9,7 @@ extern crate rustc;
 extern crate rustc_driver;
 
 use rustc::hir;
-use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
+use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
 use rustc_driver::plugin::Registry;
 
 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
@@ -30,6 +30,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_late_lint_pass(box Pass);
-    reg.register_lint_group("lint_me", None, vec![TEST_LINT, PLEASE_LINT]);
+    reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]);
+    reg.lint_store.register_late_pass(|| box Pass);
+    reg.lint_store.register_group(true, "lint_me", None,
+        vec![LintId::of(&TEST_LINT), LintId::of(&PLEASE_LINT)]);
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
index 02675191f78..40c37eb570e 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
@@ -10,8 +10,7 @@ extern crate syntax;
 extern crate rustc;
 extern crate rustc_driver;
 
-use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
-                  EarlyLintPassObject, LintArray};
+use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
 use rustc_driver::plugin::Registry;
 use syntax::ast;
 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
@@ -28,5 +27,6 @@ impl EarlyLintPass for Pass {
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
+    reg.lint_store.register_lints(&[&TEST_LINT]);
+    reg.lint_store.register_early_pass(|| box Pass);
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
index 40f8d490ac8..67135d595f4 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
@@ -8,7 +8,7 @@ extern crate syntax;
 extern crate rustc;
 extern crate rustc_driver;
 
-use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
 use rustc_driver::plugin::Registry;
 use syntax::ast;
 declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
@@ -40,6 +40,8 @@ impl EarlyLintPass for Pass {
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_early_lint_pass(box Pass);
-    reg.register_lint_group("clippy::group", Some("clippy_group"), vec![TEST_LINT, TEST_GROUP]);
+    reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]);
+    reg.lint_store.register_early_pass(|| box Pass);
+    reg.lint_store.register_group(true, "clippy::group", Some("clippy_group"),
+        vec![LintId::of(&TEST_LINT), LintId::of(&TEST_GROUP)]);
 }
diff --git a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
index 48dd5b122b5..0bfb32c6dc4 100644
--- a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
+++ b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.rs
@@ -6,7 +6,7 @@
 extern crate rustc;
 
 use rustc::lint::{LintArray, LintPass};
-use rustc::{declare_lint, declare_lint_pass, impl_lint_pass, lint_array};
+use rustc::{declare_lint, declare_lint_pass, impl_lint_pass};
 
 declare_lint! {
     pub TEST_LINT,
@@ -17,10 +17,6 @@ declare_lint! {
 struct Foo;
 
 impl LintPass for Foo { //~ERROR implementing `LintPass` by hand
-    fn get_lints(&self) -> LintArray {
-        lint_array!(TEST_LINT)
-    }
-
     fn name(&self) -> &'static str {
         "Foo"
     }
@@ -31,10 +27,6 @@ macro_rules! custom_lint_pass_macro {
         struct Custom;
 
         impl LintPass for Custom { //~ERROR implementing `LintPass` by hand
-            fn get_lints(&self) -> LintArray {
-                lint_array!(TEST_LINT)
-            }
-
             fn name(&self) -> &'static str {
                 "Custom"
             }
diff --git a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
index b439ae2cd14..0dbdf4f5aa9 100644
--- a/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
+++ b/src/test/ui-fulldeps/internal-lints/lint_pass_impl_without_macro.stderr
@@ -12,7 +12,7 @@ LL | #![deny(rustc::lint_pass_impl_without_macro)]
    = help: try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
 error: implementing `LintPass` by hand
-  --> $DIR/lint_pass_impl_without_macro.rs:33:14
+  --> $DIR/lint_pass_impl_without_macro.rs:29:14
    |
 LL |         impl LintPass for Custom {
    |              ^^^^^^^^
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/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-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/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 563885133a4..64c9f693115 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]}]}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
+{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"kind":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
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/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/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/break-outside-loop.rs b/src/test/ui/break-outside-loop.rs
index c424c25c646..a6f9d0423d0 100644
--- a/src/test/ui/break-outside-loop.rs
+++ b/src/test/ui/break-outside-loop.rs
@@ -22,4 +22,12 @@ fn main() {
     let rs: Foo = Foo{t: pth};
 
     let unconstrained = break; //~ ERROR: `break` outside of a loop
+
+    // This used to ICE because `target_id` passed to `check_expr_break` would be the closure and
+    // not the `loop`, which failed in the call to `find_breakable`. (#65383)
+    'lab: loop {
+        || {
+            break 'lab; //~ ERROR `break` inside of a closure
+        };
+    }
 }
diff --git a/src/test/ui/break-outside-loop.stderr b/src/test/ui/break-outside-loop.stderr
index 8b686356055..8e300fd848d 100644
--- a/src/test/ui/break-outside-loop.stderr
+++ b/src/test/ui/break-outside-loop.stderr
@@ -33,7 +33,15 @@ error[E0268]: `break` outside of a loop
 LL |     let unconstrained = break;
    |                         ^^^^^ cannot `break` outside of a loop
 
-error: aborting due to 5 previous errors
+error[E0267]: `break` inside of a closure
+  --> $DIR/break-outside-loop.rs:30:13
+   |
+LL |         || {
+   |         -- enclosing closure
+LL |             break 'lab;
+   |             ^^^^^^^^^^ cannot `break` inside of a closure
+
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0267, E0268.
 For more information about an error, try `rustc --explain E0267`.
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/coherence/coherence-unsafe-trait-object-impl.rs b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs
new file mode 100644
index 00000000000..9859a226efd
--- /dev/null
+++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs
@@ -0,0 +1,18 @@
+// Check that unsafe trait object do not implement themselves
+// automatically
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {
+    fn call(&self);
+}
+
+fn takes_t<S: Trait>(s: S) {
+    s.call();
+}
+
+fn takes_t_obj(t: &dyn Trait) {
+    takes_t(t); //~ ERROR E0277
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr
new file mode 100644
index 00000000000..b5a86acfb97
--- /dev/null
+++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&dyn Trait: Trait` is not satisfied
+  --> $DIR/coherence-unsafe-trait-object-impl.rs:15:13
+   |
+LL | fn takes_t<S: Trait>(s: S) {
+   |    -------    ----- required by this bound in `takes_t`
+...
+LL |     takes_t(t);
+   |             ^ the trait `Trait` is not implemented for `&dyn Trait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
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/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
index b7fd29ce706..7090cb880fd 100644
--- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
+++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr
@@ -1,20 +1,20 @@
 error[E0308]: mismatched types
-  --> $DIR/const-argument-cross-crate-mismatch.rs:6:41
+  --> $DIR/const-argument-cross-crate-mismatch.rs:6:67
    |
 LL |     let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `2usize`
+   |                                                                   ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
    |
-   = note: expected type `const_generic_lib::Struct<3usize>`
-              found type `const_generic_lib::Struct<_: usize>`
+   = note: expected type `[u8; 3]`
+              found type `[u8; 2]`
 
 error[E0308]: mismatched types
-  --> $DIR/const-argument-cross-crate-mismatch.rs:8:39
+  --> $DIR/const-argument-cross-crate-mismatch.rs:8:65
    |
 LL |     let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2usize`, found `3usize`
+   |                                                                 ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements
    |
-   = note: expected type `const_generic_lib::Struct<2usize>`
-              found type `const_generic_lib::Struct<_: usize>`
+   = note: expected type `[u8; 2]`
+              found type `[u8; 3]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/issue-65394.rs b/src/test/ui/consts/const-eval/issue-65394.rs
index 978e227bcc8..8cf527f0429 100644
--- a/src/test/ui/consts/const-eval/issue-65394.rs
+++ b/src/test/ui/consts/const-eval/issue-65394.rs
@@ -1,8 +1,5 @@
 // Test for absence of validation mismatch ICE in #65394
 
-#![feature(rustc_attrs)]
-
-#[rustc_mir(borrowck_graphviz_postflow="hello.dot")]
 const _: Vec<i32> = {
     let mut x = Vec::<i32>::new();
     let r = &mut x; //~ ERROR references in constants may only refer to immutable values
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
index f48c551cb50..15df813836e 100644
--- a/src/test/ui/consts/const-eval/issue-65394.stderr
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -1,11 +1,11 @@
 error[E0017]: references in constants may only refer to immutable values
-  --> $DIR/issue-65394.rs:8:13
+  --> $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:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })")]
-[ERROR rustc_mir::transform::qualify_consts] new validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })"), ($DIR/issue-65394.rs:7:9: 7:14, "LiveDrop")]
+[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-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/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/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 7fd3f420a6d..5a7568fe2cd 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -8,6 +8,7 @@
 #![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/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-object_safe_for_dispatch.rs b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs
new file mode 100644
index 00000000000..8945360b7be
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs
@@ -0,0 +1,41 @@
+// Test that the use of the non object-safe trait objects
+// are gated by `object_safe_for_dispatch` feature gate.
+
+trait NonObjectSafe1: Sized {}
+
+trait NonObjectSafe2 {
+    fn static_fn() {}
+}
+
+trait NonObjectSafe3 {
+    fn foo<T>(&self);
+}
+
+trait NonObjectSafe4 {
+    fn foo(&self, &Self);
+}
+
+fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
+    //~^ ERROR E0038
+}
+
+fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
+    //~^ ERROR E0038
+    loop {}
+}
+
+fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
+    //~^ ERROR E0038
+}
+
+fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
+    //~^ ERROR E0038
+    loop {}
+}
+
+trait Trait {}
+
+impl Trait for dyn NonObjectSafe1 {}
+//~^ ERROR E0038
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..54e64e2fc1b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
@@ -0,0 +1,46 @@
+error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:1
+   |
+LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+
+error[E0038]: the trait `NonObjectSafe2` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:1
+   |
+LL |     fn static_fn() {}
+   |        --------- associated function `static_fn` has no `self` parameter
+...
+LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object
+
+error[E0038]: the trait `NonObjectSafe3` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:1
+   |
+LL |     fn foo<T>(&self);
+   |        --- method `foo` has generic type parameters
+...
+LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe3` cannot be made into an object
+
+error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:1
+   |
+LL |     fn foo(&self, &Self);
+   |        --- method `foo` references the `Self` type in its parameters or return type
+...
+LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object
+
+error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6
+   |
+LL | impl Trait for dyn NonObjectSafe1 {}
+   |      ^^^^^ the trait `NonObjectSafe1` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
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/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/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr
index 4a0fb186e49..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
diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr
index 5415a45f7d6..83c03b514dd 100644
--- a/src/test/ui/issues/issue-19538.stderr
+++ b/src/test/ui/issues/issue-19538.stderr
@@ -17,6 +17,7 @@ LL |     let test: &mut dyn Bar = &mut thing;
    |                              ^^^^^^^^^^ the trait `Bar` cannot be made into an object
    |
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing`
+   = note: required by cast to type `&mut dyn Bar`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr
index 66309394a42..06c83f65be2 100644
--- a/src/test/ui/issues/issue-20692.stderr
+++ b/src/test/ui/issues/issue-20692.stderr
@@ -14,6 +14,7 @@ LL |     let _ = x
    |
    = note: the trait cannot require that `Self : Sized`
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T`
+   = note: required by cast to type `&dyn Array`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr
index 8ef7d346cb3..8b923a2c6b2 100644
--- a/src/test/ui/issues/issue-38604.stderr
+++ b/src/test/ui/issues/issue-38604.stderr
@@ -14,6 +14,7 @@ LL |         Box::new(());
    |
    = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<()>`
+   = note: required by cast to type `std::boxed::Box<dyn Foo>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index 27901d06927..a93f4686496 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:18:16
+  --> $DIR/kindck-inherited-copy-bound.rs:21:16
    |
 LL | fn take_param<T:Foo>(foo: &T) { }
    |    ----------   --- required by this bound in `take_param`
@@ -10,7 +10,7 @@ LL |     take_param(&x);
    = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>`
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/kindck-inherited-copy-bound.rs:24:19
+  --> $DIR/kindck-inherited-copy-bound.rs:28:19
    |
 LL |     let z = &x as &dyn Foo;
    |                   ^^^^^^^^ the trait `Foo` cannot be made into an object
@@ -18,13 +18,14 @@ LL |     let z = &x as &dyn Foo;
    = note: the trait cannot require that `Self : Sized`
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/kindck-inherited-copy-bound.rs:24:13
+  --> $DIR/kindck-inherited-copy-bound.rs:28:13
    |
 LL |     let z = &x as &dyn Foo;
    |             ^^ the trait `Foo` cannot be made into an object
    |
    = note: the trait cannot require that `Self : Sized`
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>`
+   = note: required by cast to type `&dyn Foo`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..7c67c5f9e95
--- /dev/null
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
+  --> $DIR/kindck-inherited-copy-bound.rs:21:16
+   |
+LL | fn take_param<T:Foo>(foo: &T) { }
+   |    ----------   --- required by this bound in `take_param`
+...
+LL |     take_param(&x);
+   |                ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>`
+   |
+   = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>`
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/kindck-inherited-copy-bound.rs:28:13
+   |
+LL |     let z = &x as &dyn Foo;
+   |             ^^ the trait `Foo` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<i32>`
+   = note: required by cast to type `&dyn Foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.rs b/src/test/ui/kindck/kindck-inherited-copy-bound.rs
index 61e72908248..aad693e5b19 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.rs
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.rs
@@ -1,5 +1,8 @@
 // Test that Copy bounds inherited by trait are checked.
+//
+// revisions: curr object_safe_for_dispatch
 
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 #![feature(box_syntax)]
 
 use std::any::Any;
@@ -15,15 +18,17 @@ fn take_param<T:Foo>(foo: &T) { }
 
 fn a() {
     let x: Box<_> = box 3;
-    take_param(&x); //~ ERROR E0277
+    take_param(&x); //[curr]~ ERROR E0277
+    //[object_safe_for_dispatch]~^ ERROR E0277
 }
 
 fn b() {
     let x: Box<_> = box 3;
     let y = &x;
     let z = &x as &dyn Foo;
-    //~^ ERROR E0038
-    //~| ERROR E0038
+    //[curr]~^ ERROR E0038
+    //[curr]~| ERROR E0038
+    //[object_safe_for_dispatch]~^^^ ERROR E0038
 }
 
 fn main() { }
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/object-safety/object-safety-associated-consts.stderr b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
index 7d5aa00356e..67ef7a62f10 100644
--- a/src/test/ui/object-safety/object-safety-associated-consts.stderr
+++ b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-associated-consts.rs:9:1
+  --> $DIR/object-safety-associated-consts.rs:12:1
    |
 LL |     const X: usize;
    |           - the trait cannot contain associated consts like `X`
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..20993a680ba
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
@@ -0,0 +1,15 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-associated-consts.rs:14:5
+   |
+LL |     const X: usize;
+   |           - the trait cannot contain associated consts like `X`
+...
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.rs b/src/test/ui/object-safety/object-safety-associated-consts.rs
index 5900019ea91..e1a772e5ab2 100644
--- a/src/test/ui/object-safety/object-safety-associated-consts.rs
+++ b/src/test/ui/object-safety/object-safety-associated-consts.rs
@@ -1,14 +1,18 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with associated consts.
+//
+// revisions: curr object_safe_for_dispatch
 
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Bar {
     const X: usize;
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-    //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn main() {
diff --git a/src/test/ui/object-safety/object-safety-generics.stderr b/src/test/ui/object-safety/object-safety-generics.curr.stderr
index b25e0052e41..8ae9236a5c3 100644
--- a/src/test/ui/object-safety/object-safety-generics.stderr
+++ b/src/test/ui/object-safety/object-safety-generics.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-generics.rs:14:1
+  --> $DIR/object-safety-generics.rs:18:1
    |
 LL |     fn bar<T>(&self, t: T);
    |        --- method `bar` has generic type parameters
@@ -8,7 +8,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
 
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-generics.rs:19:1
+  --> $DIR/object-safety-generics.rs:24:1
    |
 LL |     fn bar<T>(&self, t: T);
    |        --- method `bar` has generic type parameters
diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..d3d8d368888
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
@@ -0,0 +1,27 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-generics.rs:20:5
+   |
+LL |     fn bar<T>(&self, t: T);
+   |        --- method `bar` has generic type parameters
+...
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-generics.rs:26:5
+   |
+LL |     fn bar<T>(&self, t: T);
+   |        --- method `bar` has generic type parameters
+...
+LL |     t as &dyn Bar
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-generics.rs b/src/test/ui/object-safety/object-safety-generics.rs
index d63ea28c8f2..63dcd169925 100644
--- a/src/test/ui/object-safety/object-safety-generics.rs
+++ b/src/test/ui/object-safety/object-safety-generics.rs
@@ -1,6 +1,10 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with generic methods, unless `where Self : Sized` is
 // present.
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
+
 
 trait Bar {
     fn bar<T>(&self, t: T);
@@ -12,13 +16,15 @@ trait Quux {
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
-    //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t as &dyn Bar
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_quux<T:Quux>(t: &T) -> &dyn Quux {
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
index 971e79cb021..297cd876187 100644
--- a/src/test/ui/object-safety/object-safety-mentions-Self.stderr
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-mentions-Self.rs:17:1
+  --> $DIR/object-safety-mentions-Self.rs:22:1
    |
 LL |     fn bar(&self, x: &Self);
    |        --- method `bar` references the `Self` type in its parameters or return type
@@ -8,10 +8,10 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
 
 error[E0038]: the trait `Baz` cannot be made into an object
-  --> $DIR/object-safety-mentions-Self.rs:22:1
+  --> $DIR/object-safety-mentions-Self.rs:28:1
    |
-LL |     fn bar(&self) -> Self;
-   |        --- method `bar` references the `Self` type in its parameters or return type
+LL |     fn baz(&self) -> Self;
+   |        --- method `baz` references the `Self` type in its parameters or return type
 ...
 LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Baz` cannot be made into an object
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..03b2b8da075
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
@@ -0,0 +1,27 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-mentions-Self.rs:24:5
+   |
+LL |     fn bar(&self, x: &Self);
+   |        --- method `bar` references the `Self` type in its parameters or return type
+...
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error[E0038]: the trait `Baz` cannot be made into an object
+  --> $DIR/object-safety-mentions-Self.rs:30:5
+   |
+LL |     fn baz(&self) -> Self;
+   |        --- method `baz` references the `Self` type in its parameters or return type
+...
+LL |     t
+   |     ^ the trait `Baz` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Baz>` for `&T`
+   = note: required by cast to type `&dyn Baz`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.rs b/src/test/ui/object-safety/object-safety-mentions-Self.rs
index f13ffe53626..412d16ff3c7 100644
--- a/src/test/ui/object-safety/object-safety-mentions-Self.rs
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.rs
@@ -1,27 +1,34 @@
 // Check that we correctly prevent users from making trait objects
 // form traits that make use of `Self` in an argument or return
 // position, unless `where Self : Sized` is present..
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
+
 
 trait Bar {
     fn bar(&self, x: &Self);
 }
 
 trait Baz {
-    fn bar(&self) -> Self;
+    fn baz(&self) -> Self;
 }
 
 trait Quux {
-    fn get(&self, s: &Self) -> Self where Self : Sized;
+    fn quux(&self, s: &Self) -> Self where Self : Sized;
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
-    loop { }
+    //[curr]~^ ERROR E0038
+    t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-        //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_quux<T:Quux>(t: &T) -> &dyn Quux {
@@ -32,5 +39,4 @@ fn make_quux_explicit<T:Quux>(t: &T) -> &dyn Quux {
     t as &dyn Quux
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/object-safety/object-safety-no-static.curr.stderr b/src/test/ui/object-safety/object-safety-no-static.curr.stderr
new file mode 100644
index 00000000000..1641ce57771
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-no-static.curr.stderr
@@ -0,0 +1,12 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety-no-static.rs:12:1
+   |
+LL |     fn foo() {}
+   |        --- associated function `foo` has no `self` parameter
+...
+LL | fn diverges() -> Box<dyn Foo> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..91a9285b63c
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
@@ -0,0 +1,15 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety-no-static.rs:22:27
+   |
+LL |     fn foo() {}
+   |        --- associated function `foo` has no `self` parameter
+...
+LL |     let b: Box<dyn Foo> = Box::new(Bar);
+   |                           ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<Bar>`
+   = note: required by cast to type `std::boxed::Box<dyn Foo>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-no-static.rs b/src/test/ui/object-safety/object-safety-no-static.rs
index 55d31ce8087..03b62217483 100644
--- a/src/test/ui/object-safety/object-safety-no-static.rs
+++ b/src/test/ui/object-safety/object-safety-no-static.rs
@@ -1,14 +1,24 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with static methods.
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Foo {
-    fn foo();
+    fn foo() {}
 }
 
-fn foo_implicit<T:Foo+'static>(b: Box<T>) -> Box<dyn Foo + 'static> {
-    //~^ ERROR E0038
+fn diverges() -> Box<dyn Foo> {
+    //[curr]~^ ERROR E0038
     loop { }
 }
 
+struct Bar;
+
+impl Foo for Bar {}
+
 fn main() {
+    let b: Box<dyn Foo> = Box::new(Bar);
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
diff --git a/src/test/ui/object-safety/object-safety-sized-2.stderr b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
index dcaf2ff0bc2..1e1d2bf64c4 100644
--- a/src/test/ui/object-safety/object-safety-sized-2.stderr
+++ b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-sized-2.rs:10:1
+  --> $DIR/object-safety-sized-2.rs:14:1
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..06ecfd019c8
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
@@ -0,0 +1,13 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-sized-2.rs:16:5
+   |
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-sized-2.rs b/src/test/ui/object-safety/object-safety-sized-2.rs
index 7235b22404e..1e79b8cd917 100644
--- a/src/test/ui/object-safety/object-safety-sized-2.rs
+++ b/src/test/ui/object-safety/object-safety-sized-2.rs
@@ -1,5 +1,9 @@
 // Check that we correctly prevent users from making trait objects
 // from traits where `Self : Sized`.
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Bar
     where Self : Sized
@@ -8,8 +12,9 @@ trait Bar
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
-    loop { }
+    //[curr]~^ ERROR E0038
+    t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn main() {
diff --git a/src/test/ui/object-safety/object-safety-sized.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr
index 98bc73e38d4..1a67e79e83d 100644
--- a/src/test/ui/object-safety/object-safety-sized.stderr
+++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-sized.rs:8:1
+  --> $DIR/object-safety-sized.rs:12:1
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..3d88dfc40ed
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
@@ -0,0 +1,13 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-sized.rs:14:5
+   |
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-sized.rs b/src/test/ui/object-safety/object-safety-sized.rs
index 1312bb34717..b424b892d3b 100644
--- a/src/test/ui/object-safety/object-safety-sized.rs
+++ b/src/test/ui/object-safety/object-safety-sized.rs
@@ -1,13 +1,18 @@
 // Check that we correctly prevent users from making trait objects
 // from traits where `Self : Sized`.
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Bar : Sized {
     fn bar<T>(&self, t: T);
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn main() {
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/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs
new file mode 100644
index 00000000000..fa04f4b12d5
--- /dev/null
+++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs
@@ -0,0 +1,23 @@
+// Check that we if we get ahold of an object unsafe trait
+// object with auto traits and lifetimes, we can downcast it
+//
+// check-pass
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+fn downcast_auto(t: &(dyn Trait + Send)) -> &dyn Trait {
+    t
+}
+
+fn downcast_lifetime<'a, 'b, 't>(t: &'a (dyn Trait + 't))
+                                 -> &'b (dyn Trait + 't)
+where
+    'a: 'b,
+    't: 'a + 'b,
+{
+    t
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
new file mode 100644
index 00000000000..1dea4012265
--- /dev/null
+++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
@@ -0,0 +1,69 @@
+// Check that we can manually implement an object
+// unsafe trait for its trait object
+//
+// run-pass
+
+#![feature(object_safe_for_dispatch)]
+
+trait Bad {
+    fn stat() -> char {
+        'A'
+    }
+    fn virt(&self) -> char {
+        'B'
+    }
+    fn indirect(&self) -> char {
+        Self::stat()
+    }
+}
+
+trait Good {
+    fn good_virt(&self) -> char {
+        panic!()
+    }
+    fn good_indirect(&self) -> char {
+        panic!()
+    }
+}
+
+impl<'a> Bad for dyn Bad + 'a {
+    fn stat() -> char {
+        'C'
+    }
+    fn virt(&self) -> char {
+        'D'
+    }
+}
+
+struct Struct {}
+
+impl Bad for Struct {}
+
+impl Good for Struct {}
+
+fn main() {
+    let s = Struct {};
+
+    let mut res = String::new();
+
+    // Directly call static
+    res.push(Struct::stat()); // "A"
+    res.push(<dyn Bad>::stat()); // "AC"
+
+    let good: &dyn Good = &s;
+
+    // These look similar enough...
+    let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) };
+
+    // Call virtual
+    res.push(s.virt()); // "ACB"
+    res.push(bad.virt()); // "ACBD"
+
+    // Indirectly call static
+    res.push(s.indirect()); // "ACBDA"
+    res.push(bad.indirect()); // "ACBDAC"
+
+    if &res != "ACBDAC" {
+        panic!();
+    }
+}
diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs
new file mode 100644
index 00000000000..df97d2c1327
--- /dev/null
+++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs
@@ -0,0 +1,37 @@
+// Check that we can statically dispatch methods for object
+// unsafe trait objects, directly and indirectly
+//
+// check-pass
+
+#![feature(object_safe_for_dispatch)]
+
+trait Statics {
+    fn plain() {}
+    fn generic<T>() {}
+}
+
+trait Trait: Sized {}
+
+impl<'a> Statics for dyn Trait + 'a {}
+
+fn static_poly<T: Statics + ?Sized>() {
+    T::plain();
+    T::generic::<usize>();
+}
+
+fn inferred_poly<T: Statics + ?Sized>(t: &T) {
+    static_poly::<T>();
+    T::plain();
+    T::generic::<usize>();
+}
+
+fn call(t: &dyn Trait) {
+    static_poly::<dyn Trait>();
+    inferred_poly(t);
+}
+
+fn main() {
+    static_poly::<dyn Trait>();
+    <dyn Trait>::plain();
+    <dyn Trait>::generic::<usize>()
+}
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/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
new file mode 100644
index 00000000000..cdffc1d86ed
--- /dev/null
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
@@ -0,0 +1,24 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:34:32
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |        --- method `foo`'s `self` parameter cannot be dispatched on
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |                                ^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |        --- method `foo`'s `self` parameter cannot be dispatched on
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
+   = note: required by cast to type `std::rc::Rc<dyn Foo>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..725632a1212
--- /dev/null
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
@@ -0,0 +1,15 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |        --- method `foo`'s `self` parameter cannot be dispatched on
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
+   = note: required by cast to type `std::rc::Rc<dyn Foo>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
index 7443d888c9e..2eeabad28db 100644
--- a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
@@ -1,3 +1,6 @@
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 #![feature(arbitrary_self_types)]
 
 use std::rc::Rc;
@@ -29,8 +32,9 @@ impl Bar for usize {
 
 fn make_foo() {
     let x = Rc::new(5usize) as Rc<dyn Foo>;
-    //~^ ERROR E0038
-    //~| ERROR E0038
+    //[curr]~^ ERROR E0038
+    //[curr]~| ERROR E0038
+    //[object_safe_for_dispatch]~^^^ ERROR E0038
 }
 
 fn make_bar() {
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/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/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr
index 3ac1e96b30c..028e9eedd64 100644
--- a/src/test/ui/traits/trait-object-safety.stderr
+++ b/src/test/ui/traits/trait-object-safety.stderr
@@ -8,6 +8,7 @@ LL |     let _: &dyn Tr = &St;
    |                      ^^^ the trait `Tr` cannot be made into an object
    |
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St`
+   = note: required by cast to type `&dyn Tr`
 
 error[E0038]: the trait `Tr` cannot be made into an object
   --> $DIR/trait-object-safety.rs:15:12
diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr
index 83c2c065274..9b750d382ec 100644
--- a/src/test/ui/traits/trait-test-2.stderr
+++ b/src/test/ui/traits/trait-test-2.stderr
@@ -33,6 +33,7 @@ LL |     (box 10 as Box<dyn bar>).dup();
    |      ^^^^^^ the trait `bar` cannot be made into an object
    |
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn bar>>` for `std::boxed::Box<{integer}>`
+   = note: required by cast to type `std::boxed::Box<dyn bar>`
 
 error: aborting due to 4 previous errors
 
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-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/wf/wf-convert-unsafe-trait-obj-box.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs
new file mode 100644
index 00000000000..ffdb49a3be5
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs
@@ -0,0 +1,18 @@
+// Check that we do not allow casts or coercions
+// to object unsafe trait objects inside a Box
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+struct S;
+
+impl Trait for S {}
+
+fn takes_box(t: Box<dyn Trait>) {}
+
+fn main() {
+    Box::new(S) as Box<dyn Trait>; //~ ERROR E0038
+    let t_box: Box<dyn Trait> = Box::new(S); //~ ERROR E0038
+    takes_box(Box::new(S)); //~ ERROR E0038
+}
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
new file mode 100644
index 00000000000..0b63aef2bce
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:16:33
+   |
+LL |     let t_box: Box<dyn Trait> = Box::new(S);
+   |                                 ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
+   = note: required by cast to type `std::boxed::Box<dyn Trait>`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15
+   |
+LL |     takes_box(Box::new(S));
+   |               ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
+   = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5
+   |
+LL |     Box::new(S) as Box<dyn Trait>;
+   |     ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
+   = note: required by cast to type `std::boxed::Box<dyn Trait>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs
new file mode 100644
index 00000000000..143b854ed6b
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs
@@ -0,0 +1,18 @@
+// Check that we do not allow casts or coercions
+// to object unsafe trait objects by ref
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+struct S;
+
+impl Trait for S {}
+
+fn takes_trait(t: &dyn Trait) {}
+
+fn main() {
+    &S as &dyn Trait; //~ ERROR E0038
+    let t: &dyn Trait = &S; //~ ERROR E0038
+    takes_trait(&S); //~ ERROR E0038
+}
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
new file mode 100644
index 00000000000..7aeefd731fb
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:16:25
+   |
+LL |     let t: &dyn Trait = &S;
+   |                         ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17
+   |
+LL |     takes_trait(&S);
+   |                 ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5
+   |
+LL |     &S as &dyn Trait;
+   |     ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.rs b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs
new file mode 100644
index 00000000000..c8731a8ecaf
--- /dev/null
+++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs
@@ -0,0 +1,29 @@
+// Check that we do not allow coercions to object
+// unsafe trait objects in match arms
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+struct S;
+
+impl Trait for S {}
+
+struct R;
+
+impl Trait for R {}
+
+fn opt() -> Option<()> {
+    Some(())
+}
+
+fn main() {
+    match opt() {
+        Some(()) => &S,
+        None => &R,  //~ ERROR E0308
+    }
+    let t: &dyn Trait = match opt() { //~ ERROR E0038
+        Some(()) => &S, //~ ERROR E0038
+        None => &R,
+    };
+}
diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
new file mode 100644
index 00000000000..185b1e6c36b
--- /dev/null
+++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
@@ -0,0 +1,38 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/wf-unsafe-trait-obj-match.rs:23:17
+   |
+LL | /     match opt() {
+LL | |         Some(()) => &S,
+   | |                     -- this is found to be of type `&S`
+LL | |         None => &R,
+   | |                 ^^ expected struct `S`, found struct `R`
+LL | |     }
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected type `&S`
+              found type `&R`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-unsafe-trait-obj-match.rs:26:21
+   |
+LL |         Some(()) => &S,
+   |                     ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-unsafe-trait-obj-match.rs:25:25
+   |
+LL |     let t: &dyn Trait = match opt() {
+   |                         ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R`
+   = note: required by cast to type `&dyn Trait`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0038, E0308.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject cbedd97b3a58023eff365a2fa74700d06115144
+Subproject e8d5a9e95c145a3a9be89c582d8a6f88d4ea703
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 2adc39f27b7fd2d06b3d1d470827928766731a1
+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);