about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/builder.rs29
-rw-r--r--src/bootstrap/builder/tests.rs4
-rw-r--r--src/bootstrap/channel.rs2
-rw-r--r--src/bootstrap/check.rs66
-rw-r--r--src/bootstrap/compile.rs334
-rw-r--r--src/bootstrap/config.rs5
-rwxr-xr-xsrc/bootstrap/configure.py4
-rw-r--r--src/bootstrap/dist.rs29
-rw-r--r--src/bootstrap/doc.rs4
-rw-r--r--src/bootstrap/lib.rs11
-rw-r--r--src/bootstrap/test.rs2
-rw-r--r--src/bootstrap/toolstate.rs8
-rw-r--r--src/bootstrap/util.rs13
-rwxr-xr-xsrc/ci/run.sh7
m---------src/doc/reference0
-rw-r--r--src/liballoc/benches/string.rs40
-rw-r--r--src/liballoc/collections/linked_list.rs17
-rw-r--r--src/liballoc/collections/vec_deque.rs31
-rw-r--r--src/liballoc/lib.rs3
-rw-r--r--src/liballoc/raw_vec.rs21
-rw-r--r--src/liballoc/rc.rs16
-rw-r--r--src/liballoc/rc/tests.rs14
-rw-r--r--src/liballoc/string.rs1
-rw-r--r--src/liballoc/sync.rs40
-rw-r--r--src/liballoc/sync/tests.rs14
-rw-r--r--src/liballoc/tests/linked_list.rs107
-rw-r--r--src/liballoc/tests/vec_deque.rs34
-rw-r--r--src/liballoc/vec.rs18
-rw-r--r--src/libcore/alloc.rs1
-rw-r--r--src/libcore/any.rs12
-rw-r--r--src/libcore/benches/lib.rs1
-rw-r--r--src/libcore/benches/pattern.rs43
-rw-r--r--src/libcore/cell.rs5
-rw-r--r--src/libcore/char/methods.rs1
-rw-r--r--src/libcore/clone.rs2
-rw-r--r--src/libcore/cmp.rs8
-rw-r--r--src/libcore/convert/mod.rs98
-rw-r--r--src/libcore/convert/num.rs2
-rw-r--r--src/libcore/fmt/mod.rs124
-rw-r--r--src/libcore/intrinsics.rs4
-rw-r--r--src/libcore/iter/adapters/mod.rs8
-rw-r--r--src/libcore/iter/sources.rs1
-rw-r--r--src/libcore/lib.rs10
-rw-r--r--src/libcore/macros/mod.rs2
-rw-r--r--src/libcore/marker.rs4
-rw-r--r--src/libcore/mem/manually_drop.rs2
-rw-r--r--src/libcore/mem/maybe_uninit.rs8
-rw-r--r--src/libcore/mem/mod.rs27
-rw-r--r--src/libcore/num/f32.rs2
-rw-r--r--src/libcore/num/f64.rs2
-rw-r--r--src/libcore/num/mod.rs111
-rw-r--r--src/libcore/num/wrapping.rs1
-rw-r--r--src/libcore/ops/range.rs3
-rw-r--r--src/libcore/ops/try.rs35
-rw-r--r--src/libcore/panic.rs19
-rw-r--r--src/libcore/ptr/mod.rs8
-rw-r--r--src/libcore/ptr/non_null.rs4
-rw-r--r--src/libcore/result.rs3
-rw-r--r--src/libcore/slice/mod.rs3
-rw-r--r--src/libcore/str/mod.rs77
-rw-r--r--src/libcore/str/pattern.rs19
-rw-r--r--src/libcore/sync/atomic.rs18
-rw-r--r--src/libcore/task/wake.rs2
-rw-r--r--src/libcore/time.rs12
-rw-r--r--src/librustc/hir/lowering.rs121
-rw-r--r--src/librustc/hir/lowering/item.rs131
-rw-r--r--src/librustc/hir/map/mod.rs13
-rw-r--r--src/librustc/hir/mod.rs11
-rw-r--r--src/librustc/ich/mod.rs22
-rw-r--r--src/librustc/infer/error_reporting/mod.rs1
-rw-r--r--src/librustc/infer/error_reporting/need_type_info.rs235
-rw-r--r--src/librustc/infer/mod.rs5
-rw-r--r--src/librustc/infer/resolve.rs2
-rw-r--r--src/librustc/infer/type_variable.rs3
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/lint/context.rs4
-rw-r--r--src/librustc/lint/mod.rs8
-rw-r--r--src/librustc/middle/stability.rs29
-rw-r--r--src/librustc/mir/mod.rs18
-rw-r--r--src/librustc/mir/tcx.rs7
-rw-r--r--src/librustc/mir/visit.rs16
-rw-r--r--src/librustc/query/mod.rs1
-rw-r--r--src/librustc/traits/error_reporting.rs123
-rw-r--r--src/librustc/ty/cast.rs3
-rw-r--r--src/librustc/ty/codec.rs3
-rw-r--r--src/librustc/ty/constness.rs50
-rw-r--r--src/librustc/ty/context.rs17
-rw-r--r--src/librustc/ty/mod.rs11
-rw-r--r--src/librustc_codegen_llvm/Cargo.toml22
-rw-r--r--src/librustc_codegen_llvm/abi.rs1
-rw-r--r--src/librustc_codegen_llvm/allocator.rs1
-rw-r--r--src/librustc_codegen_llvm/asm.rs2
-rw-r--r--src/librustc_codegen_llvm/attributes.rs1
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs4
-rw-r--r--src/librustc_codegen_llvm/back/write.rs8
-rw-r--r--src/librustc_codegen_llvm/builder.rs2
-rw-r--r--src/librustc_codegen_llvm/callee.rs1
-rw-r--r--src/librustc_codegen_llvm/common.rs2
-rw-r--r--src/librustc_codegen_llvm/consts.rs2
-rw-r--r--src/librustc_codegen_llvm/context.rs2
-rw-r--r--src/librustc_codegen_llvm/debuginfo/gdb.rs1
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs3
-rw-r--r--src/librustc_codegen_llvm/debuginfo/mod.rs1
-rw-r--r--src/librustc_codegen_llvm/debuginfo/source_loc.rs1
-rw-r--r--src/librustc_codegen_llvm/declare.rs1
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs1
-rw-r--r--src/librustc_codegen_llvm/lib.rs30
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs1
-rw-r--r--src/librustc_codegen_llvm/llvm/mod.rs19
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs1
-rw-r--r--src/librustc_codegen_llvm/metadata.rs2
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs1
-rw-r--r--src/librustc_codegen_llvm/type_.rs1
-rw-r--r--src/librustc_codegen_llvm/type_of.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/place.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs101
-rw-r--r--src/librustc_codegen_utils/lib.rs2
-rw-r--r--src/librustc_data_structures/obligation_forest/mod.rs282
-rw-r--r--src/librustc_driver/Cargo.toml3
-rw-r--r--src/librustc_driver/lib.rs6
-rw-r--r--src/librustc_error_codes/error_codes/E0725.md4
-rw-r--r--src/librustc_error_codes/error_codes/E0743.md16
-rw-r--r--src/librustc_error_codes/error_codes/E0744.md2
-rw-r--r--src/librustc_error_codes/error_codes/E0745.md2
-rw-r--r--src/librustc_feature/accepted.rs2
-rw-r--r--src/librustc_feature/active.rs21
-rw-r--r--src/librustc_feature/builtin_attrs.rs8
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs9
-rw-r--r--src/librustc_incremental/assert_module_sources.rs8
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs7
-rw-r--r--src/librustc_interface/Cargo.toml4
-rw-r--r--src/librustc_interface/interface.rs2
-rw-r--r--src/librustc_interface/util.rs110
-rw-r--r--src/librustc_lint/builtin.rs8
-rw-r--r--src/librustc_llvm/Cargo.toml3
-rw-r--r--src/librustc_llvm/lib.rs20
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs4
-rw-r--r--src/librustc_metadata/rmeta/decoder/cstore_impl.rs3
-rw-r--r--src/librustc_metadata/rmeta/encoder.rs11
-rw-r--r--src/librustc_metadata/rmeta/mod.rs1
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs16
-rw-r--r--src/librustc_mir/borrow_check/invalidation.rs18
-rw-r--r--src/librustc_mir/borrow_check/mod.rs25
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs49
-rw-r--r--src/librustc_mir/build/cfg.rs12
-rw-r--r--src/librustc_mir/build/expr/as_place.rs14
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs1
-rw-r--r--src/librustc_mir/build/expr/category.rs1
-rw-r--r--src/librustc_mir/build/expr/into.rs18
-rw-r--r--src/librustc_mir/build/matches/mod.rs49
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs1
-rw-r--r--src/librustc_mir/hair/cx/expr.rs84
-rw-r--r--src/librustc_mir/hair/mod.rs5
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs119
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs133
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/interpret/traits.rs13
-rw-r--r--src/librustc_mir/interpret/validity.rs51
-rw-r--r--src/librustc_mir/lib.rs2
-rw-r--r--src/librustc_mir/transform/add_retag.rs18
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs21
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs18
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs112
-rw-r--r--src/librustc_mir/transform/const_prop.rs2
-rw-r--r--src/librustc_mir/transform/promote_consts.rs24
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs24
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs61
-rw-r--r--src/librustc_mir/util/liveness.rs2
-rw-r--r--src/librustc_parse/config.rs8
-rw-r--r--src/librustc_parse/lib.rs5
-rw-r--r--src/librustc_parse/parser/expr.rs2
-rw-r--r--src/librustc_parse/parser/item.rs271
-rw-r--r--src/librustc_parse/parser/pat.rs22
-rw-r--r--src/librustc_parse/parser/path.rs6
-rw-r--r--src/librustc_parse/parser/ty.rs50
-rw-r--r--src/librustc_passes/ast_validation.rs161
-rw-r--r--src/librustc_passes/check_const.rs87
-rw-r--r--src/librustc_passes/hir_stats.rs4
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs18
-rw-r--r--src/librustc_resolve/def_collector.rs33
-rw-r--r--src/librustc_resolve/late.rs25
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs38
-rw-r--r--src/librustc_session/config.rs939
-rw-r--r--src/librustc_session/lib.rs3
-rw-r--r--src/librustc_session/options.rs951
-rw-r--r--src/librustc_target/spec/i686_unknown_dragonfly.rs23
-rw-r--r--src/librustc_target/spec/mod.rs1
-rw-r--r--src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs2
-rw-r--r--src/librustc_typeck/astconv.rs103
-rw-r--r--src/librustc_typeck/check/cast.rs76
-rw-r--r--src/librustc_typeck/check/coercion.rs16
-rw-r--r--src/librustc_typeck/check/expr.rs6
-rw-r--r--src/librustc_typeck/check/method/probe.rs2
-rw-r--r--src/librustc_typeck/check/method/suggest.rs161
-rw-r--r--src/librustc_typeck/check/mod.rs109
-rw-r--r--src/librustc_typeck/check/op.rs85
-rw-r--r--src/librustc_typeck/check/pat.rs25
-rw-r--r--src/librustc_typeck/check/writeback.rs3
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/html/item_type.rs12
-rw-r--r--src/librustdoc/html/render.rs143
-rw-r--r--src/librustdoc/html/render/cache.rs34
-rw-r--r--src/librustdoc/html/static/main.js2
-rw-r--r--src/librustdoc/lib.rs3
-rw-r--r--src/libserialize/lib.rs2
-rw-r--r--src/libstd/error.rs9
-rw-r--r--src/libstd/ffi/c_str.rs3
-rw-r--r--src/libstd/fs.rs2
-rw-r--r--src/libstd/io/buffered.rs172
-rw-r--r--src/libstd/lib.rs6
-rw-r--r--src/libstd/net/addr.rs14
-rw-r--r--src/libstd/net/ip.rs4
-rw-r--r--src/libstd/net/mod.rs19
-rw-r--r--src/libstd/net/tcp.rs15
-rw-r--r--src/libstd/primitive_docs.rs4
-rw-r--r--src/libstd/sync/once.rs1
-rw-r--r--src/libstd/sys/sgx/abi/entry.S30
-rw-r--r--src/libstd/sys/unix/net.rs42
-rw-r--r--src/libstd/sys/unix/process/process_common.rs8
-rw-r--r--src/libstd/sys/vxworks/net.rs3
-rw-r--r--src/libstd/sys/wasi/fs.rs35
-rw-r--r--src/libsyntax/ast.rs69
-rw-r--r--src/libsyntax/attr/builtin.rs125
-rw-r--r--src/libsyntax/attr/mod.rs2
-rw-r--r--src/libsyntax/feature_gate/check.rs60
-rw-r--r--src/libsyntax/mut_visit.rs66
-rw-r--r--src/libsyntax/print/pprust.rs190
-rw-r--r--src/libsyntax/ptr.rs9
-rw-r--r--src/libsyntax/token.rs4
-rw-r--r--src/libsyntax/util/node_count.rs8
-rw-r--r--src/libsyntax/visit.rs70
-rw-r--r--src/libsyntax_expand/base.rs30
-rw-r--r--src/libsyntax_expand/expand.rs21
-rw-r--r--src/libsyntax_expand/mbe/macro_parser.rs23
-rw-r--r--src/libsyntax_expand/mbe/macro_rules.rs4
-rw-r--r--src/libsyntax_expand/mbe/transcribe.rs4
-rw-r--r--src/libsyntax_expand/placeholders.rs21
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs18
-rw-r--r--src/libsyntax_pos/symbol.rs2
-rw-r--r--src/libterm/terminfo/mod.rs2
-rw-r--r--src/rustc/Cargo.toml1
-rw-r--r--src/stage0.txt2
-rw-r--r--src/test/codegen/enum-debug-niche-2.rs2
-rw-r--r--src/test/mir-opt/address-of.rs112
-rw-r--r--src/test/mir-opt/array-index-is-temporary.rs19
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs18
-rw-r--r--src/test/mir-opt/retag.rs10
-rw-r--r--src/test/mir-opt/retain-never-const.rs1
-rw-r--r--src/test/mir-opt/slice-drop-shim.rs18
-rw-r--r--src/test/mir-opt/uninhabited-enum.rs2
-rw-r--r--src/test/pretty/raw-address-of.rs12
-rw-r--r--src/test/rustdoc/const-display.rs6
-rw-r--r--src/test/ui/associated-const/associated-const-ambiguity-report.stderr10
-rw-r--r--src/test/ui/associated-const/issue-63496.rs4
-rw-r--r--src/test/ui/associated-const/issue-63496.stderr12
-rw-r--r--src/test/ui/associated-item/issue-48027.stderr6
-rw-r--r--src/test/ui/associated-types/associated-types-overridden-binding.stderr17
-rw-r--r--src/test/ui/associated-types/associated-types-unconstrained.stderr6
-rw-r--r--src/test/ui/async-await/issue-67252-unnamed-future.rs24
-rw-r--r--src/test/ui/async-await/issue-67252-unnamed-future.stderr22
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs2
-rw-r--r--src/test/ui/async-await/unresolved_type_param.stderr2
-rw-r--r--src/test/ui/autoderef-full-lval.rs4
-rw-r--r--src/test/ui/autoderef-full-lval.stderr4
-rw-r--r--src/test/ui/binary-op-on-double-ref.rs2
-rw-r--r--src/test/ui/binary-op-on-double-ref.stderr2
-rw-r--r--src/test/ui/binding/empty-types-in-patterns.rs2
-rw-r--r--src/test/ui/binop/binop-bitxor-str.rs2
-rw-r--r--src/test/ui/binop/binop-bitxor-str.stderr2
-rw-r--r--src/test/ui/binop/binop-mul-bool.rs2
-rw-r--r--src/test/ui/binop/binop-mul-bool.stderr2
-rw-r--r--src/test/ui/binop/binop-typeck.rs2
-rw-r--r--src/test/ui/binop/binop-typeck.stderr2
-rw-r--r--src/test/ui/borrowck/assign-never-type.rs2
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-borrowed.rs22
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-borrowed.stderr40
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs23
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.rs17
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr21
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-mutability-ok.rs44
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-mutability.rs42
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr59
-rw-r--r--src/test/ui/break-while-condition.rs2
-rw-r--r--src/test/ui/break-while-condition.stderr6
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr4
-rw-r--r--src/test/ui/cast/cast-as-bool.rs2
-rw-r--r--src/test/ui/cast/cast-as-bool.stderr7
-rw-r--r--src/test/ui/closures/issue-52437.stderr7
-rw-r--r--src/test/ui/coercion/coerce-issue-49593-box-never.rs2
-rw-r--r--src/test/ui/coercion/coerce-to-bang-cast.rs2
-rw-r--r--src/test/ui/coercion/coerce-to-bang-cast.stderr4
-rw-r--r--src/test/ui/coercion/coerce-to-bang.rs2
-rw-r--r--src/test/ui/coercion/coerce-to-bang.stderr20
-rw-r--r--src/test/ui/command/command-argv0-debug.rs24
-rw-r--r--src/test/ui/command/command-argv0.rs (renamed from src/test/ui/command-argv0.rs)0
-rw-r--r--src/test/ui/command/command-exec.rs (renamed from src/test/ui/command-exec.rs)0
-rw-r--r--src/test/ui/command/command-pre-exec.rs (renamed from src/test/ui/command-pre-exec.rs)0
-rw-r--r--src/test/ui/command/command-uid-gid.rs (renamed from src/test/ui/command-uid-gid.rs)0
-rw-r--r--src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs1
-rw-r--r--src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr19
-rw-r--r--src/test/ui/const-generics/cannot-infer-const-args.stderr2
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.stderr2
-rw-r--r--src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs2
-rw-r--r--src/test/ui/consts/const-address-of-interior-mut.rs16
-rw-r--r--src/test/ui/consts/const-address-of-interior-mut.stderr27
-rw-r--r--src/test/ui/consts/const-address-of-mut.rs14
-rw-r--r--src/test/ui/consts/const-address-of-mut.stderr39
-rw-r--r--src/test/ui/consts/const-address-of.rs19
-rw-r--r--src/test/ui/consts/const-eval/auxiliary/stability.rs4
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs4
-rw-r--r--src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs1
-rw-r--r--src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr4
-rw-r--r--src/test/ui/consts/const-eval/infinite_loop.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-52442.stderr7
-rw-r--r--src/test/ui/consts/const-eval/issue-52475.stderr8
-rw-r--r--src/test/ui/consts/const-eval/issue-62272.stderr12
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.rs1
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.stderr6
-rw-r--r--src/test/ui/consts/const-eval/panic-never-type.rs1
-rw-r--r--src/test/ui/consts/const-eval/panic-never-type.stderr6
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.rs15
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.stderr54
-rw-r--r--src/test/ui/consts/const-labeled-break.stderr8
-rw-r--r--src/test/ui/consts/const-mut-refs/const_mut_address_of.rs30
-rw-r--r--src/test/ui/consts/const-mut-refs/const_mut_refs.rs1
-rw-r--r--src/test/ui/consts/const-prop-ice3.rs7
-rw-r--r--src/test/ui/consts/control-flow/basics.rs62
-rw-r--r--src/test/ui/consts/control-flow/drop-failure.rs26
-rw-r--r--src/test/ui/consts/control-flow/drop-failure.stderr14
-rw-r--r--src/test/ui/consts/control-flow/drop-success.rs21
-rw-r--r--src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs1
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr2
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.rs1
-rw-r--r--src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr50
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.rs20
-rw-r--r--src/test/ui/consts/control-flow/interior-mutability.stderr19
-rw-r--r--src/test/ui/consts/control-flow/loop.both.stderr19
-rw-r--r--src/test/ui/consts/control-flow/loop.if_match.stderr98
-rw-r--r--src/test/ui/consts/control-flow/loop.loop_.stderr96
-rw-r--r--src/test/ui/consts/control-flow/loop.rs28
-rw-r--r--src/test/ui/consts/control-flow/loop.stock.stderr104
-rw-r--r--src/test/ui/consts/control-flow/short-circuit-let.rs1
-rw-r--r--src/test/ui/consts/control-flow/single_variant_match_ice.rs2
-rw-r--r--src/test/ui/consts/issue-64662.stderr4
-rw-r--r--src/test/ui/consts/min_const_fn/address_of.rs17
-rw-r--r--src/test/ui/consts/min_const_fn/address_of.stderr21
-rw-r--r--src/test/ui/consts/min_const_fn/address_of_const.rs19
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr2
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs1
-rw-r--r--src/test/ui/consts/min_const_fn/loop_ice.stderr7
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs7
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr6
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.rs2
-rw-r--r--src/test/ui/consts/validate_never_arrays.rs2
-rw-r--r--src/test/ui/did_you_mean/issue-40006.rs4
-rw-r--r--src/test/ui/did_you_mean/issue-40006.stderr12
-rw-r--r--src/test/ui/empty/empty-never-array.rs2
-rw-r--r--src/test/ui/empty/empty-never-array.stderr4
-rw-r--r--src/test/ui/error-codes/E0004-2.stderr4
-rw-r--r--src/test/ui/error-codes/E0034.stderr10
-rw-r--r--src/test/ui/error-codes/E0283.stderr6
-rw-r--r--src/test/ui/error-codes/E0401.stderr2
-rw-r--r--src/test/ui/feature-gate/allow-features-empty.rs2
-rw-r--r--src/test/ui/feature-gate/allow-features-empty.stderr12
-rw-r--r--src/test/ui/feature-gate/allow-features.rs2
-rw-r--r--src/test/ui/feature-gate/allow-features.stderr10
-rw-r--r--src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-never_type.rs17
-rw-r--r--src/test/ui/feature-gates/feature-gate-never_type.stderr48
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr8
-rw-r--r--src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr18
-rw-r--r--src/test/ui/for-loop-while/loop-break-value.rs1
-rw-r--r--src/test/ui/for/for-loop-type-error.rs2
-rw-r--r--src/test/ui/for/for-loop-type-error.stderr2
-rw-r--r--src/test/ui/inference/inference_unstable_featured.stderr10
-rw-r--r--src/test/ui/invalid/invalid-variadic-function.rs3
-rw-r--r--src/test/ui/invalid/invalid-variadic-function.stderr15
-rw-r--r--src/test/ui/invalid_const_promotion.rs1
-rw-r--r--src/test/ui/issues/issue-12028.stderr6
-rw-r--r--src/test/ui/issues/issue-14915.rs2
-rw-r--r--src/test/ui/issues/issue-14915.stderr2
-rw-r--r--src/test/ui/issues/issue-16966.stderr2
-rw-r--r--src/test/ui/issues/issue-17551.stderr2
-rw-r--r--src/test/ui/issues/issue-18446.stderr6
-rw-r--r--src/test/ui/issues/issue-21974.stderr6
-rw-r--r--src/test/ui/issues/issue-24363.rs2
-rw-r--r--src/test/ui/issues/issue-24363.stderr2
-rw-r--r--src/test/ui/issues/issue-24424.rs2
-rw-r--r--src/test/ui/issues/issue-24424.stderr6
-rw-r--r--src/test/ui/issues/issue-25368.stderr2
-rw-r--r--src/test/ui/issues/issue-28837.rs18
-rw-r--r--src/test/ui/issues/issue-28837.stderr18
-rw-r--r--src/test/ui/issues/issue-29147.rs2
-rw-r--r--src/test/ui/issues/issue-29147.stderr6
-rw-r--r--src/test/ui/issues/issue-31076.rs4
-rw-r--r--src/test/ui/issues/issue-31076.stderr4
-rw-r--r--src/test/ui/issues/issue-35668.rs2
-rw-r--r--src/test/ui/issues/issue-35668.stderr2
-rw-r--r--src/test/ui/issues/issue-3601.stderr4
-rw-r--r--src/test/ui/issues/issue-3702-2.stderr10
-rw-r--r--src/test/ui/issues/issue-3820.rs2
-rw-r--r--src/test/ui/issues/issue-3820.stderr2
-rw-r--r--src/test/ui/issues/issue-40610.rs2
-rw-r--r--src/test/ui/issues/issue-40610.stderr2
-rw-r--r--src/test/ui/issues/issue-41394.rs2
-rw-r--r--src/test/ui/issues/issue-41394.stderr2
-rw-r--r--src/test/ui/issues/issue-47377.stderr2
-rw-r--r--src/test/ui/issues/issue-47380.stderr2
-rw-r--r--src/test/ui/issues/issue-5062.stderr2
-rw-r--r--src/test/ui/issues/issue-51714.stderr8
-rw-r--r--src/test/ui/issues/issue-54954.stderr6
-rw-r--r--src/test/ui/issues/issue-58022.rs2
-rw-r--r--src/test/ui/issues/issue-58022.stderr6
-rw-r--r--src/test/ui/issues/issue-58856-1.rs2
-rw-r--r--src/test/ui/issues/issue-58856-1.stderr17
-rw-r--r--src/test/ui/issues/issue-60075.stderr2
-rw-r--r--src/test/ui/issues/issue-6458-2.stderr2
-rw-r--r--src/test/ui/issues/issue-6458-3.stderr2
-rw-r--r--src/test/ui/issues/issue-6458.stderr2
-rw-r--r--src/test/ui/issues/issue-65611.stderr5
-rw-r--r--src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr10
-rw-r--r--src/test/ui/issues/issue-66923-show-error-for-correct-call.rs15
-rw-r--r--src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr19
-rw-r--r--src/test/ui/lint/lint-unused-mut-variables.rs8
-rw-r--r--src/test/ui/lint/lint-unused-mut-variables.stderr14
-rw-r--r--src/test/ui/lint/must_use-unit.rs1
-rw-r--r--src/test/ui/lint/must_use-unit.stderr6
-rw-r--r--src/test/ui/lint/uninitialized-zeroed.rs2
-rw-r--r--src/test/ui/loops/loop-break-value.rs2
-rw-r--r--src/test/ui/loops/loop-break-value.stderr34
-rw-r--r--src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr2
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr10
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr10
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-impls.stderr10
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr10
-rw-r--r--src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr10
-rw-r--r--src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr15
-rw-r--r--src/test/ui/mir/mir_calls_to_shims.rs1
-rw-r--r--src/test/ui/missing/missing-items/missing-type-parameter.stderr2
-rw-r--r--src/test/ui/never_type/adjust_never.rs2
-rw-r--r--src/test/ui/never_type/auto-traits.rs1
-rw-r--r--src/test/ui/never_type/call-fn-never-arg-wrong-type.rs2
-rw-r--r--src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr2
-rw-r--r--src/test/ui/never_type/call-fn-never-arg.rs1
-rw-r--r--src/test/ui/never_type/cast-never.rs2
-rw-r--r--src/test/ui/never_type/defaulted-never-note.rs2
-rw-r--r--src/test/ui/never_type/dispatch_from_dyn_zst.rs2
-rw-r--r--src/test/ui/never_type/diverging-fallback-control-flow.rs2
-rw-r--r--src/test/ui/never_type/impl-for-never.rs2
-rw-r--r--src/test/ui/never_type/issue-44402.rs1
-rw-r--r--src/test/ui/never_type/never-assign-dead-code.rs1
-rw-r--r--src/test/ui/never_type/never-assign-dead-code.stderr10
-rw-r--r--src/test/ui/never_type/never-assign-wrong-type.rs1
-rw-r--r--src/test/ui/never_type/never-assign-wrong-type.stderr2
-rw-r--r--src/test/ui/never_type/never-associated-type.rs2
-rw-r--r--src/test/ui/never_type/never-from-impl-is-reserved.rs2
-rw-r--r--src/test/ui/never_type/never-from-impl-is-reserved.stderr2
-rw-r--r--src/test/ui/never_type/never-result.rs2
-rw-r--r--src/test/ui/never_type/never-type-arg.rs2
-rw-r--r--src/test/ui/never_type/never-type-rvalues.rs1
-rw-r--r--src/test/ui/never_type/never-value-fallback-issue-66757.rs29
-rw-r--r--src/test/ui/never_type/never_transmute_never.rs1
-rw-r--r--src/test/ui/never_type/panic-uninitialized-zeroed.rs1
-rw-r--r--src/test/ui/never_type/try_from.rs2
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.rs2
-rw-r--r--src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr2
-rw-r--r--src/test/ui/packed/packed-struct-address-of-element.rs37
-rw-r--r--src/test/ui/packed/packed-struct-borrow-element.rs2
-rw-r--r--src/test/ui/parser/impl-item-const-pass.rs8
-rw-r--r--src/test/ui/parser/impl-item-const-semantic-fail.rs7
-rw-r--r--src/test/ui/parser/impl-item-const-semantic-fail.stderr10
-rw-r--r--src/test/ui/parser/impl-item-fn-no-body-pass.rs8
-rw-r--r--src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs7
-rw-r--r--src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr10
-rw-r--r--src/test/ui/parser/impl-item-type-no-body-pass.rs11
-rw-r--r--src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs22
-rw-r--r--src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr73
-rw-r--r--src/test/ui/parser/issue-21153.stderr2
-rw-r--r--src/test/ui/parser/issue-32446.stderr4
-rw-r--r--src/test/ui/parser/lifetime-in-pattern-recover.rs6
-rw-r--r--src/test/ui/parser/lifetime-in-pattern-recover.stderr23
-rw-r--r--src/test/ui/parser/lifetime-in-pattern.rs1
-rw-r--r--src/test/ui/parser/lifetime-in-pattern.stderr10
-rw-r--r--src/test/ui/parser/macro/trait-non-item-macros.stderr4
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr4
-rw-r--r--src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs12
-rw-r--r--src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr38
-rw-r--r--src/test/ui/parser/trait-item-with-defaultness-pass.rs13
-rw-r--r--src/test/ui/parser/variadic-ffi-3.rs5
-rw-r--r--src/test/ui/parser/variadic-ffi-3.stderr9
-rw-r--r--src/test/ui/parser/variadic-ffi-4.rs5
-rw-r--r--src/test/ui/parser/variadic-ffi-4.stderr9
-rw-r--r--src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs9
-rw-r--r--src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr24
-rw-r--r--src/test/ui/parser/variadic-ffi-semantic-restrictions.rs76
-rw-r--r--src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr206
-rw-r--r--src/test/ui/parser/variadic-ffi-syntactic-pass.rs53
-rw-r--r--src/test/ui/pattern/pattern-tyvar-2.rs2
-rw-r--r--src/test/ui/pattern/pattern-tyvar-2.stderr2
-rw-r--r--src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr9
-rw-r--r--src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs93
-rw-r--r--src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr223
-rw-r--r--src/test/ui/pattern/usefulness/match-empty.rs92
-rw-r--r--src/test/ui/pattern/usefulness/match-empty.stderr204
-rw-r--r--src/test/ui/pattern/usefulness/match-privately-empty.rs1
-rw-r--r--src/test/ui/pattern/usefulness/match-privately-empty.stderr2
-rw-r--r--src/test/ui/print_type_sizes/uninhabited.rs1
-rw-r--r--src/test/ui/question-mark-type-infer.rs2
-rw-r--r--src/test/ui/question-mark-type-infer.stderr11
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-op.rs6
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-op.stderr18
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-temp-deref.rs20
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-temp-deref.stderr74
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-temp.rs6
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-temp.stderr40
-rw-r--r--src/test/ui/raw-ref-op/unusual_locations.rs31
-rw-r--r--src/test/ui/raw-ref-op/unusual_locations.stderr18
-rw-r--r--src/test/ui/reachable/expr_add.rs1
-rw-r--r--src/test/ui/reachable/expr_add.stderr4
-rw-r--r--src/test/ui/reachable/expr_assign.rs1
-rw-r--r--src/test/ui/reachable/expr_assign.stderr8
-rw-r--r--src/test/ui/reachable/expr_call.rs1
-rw-r--r--src/test/ui/reachable/expr_call.stderr6
-rw-r--r--src/test/ui/reachable/expr_cast.rs2
-rw-r--r--src/test/ui/reachable/expr_method.rs1
-rw-r--r--src/test/ui/reachable/expr_method.stderr6
-rw-r--r--src/test/ui/reachable/expr_type.rs2
-rw-r--r--src/test/ui/reachable/expr_unary.rs1
-rw-r--r--src/test/ui/reachable/expr_unary.stderr6
-rw-r--r--src/test/ui/reachable/unreachable-loop-patterns.rs2
-rw-r--r--src/test/ui/reachable/unreachable-try-pattern.rs2
-rw-r--r--src/test/ui/reachable/unwarned-match-on-never.rs2
-rw-r--r--src/test/ui/reachable/unwarned-match-on-never.stderr6
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs3
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum.rs12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum.stderr20
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs37
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr45
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr8
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs2
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr8
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr16
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs2
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr36
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr8
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr16
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs2
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr28
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs1
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr10
-rw-r--r--src/test/ui/self/self-vs-path-ambiguity.stderr2
-rw-r--r--src/test/ui/span/issue-37767.stderr30
-rw-r--r--src/test/ui/span/issue-39018.rs26
-rw-r--r--src/test/ui/span/issue-39018.stderr26
-rw-r--r--src/test/ui/span/issue-42234-unknown-receiver-type.rs4
-rw-r--r--src/test/ui/span/issue-42234-unknown-receiver-type.stderr9
-rw-r--r--src/test/ui/span/issue-7575.stderr20
-rw-r--r--src/test/ui/span/type-annotations-needed-expr.stderr5
-rw-r--r--src/test/ui/span/type-binding.stderr2
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.rs7
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.stderr10
-rw-r--r--src/test/ui/str/str-concat-on-double-ref.rs2
-rw-r--r--src/test/ui/str/str-concat-on-double-ref.stderr2
-rw-r--r--src/test/ui/suggestions/option-content-move2.rs16
-rw-r--r--src/test/ui/suggestions/option-content-move2.stderr18
-rw-r--r--src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs2
-rw-r--r--src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr2
-rw-r--r--src/test/ui/traits/reservation-impls/reservation-impl-non-lattice-ok.rs2
-rw-r--r--src/test/ui/traits/trait-alias-ambiguous.stderr10
-rw-r--r--src/test/ui/traits/trait-resolution-in-overloaded-op.rs2
-rw-r--r--src/test/ui/traits/trait-resolution-in-overloaded-op.stderr2
-rw-r--r--src/test/ui/traits/trait-static-method-generic-inference.stderr6
-rw-r--r--src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr2
-rw-r--r--src/test/ui/type-inference/or_else-multiple-type-params.rs10
-rw-r--r--src/test/ui/type-inference/or_else-multiple-type-params.stderr12
-rw-r--r--src/test/ui/type-inference/sort_by_key.rs5
-rw-r--r--src/test/ui/type-inference/sort_by_key.stderr11
-rw-r--r--src/test/ui/type-inference/unbounded-associated-type.rs16
-rw-r--r--src/test/ui/type-inference/unbounded-associated-type.stderr15
-rw-r--r--src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs9
-rw-r--r--src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr9
-rw-r--r--src/test/ui/type-inference/unbounded-type-param-in-fn.rs7
-rw-r--r--src/test/ui/type-inference/unbounded-type-param-in-fn.stderr9
-rw-r--r--src/test/ui/type-sizes.rs1
-rw-r--r--src/test/ui/type/type-annotation-needed.rs2
-rw-r--r--src/test/ui/type/type-annotation-needed.stderr7
-rw-r--r--src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr2
-rw-r--r--src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr2
-rw-r--r--src/test/ui/type/type-check/issue-22897.stderr2
-rw-r--r--src/test/ui/type/type-check/issue-40294.stderr6
-rw-r--r--src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs27
-rw-r--r--src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr22
-rw-r--r--src/test/ui/type/type-check/missing_trait_impl.rs2
-rw-r--r--src/test/ui/type/type-check/missing_trait_impl.stderr2
-rw-r--r--src/test/ui/unconstrained-none.stderr2
-rw-r--r--src/test/ui/unconstrained-ref.stderr2
-rw-r--r--src/test/ui/uninhabited/uninhabited-irrefutable.rs1
-rw-r--r--src/test/ui/uninhabited/uninhabited-irrefutable.stderr2
-rw-r--r--src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr3
-rw-r--r--src/test/ui/uninhabited/uninhabited-patterns.rs1
-rw-r--r--src/test/ui/uninhabited/uninhabited-patterns.stderr12
-rw-r--r--src/test/ui/vec/vec-res-add.rs2
-rw-r--r--src/test/ui/vec/vec-res-add.stderr2
-rw-r--r--src/test/ui/vector-no-ann.stderr2
m---------src/tools/clippy18
-rw-r--r--src/tools/compiletest/src/main.rs1
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--src/tools/tidy/src/error_codes_check.rs1
627 files changed, 8586 insertions, 4649 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 5c0b43c1d24..8b0ad169cfc 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -339,7 +339,6 @@ impl<'a> Builder<'a> {
             Kind::Build => describe!(
                 compile::Std,
                 compile::Rustc,
-                compile::CodegenBackend,
                 compile::StartupObjects,
                 tool::BuildManifest,
                 tool::Rustbook,
@@ -364,7 +363,6 @@ impl<'a> Builder<'a> {
             Kind::Check | Kind::Clippy | Kind::Fix => describe!(
                 check::Std,
                 check::Rustc,
-                check::CodegenBackend,
                 check::Rustdoc
             ),
             Kind::Test => describe!(
@@ -632,11 +630,6 @@ impl<'a> Builder<'a> {
         self.ensure(Libdir { compiler, target })
     }
 
-    pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
-        self.sysroot_libdir(compiler, compiler.host)
-            .with_file_name(self.config.rust_codegen_backends_dir.clone())
-    }
-
     /// Returns the compiler's libdir where it stores the dynamic libraries that
     /// it itself links against.
     ///
@@ -707,15 +700,6 @@ impl<'a> Builder<'a> {
         }
     }
 
-    /// Gets the paths to all of the compiler's codegen backends.
-    fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
-        fs::read_dir(self.sysroot_codegen_backends(compiler))
-            .into_iter()
-            .flatten()
-            .filter_map(Result::ok)
-            .map(|entry| entry.path())
-    }
-
     pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
         self.ensure(tool::Rustdoc { compiler })
     }
@@ -759,12 +743,6 @@ impl<'a> Builder<'a> {
         let mut cargo = Command::new(&self.initial_cargo);
         let out_dir = self.stage_out(compiler, mode);
 
-        // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
-        // so we need to explicitly clear out if they've been updated.
-        for backend in self.codegen_backends(compiler) {
-            self.clear_if_dirty(&out_dir, &backend);
-        }
-
         if cmd == "doc" || cmd == "rustdoc" {
             let my_out = match mode {
                 // This is the intended out directory for compiler documentation.
@@ -981,7 +959,7 @@ impl<'a> Builder<'a> {
         // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
         // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
         // to change a flag in a binary?
-        if self.config.rust_rpath {
+        if self.config.rust_rpath && util::use_host_linker(&target) {
             let rpath = if target.contains("apple") {
 
                 // Note that we need to take one extra step on macOS to also pass
@@ -991,10 +969,7 @@ impl<'a> Builder<'a> {
                 // flesh out rpath support more fully in the future.
                 rustflags.arg("-Zosx-rpath-install-name");
                 Some("-Wl,-rpath,@loader_path/../lib")
-            } else if !target.contains("windows") &&
-                      !target.contains("wasm32") &&
-                      !target.contains("emscripten") &&
-                      !target.contains("fuchsia") {
+            } else if !target.contains("windows") {
                 Some("-Wl,-rpath,$ORIGIN/../lib")
             } else {
                 None
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 2bb90fdb04e..b9d97fb8b76 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -363,6 +363,10 @@ fn dist_with_same_targets_and_hosts() {
                 compiler: Compiler { host: a, stage: 1 },
                 target: b,
             },
+            compile::Std {
+                compiler: Compiler { host: a, stage: 2 },
+                target: b,
+            },
         ]
     );
     assert_eq!(
diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs
index b17ee098ff6..ec4bf9a04fa 100644
--- a/src/bootstrap/channel.rs
+++ b/src/bootstrap/channel.rs
@@ -13,7 +13,7 @@ use build_helper::output;
 use crate::Build;
 
 // The version number
-pub const CFG_RELEASE_NUM: &str = "1.41.0";
+pub const CFG_RELEASE_NUM: &str = "1.42.0";
 
 pub struct GitInfo {
     inner: Option<Info>,
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index df1c7257584..f5c427d870e 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -1,11 +1,10 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
-use crate::compile::{run_cargo, std_cargo, rustc_cargo, rustc_cargo_env,
-                     add_to_sysroot};
+use crate::compile::{run_cargo, std_cargo, rustc_cargo, add_to_sysroot};
 use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step};
 use crate::tool::{prepare_tool_cargo, SourceType};
 use crate::{Compiler, Mode};
-use crate::cache::{INTERNER, Interned};
+use crate::cache::Interned;
 use std::path::PathBuf;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -97,7 +96,7 @@ impl Step for Rustc {
 
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target,
             cargo_subcommand(builder.kind));
-        rustc_cargo(builder, &mut cargo);
+        rustc_cargo(builder, &mut cargo, target);
 
         builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
         run_cargo(builder,
@@ -114,55 +113,6 @@ impl Step for Rustc {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CodegenBackend {
-    pub target: Interned<String>,
-    pub backend: Interned<String>,
-}
-
-impl Step for CodegenBackend {
-    type Output = ();
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("rustc_codegen_llvm")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        let backend = run.builder.config.rust_codegen_backends.get(0);
-        let backend = backend.cloned().unwrap_or_else(|| {
-            INTERNER.intern_str("llvm")
-        });
-        run.builder.ensure(CodegenBackend {
-            target: run.target,
-            backend,
-        });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(0, builder.config.build);
-        let target = self.target;
-        let backend = self.backend;
-
-        builder.ensure(Rustc { target });
-
-        let mut cargo = builder.cargo(compiler, Mode::Codegen, target,
-            cargo_subcommand(builder.kind));
-        cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
-        rustc_cargo_env(builder, &mut cargo);
-
-        // We won't build LLVM if it's not available, as it shouldn't affect `check`.
-
-        run_cargo(builder,
-                  cargo,
-                  args(builder.kind),
-                  &codegen_backend_stamp(builder, compiler, target, backend),
-                  vec![],
-                  true);
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Rustdoc {
     pub target: Interned<String>,
 }
@@ -231,16 +181,6 @@ pub fn librustc_stamp(
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
 }
 
-/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
-/// compiler for the specified target and backend.
-fn codegen_backend_stamp(builder: &Builder<'_>,
-                         compiler: Compiler,
-                         target: Interned<String>,
-                         backend: Interned<String>) -> PathBuf {
-    builder.cargo_out(compiler, Mode::Codegen, target)
-         .join(format!(".librustc_codegen_llvm-{}-check.stamp", backend))
-}
-
 /// Cargo's output path for rustdoc in a given stage, compiled by a particular
 /// compiler for the specified target.
 pub fn rustdoc_stamp(
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index f686dfe71b9..baf9aabed00 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -27,7 +27,7 @@ use crate::{Compiler, Mode, GitRepo};
 use crate::native;
 
 use crate::cache::{INTERNER, Interned};
-use crate::builder::{Step, RunConfig, ShouldRun, Builder};
+use crate::builder::{Step, RunConfig, ShouldRun, Builder, Kind};
 
 #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
@@ -445,7 +445,7 @@ impl Step for Rustc {
         });
 
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
-        rustc_cargo(builder, &mut cargo);
+        rustc_cargo(builder, &mut cargo, target);
 
         builder.info(&format!("Building stage{} compiler artifacts ({} -> {})",
                  compiler.stage, &compiler.host, target));
@@ -456,6 +456,44 @@ impl Step for Rustc {
                   vec![],
                   false);
 
+        // We used to build librustc_codegen_llvm as a separate step,
+        // which produced a dylib that the compiler would dlopen() at runtime.
+        // This meant that we only needed to make sure that libLLVM.so was
+        // installed by the time we went to run a tool using it - since
+        // librustc_codegen_llvm was effectively a standalone artifact,
+        // other crates were completely oblivious to its dependency
+        // on `libLLVM.so` during build time.
+        //
+        // However, librustc_codegen_llvm is now built as an ordinary
+        // crate during the same step as the rest of the compiler crates.
+        // This means that any crates depending on it will see the fact
+        // that it uses `libLLVM.so` as a native library, and will
+        // cause us to pass `-llibLLVM.so` to the linker when we link
+        // a binary.
+        //
+        // For `rustc` itself, this works out fine.
+        // During the `Assemble` step, we call `dist::maybe_install_llvm_dylib`
+        // to copy libLLVM.so into the `stage` directory. We then link
+        // the compiler binary, which will find `libLLVM.so` in the correct place.
+        //
+        // However, this is insufficient for tools that are build against stage0
+        // (e.g. stage1 rustdoc). Since `Assemble` for stage0 doesn't actually do anything,
+        // we won't have `libLLVM.so` in the stage0 sysroot. In the past, this wasn't
+        // a problem - we would copy the tool binary into its correct stage directory
+        // (e.g. stage1 for a stage1 rustdoc built against a stage0 compiler).
+        // Since libLLVM.so wasn't resolved until runtime, it was fine for it to
+        // not exist while we were building it.
+        //
+        // To ensure that we can still build stage1 tools against a stage0 compiler,
+        // we explicitly copy libLLVM.so into the stage0 sysroot when building
+        // the stage0 compiler. This ensures that tools built against stage0
+        // will see libLLVM.so at build time, making the linker happy.
+        if compiler.stage == 0 {
+            builder.info(&format!("Installing libLLVM.so to stage 0 ({})", compiler.host));
+            let sysroot = builder.sysroot(compiler);
+            dist::maybe_install_llvm_dylib(builder, compiler.host, &sysroot);
+        }
+
         builder.ensure(RustcLink {
             compiler: builder.compiler(compiler.stage, builder.config.build),
             target_compiler: compiler,
@@ -464,21 +502,20 @@ impl Step for Rustc {
     }
 }
 
-pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo) {
+pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
     cargo.arg("--features").arg(builder.rustc_features())
          .arg("--manifest-path")
          .arg(builder.src.join("src/rustc/Cargo.toml"));
-    rustc_cargo_env(builder, cargo);
+    rustc_cargo_env(builder, cargo, target);
 }
 
-pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo) {
+pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
     cargo.env("CFG_RELEASE", builder.rust_release())
          .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
          .env("CFG_VERSION", builder.rust_version())
-         .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default())
-         .env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir);
+         .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default());
 
     let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib"));
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
@@ -501,6 +538,49 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo) {
     if builder.config.rust_verify_llvm_ir {
         cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
     }
+
+    // Pass down configuration from the LLVM build into the build of
+    // librustc_llvm and librustc_codegen_llvm.
+    //
+    // Note that this is disabled if LLVM itself is disabled or we're in a check
+    // build, where if we're in a check build there's no need to build all of
+    // LLVM and such.
+    if builder.config.llvm_enabled() && builder.kind != Kind::Check {
+        if builder.is_rust_llvm(target) {
+            cargo.env("LLVM_RUSTLLVM", "1");
+        }
+        let llvm_config = builder.ensure(native::Llvm { target });
+        cargo.env("LLVM_CONFIG", &llvm_config);
+        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 {
+            cargo.env("LLVM_LINKER_FLAGS", s);
+        }
+        // Building with a static libstdc++ is only supported on linux right now,
+        // not for MSVC or macOS
+        if builder.config.llvm_static_stdcpp &&
+           !target.contains("freebsd") &&
+           !target.contains("windows") &&
+           !target.contains("apple") {
+            let file = compiler_file(builder,
+                                     builder.cxx(target).unwrap(),
+                                     target,
+                                     "libstdc++.a");
+            cargo.env("LLVM_STATIC_STDCPP", file);
+        }
+        if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
+            cargo.env("LLVM_LINK_SHARED", "1");
+        }
+        if builder.config.llvm_use_libcxx {
+            cargo.env("LLVM_USE_LIBCXX", "1");
+        }
+        if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
+            cargo.env("LLVM_NDEBUG", "1");
+        }
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -537,215 +617,6 @@ impl Step for RustcLink {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct CodegenBackend {
-    pub compiler: Compiler,
-    pub target: Interned<String>,
-    pub backend: Interned<String>,
-}
-
-impl Step for CodegenBackend {
-    type Output = ();
-    const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("rustc_codegen_llvm")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        let backend = run.builder.config.rust_codegen_backends.get(0);
-        let backend = backend.cloned().unwrap_or_else(|| {
-            INTERNER.intern_str("llvm")
-        });
-        run.builder.ensure(CodegenBackend {
-            compiler: run.builder.compiler(run.builder.top_stage, run.host),
-            target: run.target,
-            backend,
-        });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        let compiler = self.compiler;
-        let target = self.target;
-        let backend = self.backend;
-
-        builder.ensure(Rustc { compiler, target });
-
-        if builder.config.keep_stage.contains(&compiler.stage) {
-            builder.info("Warning: Using a potentially old codegen backend. \
-                This may not behave well.");
-            // Codegen backends are linked separately from this step today, so we don't do
-            // anything here.
-            return;
-        }
-
-        let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
-        if compiler_to_use != compiler {
-            builder.ensure(CodegenBackend {
-                compiler: compiler_to_use,
-                target,
-                backend,
-            });
-            return;
-        }
-
-        let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
-
-        let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build");
-        cargo.arg("--manifest-path")
-            .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
-        rustc_cargo_env(builder, &mut cargo);
-
-        let features = build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
-        cargo.arg("--features").arg(features);
-
-        let tmp_stamp = out_dir.join(".tmp.stamp");
-
-        let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false);
-        if builder.config.dry_run {
-            return;
-        }
-        let mut files = files.into_iter()
-            .filter(|f| {
-                let filename = f.file_name().unwrap().to_str().unwrap();
-                is_dylib(filename) && filename.contains("rustc_codegen_llvm-")
-            });
-        let codegen_backend = match files.next() {
-            Some(f) => f,
-            None => panic!("no dylibs built for codegen backend?"),
-        };
-        if let Some(f) = files.next() {
-            panic!("codegen backend built two dylibs:\n{}\n{}",
-                   codegen_backend.display(),
-                   f.display());
-        }
-        let stamp = codegen_backend_stamp(builder, compiler, target, backend);
-        let codegen_backend = codegen_backend.to_str().unwrap();
-        t!(fs::write(&stamp, &codegen_backend));
-    }
-}
-
-pub fn build_codegen_backend(builder: &Builder<'_>,
-                             cargo: &mut Cargo,
-                             compiler: &Compiler,
-                             target: Interned<String>,
-                             backend: Interned<String>) -> String {
-    match &*backend {
-        "llvm" => {
-            // Build LLVM for our target. This will implicitly build the
-            // host LLVM if necessary.
-            let llvm_config = builder.ensure(native::Llvm {
-                target,
-            });
-
-            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) {
-                cargo.env("LLVM_RUSTLLVM", "1");
-            }
-
-            cargo.env("LLVM_CONFIG", &llvm_config);
-            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 {
-                cargo.env("LLVM_LINKER_FLAGS", s);
-            }
-            // Building with a static libstdc++ is only supported on linux and mingw right now,
-            // not for MSVC or macOS
-            if builder.config.llvm_static_stdcpp &&
-               !target.contains("freebsd") &&
-               !target.contains("msvc") &&
-               !target.contains("apple") {
-                let file = compiler_file(builder,
-                                         builder.cxx(target).unwrap(),
-                                         target,
-                                         "libstdc++.a");
-                cargo.env("LLVM_STATIC_STDCPP", file);
-            }
-            if builder.config.llvm_link_shared || builder.config.llvm_thin_lto {
-                cargo.env("LLVM_LINK_SHARED", "1");
-            }
-            if builder.config.llvm_use_libcxx {
-                cargo.env("LLVM_USE_LIBCXX", "1");
-            }
-            if builder.config.llvm_optimize && !builder.config.llvm_release_debuginfo {
-                cargo.env("LLVM_NDEBUG", "1");
-            }
-        }
-        _ => panic!("unknown backend: {}", backend),
-    }
-    String::new()
-}
-
-/// Creates the `codegen-backends` folder for a compiler that's about to be
-/// assembled as a complete compiler.
-///
-/// This will take the codegen artifacts produced by `compiler` and link them
-/// into an appropriate location for `target_compiler` to be a functional
-/// compiler.
-fn copy_codegen_backends_to_sysroot(builder: &Builder<'_>,
-                                    compiler: Compiler,
-                                    target_compiler: Compiler) {
-    let target = target_compiler.host;
-
-    // Note that this step is different than all the other `*Link` steps in
-    // that it's not assembling a bunch of libraries but rather is primarily
-    // moving the codegen backend into place. The codegen backend of rustc is
-    // not linked into the main compiler by default but is rather dynamically
-    // selected at runtime for inclusion.
-    //
-    // Here we're looking for the output dylib of the `CodegenBackend` step and
-    // we're copying that into the `codegen-backends` folder.
-    let dst = builder.sysroot_codegen_backends(target_compiler);
-    t!(fs::create_dir_all(&dst));
-
-    if builder.config.dry_run {
-        return;
-    }
-
-    for backend in builder.config.rust_codegen_backends.iter() {
-        let stamp = codegen_backend_stamp(builder, compiler, target, *backend);
-        let dylib = t!(fs::read_to_string(&stamp));
-        let file = Path::new(&dylib);
-        let filename = file.file_name().unwrap().to_str().unwrap();
-        // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so`
-        let target_filename = {
-            let dash = filename.find('-').unwrap();
-            let dot = filename.find('.').unwrap();
-            format!("{}-{}{}",
-                    &filename[..dash],
-                    backend,
-                    &filename[dot..])
-        };
-        builder.copy(&file, &dst.join(target_filename));
-    }
-}
-
-fn copy_lld_to_sysroot(builder: &Builder<'_>,
-                       target_compiler: Compiler,
-                       lld_install_root: &Path) {
-    let target = target_compiler.host;
-
-    let dst = builder.sysroot_libdir(target_compiler, target)
-        .parent()
-        .unwrap()
-        .join("bin");
-    t!(fs::create_dir_all(&dst));
-
-    let src_exe = exe("lld", &target);
-    let dst_exe = exe("rust-lld", &target);
-    // we prepend this bin directory to the user PATH when linking Rust binaries. To
-    // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
-    builder.copy(&lld_install_root.join("bin").join(&src_exe), &dst.join(&dst_exe));
-}
-
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
 pub fn libstd_stamp(
@@ -766,16 +637,6 @@ pub fn librustc_stamp(
     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp")
 }
 
-/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
-/// compiler for the specified target and backend.
-fn codegen_backend_stamp(builder: &Builder<'_>,
-                         compiler: Compiler,
-                         target: Interned<String>,
-                         backend: Interned<String>) -> PathBuf {
-    builder.cargo_out(compiler, Mode::Codegen, target)
-        .join(format!(".librustc_codegen_llvm-{}.stamp", backend))
-}
-
 pub fn compiler_file(
     builder: &Builder<'_>,
     compiler: &Path,
@@ -879,13 +740,6 @@ impl Step for Assemble {
             compiler: build_compiler,
             target: target_compiler.host,
         });
-        for &backend in builder.config.rust_codegen_backends.iter() {
-            builder.ensure(CodegenBackend {
-                compiler: build_compiler,
-                target: target_compiler.host,
-                backend,
-            });
-        }
 
         let lld_install = if builder.config.lld_enabled {
             Some(builder.ensure(native::Lld {
@@ -911,13 +765,19 @@ impl Step for Assemble {
             }
         }
 
-        copy_codegen_backends_to_sysroot(builder,
-                                         build_compiler,
-                                         target_compiler);
+        let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
         if let Some(lld_install) = lld_install {
-            copy_lld_to_sysroot(builder, target_compiler, &lld_install);
+            let src_exe = exe("lld", &target_compiler.host);
+            let dst_exe = exe("rust-lld", &target_compiler.host);
+            // we prepend this bin directory to the user PATH when linking Rust binaries. To
+            // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`.
+            let dst = libdir.parent().unwrap().join("bin");
+            t!(fs::create_dir_all(&dst));
+            builder.copy(&lld_install.join("bin").join(&src_exe), &dst.join(&dst_exe));
         }
 
+        // Ensure that `libLLVM.so` ends up in the newly build compiler directory,
+        // so that it can be found when the newly built `rustc` is run.
         dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot);
 
         // Link the compiler binary itself into place
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 0c03b95c7b2..5f2ef01bd5c 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -105,7 +105,6 @@ pub struct Config {
     pub rust_optimize_tests: bool,
     pub rust_dist_src: bool,
     pub rust_codegen_backends: Vec<Interned<String>>,
-    pub rust_codegen_backends_dir: String,
     pub rust_verify_llvm_ir: bool,
     pub rust_remap_debuginfo: bool,
 
@@ -316,7 +315,6 @@ struct Rust {
     dist_src: Option<bool>,
     save_toolstates: Option<String>,
     codegen_backends: Option<Vec<String>>,
-    codegen_backends_dir: Option<String>,
     lld: Option<bool>,
     llvm_tools: Option<bool>,
     lldb: Option<bool>,
@@ -372,7 +370,6 @@ impl Config {
         config.ignore_git = false;
         config.rust_dist_src = true;
         config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
-        config.rust_codegen_backends_dir = "codegen-backends".to_owned();
         config.deny_warnings = true;
         config.missing_tools = false;
 
@@ -575,8 +572,6 @@ impl Config {
                     .collect();
             }
 
-            set(&mut config.rust_codegen_backends_dir, rust.codegen_backends_dir.clone());
-
             config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
             config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
         }
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index bb6041d7f31..7cfc5385e21 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -59,13 +59,13 @@ o("full-tools", None, "enable all tools")
 o("lld", "rust.lld", "build lld")
 o("lldb", "rust.lldb", "build lldb")
 o("missing-tools", "dist.missing-tools", "allow failures when building tools")
-o("use-libcxx", "llvm.use_libcxx", "build LLVM with libc++")
+o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++")
 
 o("cflags", "llvm.cflags", "build LLVM with these extra compiler flags")
 o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags")
 o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags")
 
-o("llvm-libunwind", "rust.llvm_libunwind", "use LLVM libunwind")
+o("llvm-libunwind", "rust.llvm-libunwind", "use LLVM libunwind")
 
 # Optimization and debugging options. These may be overridden by the release
 # channel, etc.
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index d0c9e0dbaf4..02533944fc2 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -498,16 +498,6 @@ impl Step for Rustc {
                 }
             }
 
-            // Copy over the codegen backends
-            let backends_src = builder.sysroot_codegen_backends(compiler);
-            let backends_rel = backends_src.strip_prefix(&src).unwrap()
-                .strip_prefix(builder.sysroot_libdir_relative(compiler)).unwrap();
-            // Don't use custom libdir here because ^lib/ will be resolved again with installer
-            let backends_dst = image.join("lib").join(&backends_rel);
-
-            t!(fs::create_dir_all(&backends_dst));
-            builder.cp_r(&backends_src, &backends_dst);
-
             // Copy libLLVM.so to the lib dir as well, if needed. While not
             // technically needed by rustc itself it's needed by lots of other
             // components like the llvm tools and LLD. LLD is included below and
@@ -2134,6 +2124,10 @@ impl Step for HashSign {
 
 // Maybe add libLLVM.so to the lib-dir. It will only have been built if
 // LLVM tools are linked dynamically.
+//
+// We add this to both the libdir of the rustc binary itself (for it to load at
+// runtime) and also to the target directory so it can find it at link-time.
+//
 // Note: This function does no yet support Windows but we also don't support
 //       linking LLVM tools dynamically on Windows yet.
 pub fn maybe_install_llvm_dylib(builder: &Builder<'_>,
@@ -2142,13 +2136,19 @@ pub fn maybe_install_llvm_dylib(builder: &Builder<'_>,
     let src_libdir = builder
         .llvm_out(target)
         .join("lib");
-    let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib");
-    t!(fs::create_dir_all(&dst_libdir));
+    let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
+    let dst_libdir2 = sysroot.join(builder.sysroot_libdir_relative(Compiler {
+        stage: 1,
+        host: target,
+    }));
+    t!(fs::create_dir_all(&dst_libdir1));
+    t!(fs::create_dir_all(&dst_libdir2));
 
     if target.contains("apple-darwin") {
         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
         if llvm_dylib_path.exists() {
-            builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
+            builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
+            builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
         }
         return
     }
@@ -2164,7 +2164,8 @@ pub fn maybe_install_llvm_dylib(builder: &Builder<'_>,
         });
 
 
-        builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
+        builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
+        builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
     }
 }
 
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 4ee8cd2485c..608cee0a80b 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -433,7 +433,7 @@ impl Step for Std {
         builder.info(&format!("Documenting stage{} std ({})", stage, target));
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
-        let compiler = builder.compiler_for(stage, builder.config.build, target);
+        let compiler = builder.compiler(stage, builder.config.build);
 
         builder.ensure(compile::Std { compiler, target });
         let out_dir = builder.stage_out(compiler, Mode::Std)
@@ -541,7 +541,7 @@ impl Step for Rustc {
         // Build cargo command.
         let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
         cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden");
-        compile::rustc_cargo(builder, &mut cargo);
+        compile::rustc_cargo(builder, &mut cargo, target);
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
         cargo.arg("--no-deps");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 1f4a4f923e0..080bef6853a 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -500,6 +500,9 @@ impl Build {
         if self.config.jemalloc {
             features.push_str("jemalloc");
         }
+        if self.config.llvm_enabled() {
+            features.push_str(" llvm");
+        }
         features
     }
 
@@ -805,12 +808,8 @@ impl Build {
                                                        .and_then(|c| c.linker.as_ref()) {
             Some(linker)
         } else if target != self.config.build &&
-                  !target.contains("msvc") &&
-                  !target.contains("emscripten") &&
-                  !target.contains("wasm32") &&
-                  !target.contains("nvptx") &&
-                  !target.contains("fortanix") &&
-                  !target.contains("fuchsia") {
+                  util::use_host_linker(&target) &&
+                  !target.contains("msvc") {
             Some(self.cc(target))
         } else {
             None
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index a858ed42bad..f3b2a73d3c5 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1773,7 +1773,7 @@ impl Step for Crate {
             }
             Mode::Rustc => {
                 builder.ensure(compile::Rustc { compiler, target });
-                compile::rustc_cargo(builder, &mut cargo);
+                compile::rustc_cargo(builder, &mut cargo, target);
             }
             _ => panic!("can only test libraries"),
         };
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index a6d9ef38e57..a90f69d597d 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -13,13 +13,13 @@ use std::env;
 // Each cycle is 42 days long (6 weeks); the last week is 35..=42 then.
 const BETA_WEEK_START: u64 = 35;
 
-#[cfg(linux)]
+#[cfg(target_os = "linux")]
 const OS: Option<&str> = Some("linux");
 
 #[cfg(windows)]
 const OS: Option<&str> = Some("windows");
 
-#[cfg(all(not(linux), not(windows)))]
+#[cfg(all(not(target_os = "linux"), not(windows)))]
 const OS: Option<&str> = None;
 
 type ToolstateData = HashMap<Box<str>, ToolState>;
@@ -379,7 +379,7 @@ fn change_toolstate(
     let mut regressed = false;
     for repo_state in old_toolstate {
         let tool = &repo_state.tool;
-        let state = if cfg!(linux) {
+        let state = if cfg!(target_os = "linux") {
             &repo_state.linux
         } else if cfg!(windows) {
             &repo_state.windows
@@ -413,7 +413,7 @@ fn change_toolstate(
     let history_path = format!("rust-toolstate/history/{}.tsv", OS.expect("linux/windows only"));
     let mut file = t!(fs::read_to_string(&history_path));
     let end_of_first_line = file.find('\n').unwrap();
-    file.insert_str(end_of_first_line, &format!("{}\t{}\n", commit, toolstate_serialized));
+    file.insert_str(end_of_first_line, &format!("\n{}\t{}", commit.trim(), toolstate_serialized));
     t!(fs::write(&history_path, file));
 }
 
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 6f8a6308745..6824b7a58c4 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -15,6 +15,7 @@ use build_helper::t;
 
 use crate::config::Config;
 use crate::builder::Builder;
+use crate::cache::Interned;
 
 /// Returns the `name` as the filename of a static library for `target`.
 pub fn staticlib(name: &str, target: &str) -> String {
@@ -306,3 +307,15 @@ pub fn forcing_clang_based_tests() -> bool {
         false
     }
 }
+
+pub fn use_host_linker(target: &Interned<String>) -> bool {
+    // FIXME: this information should be gotten by checking the linker flavor
+    // of the rustc target
+    !(
+        target.contains("emscripten") ||
+        target.contains("wasm32") ||
+        target.contains("nvptx") ||
+        target.contains("fortanix") ||
+        target.contains("fuchsia")
+    )
+}
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 38d1d2baf25..73c3a964f53 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -44,8 +44,13 @@ fi
 # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable`
 #        either automatically or manually.
 export RUST_RELEASE_CHANNEL=nightly
+
+# Always set the release channel for bootstrap; this is normally not important (i.e., only dist
+# builds would seem to matter) but in practice bootstrap wants to know whether we're targeting
+# master, beta, or stable with a build to determine whether to run some checks (notably toolstate).
+RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
+
 if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
-  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 9e843aeb4df083522c7277179bbaa25d0507731
+Subproject d8dfe1b005c03584cd7adc4bfb72b005e7e8474
diff --git a/src/liballoc/benches/string.rs b/src/liballoc/benches/string.rs
index 2933014cb58..599c8b16828 100644
--- a/src/liballoc/benches/string.rs
+++ b/src/liballoc/benches/string.rs
@@ -122,3 +122,43 @@ fn bench_to_string(b: &mut Bencher) {
              Lorem ipsum dolor sit amet, consectetur. ";
     b.iter(|| s.to_string())
 }
+
+#[bench]
+fn bench_insert_char_short(b: &mut Bencher) {
+    let s = "Hello, World!";
+    b.iter(|| {
+        let mut x = String::from(s);
+        black_box(&mut x).insert(6, black_box(' '));
+        x
+    })
+}
+
+#[bench]
+fn bench_insert_char_long(b: &mut Bencher) {
+    let s = "Hello, World!";
+    b.iter(|| {
+        let mut x = String::from(s);
+        black_box(&mut x).insert(6, black_box('❤'));
+        x
+    })
+}
+
+#[bench]
+fn bench_insert_str_short(b: &mut Bencher) {
+    let s = "Hello, World!";
+    b.iter(|| {
+        let mut x = String::from(s);
+        black_box(&mut x).insert_str(6, black_box(" "));
+        x
+    })
+}
+
+#[bench]
+fn bench_insert_str_long(b: &mut Bencher) {
+    let s = "Hello, World!";
+    b.iter(|| {
+        let mut x = String::from(s);
+        black_box(&mut x).insert_str(6, black_box(" rustic "));
+        x
+    })
+}
diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs
index a0c9263673d..5a6d4ee2aea 100644
--- a/src/liballoc/collections/linked_list.rs
+++ b/src/liballoc/collections/linked_list.rs
@@ -275,6 +275,7 @@ impl<T> LinkedList<T> {
     /// let list: LinkedList<u32> = LinkedList::new();
     /// ```
     #[inline]
+    #[rustc_const_stable(feature = "const_linked_list_new", since = "1.32.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn new() -> Self {
         LinkedList {
@@ -808,7 +809,21 @@ impl<T> LinkedList<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
     fn drop(&mut self) {
-        while let Some(_) = self.pop_front_node() {}
+        struct DropGuard<'a, T>(&'a mut LinkedList<T>);
+
+        impl<'a, T> Drop for DropGuard<'a, T> {
+            fn drop(&mut self) {
+                // Continue the same loop we do below. This only runs when a destructor has
+                // panicked. If another one panics this will abort.
+                while let Some(_) = self.0.pop_front_node() {}
+            }
+        }
+
+        while let Some(node) = self.pop_front_node() {
+            let guard = DropGuard(self);
+            drop(node);
+            mem::forget(guard);
+        }
     }
 }
 
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 7795083e058..913613653a6 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -144,11 +144,23 @@ impl<T: Clone> Clone for VecDeque<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
     fn drop(&mut self) {
+        /// Runs the destructor for all items in the slice when it gets dropped (normally or
+        /// during unwinding).
+        struct Dropper<'a, T>(&'a mut [T]);
+
+        impl<'a, T> Drop for Dropper<'a, T> {
+            fn drop(&mut self) {
+                unsafe {
+                    ptr::drop_in_place(self.0);
+                }
+            }
+        }
+
         let (front, back) = self.as_mut_slices();
         unsafe {
+            let _back_dropper = Dropper(back);
             // use drop for [T]
             ptr::drop_in_place(front);
-            ptr::drop_in_place(back);
         }
         // RawVec handles deallocation
     }
@@ -2809,7 +2821,22 @@ impl<'a, T> IntoIterator for &'a mut VecDeque<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A> Extend<A> for VecDeque<A> {
     fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
-        iter.into_iter().for_each(move |elt| self.push_back(elt));
+        // This function should be the moral equivalent of:
+        //
+        //      for item in iter.into_iter() {
+        //          self.push_back(item);
+        //      }
+        let mut iter = iter.into_iter();
+        while let Some(element) = iter.next() {
+            if self.len() == self.capacity() {
+                let (lower, _) = iter.size_hint();
+                self.reserve(lower.saturating_add(1));
+            }
+
+            let head = self.head;
+            self.head = self.wrap_add(self.head, 1);
+            unsafe { self.buffer_write(head, element); }
+        }
     }
 }
 
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index ddfa6797a57..be46e632be4 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(const_if_match)]
 #![feature(cow_is_borrowed)]
 #![feature(dispatch_from_dyn)]
 #![feature(core_intrinsics)]
@@ -116,8 +117,6 @@
 #![feature(unsize)]
 #![feature(unsized_locals)]
 #![feature(allocator_internals)]
-#![cfg_attr(bootstrap, feature(on_unimplemented))]
-#![feature(rustc_const_unstable)]
 #![feature(slice_partition_dedup)]
 #![feature(maybe_uninit_extra, maybe_uninit_slice)]
 #![feature(alloc_layout_extra)]
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index ee75fc288fe..3201c702abb 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -52,15 +52,12 @@ impl<T, A: Alloc> RawVec<T, A> {
     /// Like `new`, but parameterized over the choice of allocator for
     /// the returned `RawVec`.
     pub const fn new_in(a: A) -> Self {
-        // `!0` is `usize::MAX`. This branch should be stripped at compile time.
-        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`:
-        //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
+        let cap = if mem::size_of::<T>() == 0 { core::usize::MAX } else { 0 };
 
         // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation".
         RawVec {
             ptr: Unique::empty(),
-            // FIXME(mark-i-m): use `cap` when ifs are allowed in const
-            cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
+            cap,
             a,
         }
     }
@@ -132,19 +129,7 @@ impl<T> RawVec<T, Global> {
     /// `RawVec` with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     pub const fn new() -> Self {
-        // FIXME(Centril): Reintegrate this with `fn new_in` when we can.
-
-        // `!0` is `usize::MAX`. This branch should be stripped at compile time.
-        // FIXME(mark-i-m): use this line when `if`s are allowed in `const`:
-        //let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
-
-        // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation".
-        RawVec {
-            ptr: Unique::empty(),
-            // FIXME(mark-i-m): use `cap` when ifs are allowed in const
-            cap: [0, !0][(mem::size_of::<T>() == 0) as usize],
-            a: Global,
-        }
+        Self::new_in(Global)
     }
 
     /// Creates a `RawVec` (on the system heap) with exactly the
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 1ff1c3c834f..42a278de98b 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -1836,7 +1836,7 @@ impl<T: ?Sized> Weak<T> {
     /// If `self` was created using [`Weak::new`], this will return 0.
     ///
     /// [`Weak::new`]: #method.new
-    #[unstable(feature = "weak_counts", issue = "57977")]
+    #[stable(feature = "weak_counts", since = "1.41.0")]
     pub fn strong_count(&self) -> usize {
         if let Some(inner) = self.inner() {
             inner.strong()
@@ -1847,20 +1847,16 @@ impl<T: ?Sized> Weak<T> {
 
     /// Gets the number of `Weak` pointers pointing to this allocation.
     ///
-    /// If `self` was created using [`Weak::new`], this will return `None`. If
-    /// not, the returned value is at least 1, since `self` still points to the
-    /// allocation.
-    ///
-    /// [`Weak::new`]: #method.new
-    #[unstable(feature = "weak_counts", issue = "57977")]
-    pub fn weak_count(&self) -> Option<usize> {
+    /// If no strong pointers remain, this will return zero.
+    #[stable(feature = "weak_counts", since = "1.41.0")]
+    pub fn weak_count(&self) -> usize {
         self.inner().map(|inner| {
             if inner.strong() > 0 {
                 inner.weak() - 1  // subtract the implicit weak ptr
             } else {
-                inner.weak()
+                0
             }
-        })
+        }).unwrap_or(0)
     }
 
     /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`
diff --git a/src/liballoc/rc/tests.rs b/src/liballoc/rc/tests.rs
index 6fd3f909357..bf5c85a5c59 100644
--- a/src/liballoc/rc/tests.rs
+++ b/src/liballoc/rc/tests.rs
@@ -114,28 +114,28 @@ fn test_weak_count() {
 
 #[test]
 fn weak_counts() {
-    assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
+    assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
     assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
 
     let a = Rc::new(0);
     let w = Rc::downgrade(&a);
     assert_eq!(Weak::strong_count(&w), 1);
-    assert_eq!(Weak::weak_count(&w), Some(1));
+    assert_eq!(Weak::weak_count(&w), 1);
     let w2 = w.clone();
     assert_eq!(Weak::strong_count(&w), 1);
-    assert_eq!(Weak::weak_count(&w), Some(2));
+    assert_eq!(Weak::weak_count(&w), 2);
     assert_eq!(Weak::strong_count(&w2), 1);
-    assert_eq!(Weak::weak_count(&w2), Some(2));
+    assert_eq!(Weak::weak_count(&w2), 2);
     drop(w);
     assert_eq!(Weak::strong_count(&w2), 1);
-    assert_eq!(Weak::weak_count(&w2), Some(1));
+    assert_eq!(Weak::weak_count(&w2), 1);
     let a2 = a.clone();
     assert_eq!(Weak::strong_count(&w2), 2);
-    assert_eq!(Weak::weak_count(&w2), Some(1));
+    assert_eq!(Weak::weak_count(&w2), 1);
     drop(a2);
     drop(a);
     assert_eq!(Weak::strong_count(&w2), 0);
-    assert_eq!(Weak::weak_count(&w2), Some(1));
+    assert_eq!(Weak::weak_count(&w2), 0);
     drop(w2);
 }
 
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index f7dff4c21f7..f880f5915a3 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -367,6 +367,7 @@ impl String {
     /// let s = String::new();
     /// ```
     #[inline]
+    #[rustc_const_stable(feature = "const_string_new", since = "1.32.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn new() -> String {
         String { vec: Vec::new() }
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 19b0086fa33..a99564c0dac 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -12,7 +12,7 @@ use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 use core::borrow;
 use core::fmt;
-use core::cmp::{self, Ordering};
+use core::cmp::Ordering;
 use core::iter;
 use core::intrinsics::abort;
 use core::mem::{self, align_of, align_of_val, size_of_val};
@@ -1529,7 +1529,7 @@ impl<T: ?Sized> Weak<T> {
     /// If `self` was created using [`Weak::new`], this will return 0.
     ///
     /// [`Weak::new`]: #method.new
-    #[unstable(feature = "weak_counts", issue = "57977")]
+    #[stable(feature = "weak_counts", since = "1.41.0")]
     pub fn strong_count(&self) -> usize {
         if let Some(inner) = self.inner() {
             inner.strong.load(SeqCst)
@@ -1541,9 +1541,8 @@ impl<T: ?Sized> Weak<T> {
     /// Gets an approximation of the number of `Weak` pointers pointing to this
     /// allocation.
     ///
-    /// If `self` was created using [`Weak::new`], this will return 0. If not,
-    /// the returned value is at least 1, since `self` still points to the
-    /// allocation.
+    /// If `self` was created using [`Weak::new`], or if there are no remaining
+    /// strong pointers, this will return 0.
     ///
     /// # Accuracy
     ///
@@ -1552,31 +1551,22 @@ impl<T: ?Sized> Weak<T> {
     /// `Weak`s pointing to the same allocation.
     ///
     /// [`Weak::new`]: #method.new
-    #[unstable(feature = "weak_counts", issue = "57977")]
-    pub fn weak_count(&self) -> Option<usize> {
-        // Due to the implicit weak pointer added when any strong pointers are
-        // around, we cannot implement `weak_count` correctly since it
-        // necessarily requires accessing the strong count and weak count in an
-        // unsynchronized fashion. So this version is a bit racy.
+    #[stable(feature = "weak_counts", since = "1.41.0")]
+    pub fn weak_count(&self) -> usize {
         self.inner().map(|inner| {
-            let strong = inner.strong.load(SeqCst);
             let weak = inner.weak.load(SeqCst);
+            let strong = inner.strong.load(SeqCst);
             if strong == 0 {
-                // If the last `Arc` has *just* been dropped, it might not yet
-                // have removed the implicit weak count, so the value we get
-                // here might be 1 too high.
-                weak
+                0
             } else {
-                // As long as there's still at least 1 `Arc` around, subtract
-                // the implicit weak pointer.
-                // Note that the last `Arc` might get dropped between the 2
-                // loads we do above, removing the implicit weak pointer. This
-                // means that the value might be 1 too low here. In order to not
-                // return 0 here (which would happen if we're the only weak
-                // pointer), we guard against that specifically.
-                cmp::max(1, weak - 1)
+                // Since we observed that there was at least one strong pointer
+                // after reading the weak count, we know that the implicit weak
+                // reference (present whenever any strong references are alive)
+                // was still around when we observed the weak count, and can
+                // therefore safely subtract it.
+                weak - 1
             }
-        })
+        }).unwrap_or(0)
     }
 
     /// Returns `None` when the pointer is dangling and there is no allocated `ArcInner`,
diff --git a/src/liballoc/sync/tests.rs b/src/liballoc/sync/tests.rs
index 9ddba495b7e..8f516129cd0 100644
--- a/src/liballoc/sync/tests.rs
+++ b/src/liballoc/sync/tests.rs
@@ -62,28 +62,28 @@ fn test_arc_get_mut() {
 
 #[test]
 fn weak_counts() {
-    assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
+    assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
     assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
 
     let a = Arc::new(0);
     let w = Arc::downgrade(&a);
     assert_eq!(Weak::strong_count(&w), 1);
-    assert_eq!(Weak::weak_count(&w), Some(1));
+    assert_eq!(Weak::weak_count(&w), 1);
     let w2 = w.clone();
     assert_eq!(Weak::strong_count(&w), 1);
-    assert_eq!(Weak::weak_count(&w), Some(2));
+    assert_eq!(Weak::weak_count(&w), 2);
     assert_eq!(Weak::strong_count(&w2), 1);
-    assert_eq!(Weak::weak_count(&w2), Some(2));
+    assert_eq!(Weak::weak_count(&w2), 2);
     drop(w);
     assert_eq!(Weak::strong_count(&w2), 1);
-    assert_eq!(Weak::weak_count(&w2), Some(1));
+    assert_eq!(Weak::weak_count(&w2), 1);
     let a2 = a.clone();
     assert_eq!(Weak::strong_count(&w2), 2);
-    assert_eq!(Weak::weak_count(&w2), Some(1));
+    assert_eq!(Weak::weak_count(&w2), 1);
     drop(a2);
     drop(a);
     assert_eq!(Weak::strong_count(&w2), 0);
-    assert_eq!(Weak::weak_count(&w2), Some(1));
+    assert_eq!(Weak::weak_count(&w2), 0);
     drop(w2);
 }
 
diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs
index daa49c48c6a..54a77d643cb 100644
--- a/src/liballoc/tests/linked_list.rs
+++ b/src/liballoc/tests/linked_list.rs
@@ -1,4 +1,5 @@
 use std::collections::LinkedList;
+use std::panic::catch_unwind;
 
 #[test]
 fn test_basic() {
@@ -529,3 +530,109 @@ fn drain_filter_complex() {
         assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
     }
 }
+
+
+#[test]
+fn test_drop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    drop(ring);
+
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+
+    drop(ring.pop_back());
+    drop(ring.pop_front());
+    assert_eq!(unsafe { DROPS }, 2);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+    static mut DROPS: i32 = 0;
+    struct Elem;
+    impl Drop for Elem {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+        }
+    }
+
+    let mut ring = LinkedList::new();
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.push_back(Elem);
+    ring.push_front(Elem);
+    ring.clear();
+    assert_eq!(unsafe { DROPS }, 4);
+
+    drop(ring);
+    assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = LinkedList::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs
index ebcc8320171..1ab3694a3ca 100644
--- a/src/liballoc/tests/vec_deque.rs
+++ b/src/liballoc/tests/vec_deque.rs
@@ -2,6 +2,7 @@ use std::collections::TryReserveError::*;
 use std::collections::{vec_deque::Drain, VecDeque};
 use std::fmt::Debug;
 use std::mem::size_of;
+use std::panic::catch_unwind;
 use std::{isize, usize};
 
 use crate::hash;
@@ -710,6 +711,39 @@ fn test_drop_clear() {
 }
 
 #[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = VecDeque::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
+
+#[test]
 fn test_reserve_grow() {
     // test growth path A
     // [T o o H] -> [T o o H . . . . ]
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 6e165ccb919..19c95e20793 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -315,6 +315,7 @@ impl<T> Vec<T> {
     /// let mut vec: Vec<i32> = Vec::new();
     /// ```
     #[inline]
+    #[rustc_const_stable(feature = "const_vec_new", since = "1.32.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn new() -> Vec<T> {
         Vec {
@@ -1075,7 +1076,22 @@ impl<T> Vec<T> {
     pub fn retain<F>(&mut self, mut f: F)
         where F: FnMut(&T) -> bool
     {
-        self.drain_filter(|x| !f(x));
+        let len = self.len();
+        let mut del = 0;
+        {
+            let v = &mut **self;
+
+            for i in 0..len {
+                if !f(&v[i]) {
+                    del += 1;
+                } else if del > 0 {
+                    v.swap(i - del, i);
+                }
+            }
+        }
+        if del > 0 {
+            self.truncate(len - del);
+        }
     }
 
     /// Removes all but the first of consecutive elements in the vector that resolve to the same
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 5c24e3d8f5d..cb476acfb3a 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -100,6 +100,7 @@ impl Layout {
     /// This function is unsafe as it does not verify the preconditions from
     /// [`Layout::from_size_align`](#method.from_size_align).
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index 466750fc7d2..882c4a53faf 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -423,13 +423,9 @@ impl TypeId {
     /// assert_eq!(is_string(&"cookie monster".to_string()), true);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature="const_type_id")]
+    #[rustc_const_unstable(feature="const_type_id", issue = "41875")]
     pub const fn of<T: ?Sized + 'static>() -> TypeId {
         TypeId {
-            #[cfg(bootstrap)]
-            // SAFETY: going away soon
-            t: unsafe { intrinsics::type_id::<T>() },
-            #[cfg(not(bootstrap))]
             t: intrinsics::type_id::<T>(),
         }
     }
@@ -461,7 +457,7 @@ impl TypeId {
 /// );
 /// ```
 #[stable(feature = "type_name", since = "1.38.0")]
-#[rustc_const_unstable(feature = "const_type_name")]
+#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
 pub const fn type_name<T: ?Sized>() -> &'static str {
     intrinsics::type_name::<T>()
 }
@@ -474,7 +470,7 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
 ///
 /// This is intended for diagnostic use. The exact contents and format of the
 /// string are not specified, other than being a best-effort description of the
-/// type. For example, `type_name_of::<Option<String>>(None)` could return the
+/// type. For example, `type_name_of::<Option<String>>(None)` could return
 /// `"Option<String>"` or `"std::option::Option<std::string::String>"`, but not
 /// `"foobar"`. In addition, the output may change between versions of the
 /// compiler.
@@ -499,7 +495,7 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
 /// println!("{}", type_name_of_val(&y));
 /// ```
 #[unstable(feature = "type_name_of_val", issue = "66359")]
-#[rustc_const_unstable(feature = "const_type_name")]
+#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
 pub const fn type_name_of_val<T: ?Sized>(val: &T) -> &'static str {
     let _ = val;
     type_name::<T>()
diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs
index 6932c7fe221..570fc4ab933 100644
--- a/src/libcore/benches/lib.rs
+++ b/src/libcore/benches/lib.rs
@@ -11,4 +11,5 @@ mod hash;
 mod iter;
 mod num;
 mod ops;
+mod pattern;
 mod slice;
diff --git a/src/libcore/benches/pattern.rs b/src/libcore/benches/pattern.rs
new file mode 100644
index 00000000000..a49490cec12
--- /dev/null
+++ b/src/libcore/benches/pattern.rs
@@ -0,0 +1,43 @@
+use test::black_box;
+use test::Bencher;
+
+#[bench]
+fn starts_with_char(b: &mut Bencher) {
+    let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+    b.iter(|| {
+        for _ in 0..1024 {
+            black_box(text.starts_with('k'));
+        }
+    })
+}
+
+#[bench]
+fn starts_with_str(b: &mut Bencher) {
+    let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+    b.iter(|| {
+        for _ in 0..1024 {
+            black_box(text.starts_with("k"));
+        }
+    })
+}
+
+
+#[bench]
+fn ends_with_char(b: &mut Bencher) {
+    let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+    b.iter(|| {
+        for _ in 0..1024 {
+            black_box(text.ends_with('k'));
+        }
+    })
+}
+
+#[bench]
+fn ends_with_str(b: &mut Bencher) {
+    let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
+    b.iter(|| {
+        for _ in 0..1024 {
+            black_box(text.ends_with("k"));
+        }
+    })
+}
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 03f32e72618..099e5307f64 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -324,6 +324,7 @@ impl<T> Cell<T> {
     /// let c = Cell::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_cell_new", since = "1.32.0")]
     #[inline]
     pub const fn new(value: T) -> Cell<T> {
         Cell {
@@ -469,6 +470,7 @@ impl<T: ?Sized> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")]
     pub const fn as_ptr(&self) -> *mut T {
         self.value.get()
     }
@@ -649,6 +651,7 @@ impl<T> RefCell<T> {
     /// let c = RefCell::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_refcell_new", since = "1.32.0")]
     #[inline]
     pub const fn new(value: T) -> RefCell<T> {
         RefCell {
@@ -1501,6 +1504,7 @@ impl<T> UnsafeCell<T> {
     /// let uc = UnsafeCell::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_unsafe_cell_new", since = "1.32.0")]
     #[inline]
     pub const fn new(value: T) -> UnsafeCell<T> {
         UnsafeCell { value }
@@ -1543,6 +1547,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
     pub const fn get(&self) -> *mut T {
         // We can just cast the pointer from `UnsafeCell<T>` to `T` because of
         // #[repr(transparent)]. This exploits libstd's special status, there is
diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs
index 5c63eebf595..bb6d6db57d2 100644
--- a/src/libcore/char/methods.rs
+++ b/src/libcore/char/methods.rs
@@ -911,6 +911,7 @@ impl char {
     /// assert!(!non_ascii.is_ascii());
     /// ```
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.32.0")]
     #[inline]
     pub const fn is_ascii(&self) -> bool {
         *self as u32 <= 0x7F
diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs
index 6e7a46ba62a..18f808638de 100644
--- a/src/libcore/clone.rs
+++ b/src/libcore/clone.rs
@@ -195,7 +195,7 @@ mod impls {
         bool char
     }
 
-    #[stable(feature = "never_type", since = "1.41.0")]
+    #[unstable(feature = "never_type", issue = "35121")]
     impl Clone for ! {
         #[inline]
         fn clone(&self) -> Self {
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index fd4be02e20f..4aa52a7a390 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -1141,24 +1141,24 @@ mod impls {
 
     ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
-    #[stable(feature = "never_type", since = "1.41.0")]
+    #[unstable(feature = "never_type", issue = "35121")]
     impl PartialEq for ! {
         fn eq(&self, _: &!) -> bool {
             *self
         }
     }
 
-    #[stable(feature = "never_type", since = "1.41.0")]
+    #[unstable(feature = "never_type", issue = "35121")]
     impl Eq for ! {}
 
-    #[stable(feature = "never_type", since = "1.41.0")]
+    #[unstable(feature = "never_type", issue = "35121")]
     impl PartialOrd for ! {
         fn partial_cmp(&self, _: &!) -> Option<Ordering> {
             *self
         }
     }
 
-    #[stable(feature = "never_type", since = "1.41.0")]
+    #[unstable(feature = "never_type", issue = "35121")]
     impl Ord for ! {
         fn cmp(&self, _: &!) -> Ordering {
             *self
diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs
index 5414d9ac234..959fd63df51 100644
--- a/src/libcore/convert/mod.rs
+++ b/src/libcore/convert/mod.rs
@@ -40,6 +40,8 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::fmt;
+
 mod num;
 
 #[unstable(feature = "convert_float_to_int", issue = "67057")]
@@ -99,6 +101,7 @@ pub use num::FloatToInt;
 /// assert_eq!(vec![1, 3], filtered);
 /// ```
 #[stable(feature = "convert_id", since = "1.33.0")]
+#[rustc_const_stable(feature = "const_identity", since = "1.33.0")]
 #[inline]
 pub const fn identity<T>(x: T) -> T {
     x
@@ -291,7 +294,7 @@ pub trait Into<T>: Sized {
 /// [`Into`].
 ///
 /// One should always prefer implementing `From` over [`Into`]
-/// because implementing `From` automatically provides one with a implementation of [`Into`]
+/// because implementing `From` automatically provides one with an implementation of [`Into`]
 /// thanks to the blanket implementation in the standard library.
 ///
 /// Only implement [`Into`] if a conversion to a type outside the current crate is required.
@@ -429,7 +432,9 @@ pub trait TryInto<T>: Sized {
 /// - `TryFrom<T> for U` implies [`TryInto`]`<U> for T`
 /// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
 /// is implemented and cannot fail -- the associated `Error` type for
-/// calling `T::try_from()` on a value of type `T` is [`!`].
+/// calling `T::try_from()` on a value of type `T` is [`Infallible`].
+/// When the [`!`] type is stabilized [`Infallible`] and [`!`] will be
+/// equivalent.
 ///
 /// `TryFrom<T>` can be implemented as follows:
 ///
@@ -478,6 +483,7 @@ pub trait TryInto<T>: Sized {
 /// [`TryInto`]: trait.TryInto.html
 /// [`i32::MAX`]: ../../std/i32/constant.MAX.html
 /// [`!`]: ../../std/primitive.never.html
+/// [`Infallible`]: enum.Infallible.html
 #[stable(feature = "try_from", since = "1.34.0")]
 pub trait TryFrom<T>: Sized {
     /// The type returned in the event of a conversion error.
@@ -633,9 +639,9 @@ impl AsRef<str> for str {
 // THE NO-ERROR ERROR TYPE
 ////////////////////////////////////////////////////////////////////////////////
 
-/// A type alias for [the `!` “never” type][never].
+/// The error type for errors that can never happen.
 ///
-/// `Infallible` represents types of errors that can never happen since `!` has no valid values.
+/// Since this enum has no variant, a value of this type can never actually exist.
 /// This can be useful for generic APIs that use [`Result`] and parameterize the error type,
 /// to indicate that the result is always [`Ok`].
 ///
@@ -652,10 +658,33 @@ impl AsRef<str> for str {
 /// }
 /// ```
 ///
-/// # Eventual deprecation
+/// # Future compatibility
+///
+/// This enum has the same role as [the `!` “never” type][never],
+/// which is unstable in this version of Rust.
+/// When `!` is stabilized, we plan to make `Infallible` a type alias to it:
+///
+/// ```ignore (illustrates future std change)
+/// pub type Infallible = !;
+/// ```
+///
+/// … and eventually deprecate `Infallible`.
+///
+///
+/// However there is one case where `!` syntax can be used
+/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
+/// Specifically, it is possible implementations for two different function pointer types:
+///
+/// ```
+/// trait MyTrait {}
+/// impl MyTrait for fn() -> ! {}
+/// impl MyTrait for fn() -> std::convert::Infallible {}
+/// ```
 ///
-/// Previously, `Infallible` was defined as `enum Infallible {}`.
-/// Now that it is merely a type alias to `!`, we will eventually deprecate `Infallible`.
+/// With `Infallible` being an enum, this code is valid.
+/// However when `Infallible` becomes an alias for the never type,
+/// the two `impl`s will start to overlap
+/// and therefore will be disallowed by the language’s trait coherence rules.
 ///
 /// [`Ok`]: ../result/enum.Result.html#variant.Ok
 /// [`Result`]: ../result/enum.Result.html
@@ -663,4 +692,57 @@ impl AsRef<str> for str {
 /// [`Into`]: trait.Into.html
 /// [never]: ../../std/primitive.never.html
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-pub type Infallible = !;
+#[derive(Copy)]
+pub enum Infallible {}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl Clone for Infallible {
+    fn clone(&self) -> Infallible {
+        match *self {}
+    }
+}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl fmt::Debug for Infallible {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {}
+    }
+}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl fmt::Display for Infallible {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {}
+    }
+}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl PartialEq for Infallible {
+    fn eq(&self, _: &Infallible) -> bool {
+        match *self {}
+    }
+}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl Eq for Infallible {}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl PartialOrd for Infallible {
+    fn partial_cmp(&self, _other: &Self) -> Option<crate::cmp::Ordering> {
+        match *self {}
+    }
+}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl Ord for Infallible {
+    fn cmp(&self, _other: &Self) -> crate::cmp::Ordering {
+        match *self {}
+    }
+}
+
+#[stable(feature = "convert_infallible", since = "1.34.0")]
+impl From<!> for Infallible {
+    fn from(x: !) -> Self {
+        x
+    }
+}
diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs
index 6f5ee756f58..596da6f786b 100644
--- a/src/libcore/convert/num.rs
+++ b/src/libcore/convert/num.rs
@@ -13,7 +13,6 @@ mod private {
 /// Typically doesn’t need to be used directly.
 #[unstable(feature = "convert_float_to_int", issue = "67057")]
 pub trait FloatToInt<Int>: private::Sealed + Sized {
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
     #[doc(hidden)]
     unsafe fn approx_unchecked(self) -> Int;
@@ -26,7 +25,6 @@ macro_rules! impl_float_to_int {
         $(
             #[unstable(feature = "convert_float_to_int", issue = "67057")]
             impl FloatToInt<$Int> for $Float {
-                #[cfg(not(bootstrap))]
                 #[doc(hidden)]
                 #[inline]
                 unsafe fn approx_unchecked(self) -> $Int {
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index e2f49ee25a7..793c1f124ed 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -63,7 +63,7 @@ pub mod rt {
 ///
 /// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 };
 ///
-/// println!("{}", pythagorean_triple);
+/// assert_eq!(format!("{}", pythagorean_triple), "(3, 4, 5)");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type Result = result::Result<(), Error>;
@@ -440,7 +440,7 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// println!("The origin is: {:?}", origin);
+/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
 /// ```
 ///
 /// Manually implementing:
@@ -455,28 +455,25 @@ impl Display for Arguments<'_> {
 ///
 /// impl fmt::Debug for Point {
 ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-///         write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
+///         f.debug_struct("Point")
+///          .field("x", &self.x)
+///          .field("y", &self.y)
+///          .finish()
 ///     }
 /// }
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// println!("The origin is: {:?}", origin);
+/// assert_eq!(format!("The origin is: {:?}", origin), "The origin is: Point { x: 0, y: 0 }");
 /// ```
 ///
-/// This outputs:
-///
-/// ```text
-/// The origin is: Point { x: 0, y: 0 }
-/// ```
-///
-/// There are a number of `debug_*` methods on [`Formatter`] to help you with manual
-/// implementations, such as [`debug_struct`][debug_struct].
+/// There are a number of helper methods on the [`Formatter`] struct to help you with manual
+/// implementations, such as [`debug_struct`].
 ///
 /// `Debug` implementations using either `derive` or the debug builder API
 /// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`.
 ///
-/// [debug_struct]: ../../std/fmt/struct.Formatter.html#method.debug_struct
+/// [`debug_struct`]: ../../std/fmt/struct.Formatter.html#method.debug_struct
 /// [`Formatter`]: ../../std/fmt/struct.Formatter.html
 ///
 /// Pretty-printing with `#?`:
@@ -490,17 +487,13 @@ impl Display for Arguments<'_> {
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// println!("The origin is: {:#?}", origin);
-/// ```
-///
-/// This outputs:
-///
-/// ```text
-/// The origin is: Point {
+/// assert_eq!(format!("The origin is: {:#?}", origin),
+/// "The origin is: Point {
 ///     x: 0,
-///     y: 0
-/// }
+///     y: 0,
+/// }");
 /// ```
+
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
@@ -528,12 +521,20 @@ pub trait Debug {
     ///
     /// impl fmt::Debug for Position {
     ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "({:?}, {:?})", self.longitude, self.latitude)
+    ///         f.debug_tuple("")
+    ///          .field(&self.longitude)
+    ///          .field(&self.latitude)
+    ///          .finish()
     ///     }
     /// }
     ///
-    /// assert_eq!("(1.987, 2.983)".to_owned(),
-    ///            format!("{:?}", Position { longitude: 1.987, latitude: 2.983, }));
+    /// let position = Position { longitude: 1.987, latitude: 2.983 };
+    /// assert_eq!(format!("{:?}", position), "(1.987, 2.983)");
+    ///
+    /// assert_eq!(format!("{:#?}", position), "(
+    ///     1.987,
+    ///     2.983,
+    /// )");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -584,7 +585,7 @@ pub use macros::Debug;
 ///
 /// let origin = Point { x: 0, y: 0 };
 ///
-/// println!("The origin is: {}", origin);
+/// assert_eq!(format!("The origin is: {}", origin), "The origin is: (0, 0)");
 /// ```
 #[rustc_on_unimplemented(
     on(
@@ -618,7 +619,7 @@ pub trait Display {
     ///     }
     /// }
     ///
-    /// assert_eq!("(1.987, 2.983)".to_owned(),
+    /// assert_eq!("(1.987, 2.983)",
     ///            format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -668,7 +669,9 @@ pub trait Display {
 ///
 /// let l = Length(9);
 ///
-/// println!("l as octal is: {:o}", l);
+/// assert_eq!(format!("l as octal is: {:o}", l), "l as octal is: 11");
+///
+/// assert_eq!(format!("l as octal is: {:#06o}", l), "l as octal is: 0o0011");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Octal {
@@ -718,7 +721,12 @@ pub trait Octal {
 ///
 /// let l = Length(107);
 ///
-/// println!("l as binary is: {:b}", l);
+/// assert_eq!(format!("l as binary is: {:b}", l), "l as binary is: 1101011");
+///
+/// assert_eq!(
+///     format!("l as binary is: {:#032b}", l),
+///     "l as binary is: 0b000000000000000000000001101011"
+/// );
 /// ```
 ///
 /// [module]: ../../std/fmt/index.html
@@ -777,7 +785,9 @@ pub trait Binary {
 ///
 /// let l = Length(9);
 ///
-/// println!("l as hex is: {:x}", l);
+/// assert_eq!(format!("l as hex is: {:x}", l), "l as hex is: 9");
+///
+/// assert_eq!(format!("l as hex is: {:#010x}", l), "l as hex is: 0x00000009");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait LowerHex {
@@ -828,9 +838,11 @@ pub trait LowerHex {
 ///     }
 /// }
 ///
-/// let l = Length(9);
+/// let l = Length(i32::max_value());
 ///
-/// println!("l as hex is: {:X}", l);
+/// assert_eq!(format!("l as hex is: {:X}", l), "l as hex is: 7FFFFFFF");
+///
+/// assert_eq!(format!("l as hex is: {:#010X}", l), "l as hex is: 0x7FFFFFFF");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait UpperHex {
@@ -877,6 +889,10 @@ pub trait UpperHex {
 /// let l = Length(42);
 ///
 /// println!("l is in memory here: {:p}", l);
+///
+/// let l_ptr = format!("{:018p}", l);
+/// assert_eq!(l_ptr.len(), 18);
+/// assert_eq!(&l_ptr[..2], "0x");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Pointer {
@@ -912,14 +928,22 @@ pub trait Pointer {
 ///
 /// impl fmt::LowerExp for Length {
 ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-///         let val = self.0;
-///         write!(f, "{}e1", val / 10)
+///         let val = f64::from(self.0);
+///         fmt::LowerExp::fmt(&val, f) // delegate to f64's implementation
 ///     }
 /// }
 ///
 /// let l = Length(100);
 ///
-/// println!("l in scientific notation is: {:e}", l);
+/// assert_eq!(
+///     format!("l in scientific notation is: {:e}", l),
+///     "l in scientific notation is: 1e2"
+/// );
+///
+/// assert_eq!(
+///     format!("l in scientific notation is: {:05e}", l),
+///     "l in scientific notation is: 001e2"
+/// );
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait LowerExp {
@@ -955,14 +979,22 @@ pub trait LowerExp {
 ///
 /// impl fmt::UpperExp for Length {
 ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-///         let val = self.0;
-///         write!(f, "{}E1", val / 10)
+///         let val = f64::from(self.0);
+///         fmt::UpperExp::fmt(&val, f) // delegate to f64's implementation
 ///     }
 /// }
 ///
 /// let l = Length(100);
 ///
-/// println!("l in scientific notation is: {:E}", l);
+/// assert_eq!(
+///     format!("l in scientific notation is: {:E}", l),
+///     "l in scientific notation is: 1E2"
+/// );
+///
+/// assert_eq!(
+///     format!("l in scientific notation is: {:05E}", l),
+///     "l in scientific notation is: 001E2"
+/// );
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait UpperExp {
@@ -1807,8 +1839,7 @@ impl<'a> Formatter<'a> {
     ///     }
     /// }
     ///
-    /// // prints "[10, 11]"
-    /// println!("{:?}", Foo(vec![10, 11]));
+    /// assert_eq!(format!("{:?}", Foo(vec![10, 11])), "[10, 11]");
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn debug_list<'b>(&'b mut self) -> DebugList<'b, 'a> {
@@ -1831,8 +1862,7 @@ impl<'a> Formatter<'a> {
     ///     }
     /// }
     ///
-    /// // prints "{10, 11}"
-    /// println!("{:?}", Foo(vec![10, 11]));
+    /// assert_eq!(format!("{:?}", Foo(vec![10, 11])), "{10, 11}");
     /// ```
     ///
     /// [`format_args!`]: ../../std/macro.format_args.html
@@ -1890,8 +1920,10 @@ impl<'a> Formatter<'a> {
     ///     }
     /// }
     ///
-    /// // prints "{"A": 10, "B": 11}"
-    /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
+    /// assert_eq!(
+    ///     format!("{:?}",  Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
+    ///     r#"{"A": 10, "B": 11}"#
+    ///  );
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, 'a> {
@@ -1940,14 +1972,14 @@ macro_rules! fmt_refs {
 
 fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
 
-#[stable(feature = "never_type", since = "1.41.0")]
+#[unstable(feature = "never_type", issue = "35121")]
 impl Debug for ! {
     fn fmt(&self, _: &mut Formatter<'_>) -> Result {
         *self
     }
 }
 
-#[stable(feature = "never_type", since = "1.41.0")]
+#[unstable(feature = "never_type", issue = "35121")]
 impl Display for ! {
     fn fmt(&self, _: &mut Formatter<'_>) -> Result {
         *self
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 18aae59573d..b02acce2d00 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -939,7 +939,7 @@ extern "rust-intrinsic" {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_transmute")]
+    #[rustc_const_unstable(feature = "const_transmute", issue = "53605")]
     pub fn transmute<T, U>(e: T) -> U;
 
     /// Returns `true` if the actual type given as `T` requires drop
@@ -1146,7 +1146,6 @@ extern "rust-intrinsic" {
 
     /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range
     /// https://github.com/rust-lang/rust/issues/10184
-    #[cfg(not(bootstrap))]
     pub fn float_to_int_approx_unchecked<Float, Int>(value: Float) -> Int;
 
 
@@ -1357,7 +1356,6 @@ extern "rust-intrinsic" {
     /// Compiles to a NOP during non-Miri codegen.
     ///
     /// Perma-unstable: do not use
-    #[cfg(not(bootstrap))]
     pub fn miri_start_panic(data: *mut (dyn crate::any::Any + crate::marker::Send)) -> ();
 }
 
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 39d571006e6..019a3290f01 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -517,14 +517,6 @@ impl<I> Iterator for StepBy<I> where I: Iterator {
         // overflow handling
         loop {
             let mul = n.checked_mul(step);
-            #[cfg(bootstrap)]
-            {
-                // SAFETY: going away soon
-                if unsafe { intrinsics::likely(mul.is_some()) } {
-                    return self.iter.nth(mul.unwrap() - 1);
-                }
-            }
-            #[cfg(not(bootstrap))]
             {
                 if intrinsics::likely(mul.is_some()) {
                     return self.iter.nth(mul.unwrap() - 1);
diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs
index ffac7d4e995..a65d47cc2c1 100644
--- a/src/libcore/iter/sources.rs
+++ b/src/libcore/iter/sources.rs
@@ -281,6 +281,7 @@ impl<T> Default for Empty<T> {
 /// assert_eq!(None, nope.next());
 /// ```
 #[stable(feature = "iter_empty", since = "1.2.0")]
+#[rustc_const_stable(feature = "const_iter_empty", since = "1.32.0")]
 pub const fn empty<T>() -> Empty<T> {
     Empty(marker::PhantomData)
 }
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 8a514f1e78e..a2ab85e64ba 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -74,8 +74,8 @@
 #![feature(const_fn)]
 #![feature(const_fn_union)]
 #![feature(const_generics)]
-#![cfg_attr(not(bootstrap), feature(const_ptr_offset_from))]
-#![cfg_attr(not(bootstrap), feature(const_type_name))]
+#![feature(const_ptr_offset_from)]
+#![feature(const_type_name)]
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
@@ -87,22 +87,20 @@
 #![feature(iter_once_with)]
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(nll)]
 #![feature(exhaustive_patterns)]
 #![feature(no_core)]
-#![cfg_attr(bootstrap, feature(on_unimplemented))]
 #![feature(optin_builtin_traits)]
 #![feature(prelude_import)]
 #![feature(repr_simd, platform_intrinsics)]
 #![feature(rustc_attrs)]
-#![feature(rustc_const_unstable)]
 #![feature(simd_ffi)]
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
-#![cfg_attr(not(bootstrap), feature(track_caller))]
+#![feature(track_caller)]
 #![feature(transparent_unions)]
 #![feature(unboxed_closures)]
 #![feature(unsized_locals)]
diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs
index cf460745ffa..dd06da7a6d2 100644
--- a/src/libcore/macros/mod.rs
+++ b/src/libcore/macros/mod.rs
@@ -686,7 +686,7 @@ macro_rules! unimplemented {
 /// }
 /// ```
 #[macro_export]
-#[stable(feature = "todo_macro", since = "1.39.0")]
+#[stable(feature = "todo_macro", since = "1.40.0")]
 macro_rules! todo {
     () => (panic!("not yet implemented"));
     ($($arg:tt)+) => (panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 288017b7ca5..1b586c3e5fe 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -97,7 +97,7 @@ pub trait Sized {
 /// Types that can be "unsized" to a dynamically-sized type.
 ///
 /// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
-/// `Unsize<fmt::Debug>`.
+/// `Unsize<dyn fmt::Debug>`.
 ///
 /// All implementations of `Unsize` are provided automatically by the compiler.
 ///
@@ -776,7 +776,7 @@ mod copy_impls {
         bool char
     }
 
-    #[stable(feature = "never_type", since = "1.41.0")]
+    #[unstable(feature = "never_type", issue = "35121")]
     impl Copy for ! {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs
index 34fc0618ea2..af4635f89f6 100644
--- a/src/libcore/mem/manually_drop.rs
+++ b/src/libcore/mem/manually_drop.rs
@@ -63,6 +63,7 @@ impl<T> ManuallyDrop<T> {
     /// ManuallyDrop::new(Box::new(()));
     /// ```
     #[stable(feature = "manually_drop", since = "1.20.0")]
+    #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
     #[inline(always)]
     pub const fn new(value: T) -> ManuallyDrop<T> {
         ManuallyDrop { value }
@@ -80,6 +81,7 @@ impl<T> ManuallyDrop<T> {
     /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
     /// ```
     #[stable(feature = "manually_drop", since = "1.20.0")]
+    #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")]
     #[inline(always)]
     pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
         slot.value
diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs
index 6661df2ae0d..7f80f61aaf9 100644
--- a/src/libcore/mem/maybe_uninit.rs
+++ b/src/libcore/mem/maybe_uninit.rs
@@ -250,6 +250,7 @@ impl<T> MaybeUninit<T> {
     ///
     /// [`assume_init`]: #method.assume_init
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub const fn new(val: T) -> MaybeUninit<T> {
         MaybeUninit { value: ManuallyDrop::new(val) }
@@ -264,8 +265,9 @@ impl<T> MaybeUninit<T> {
     ///
     /// [type]: union.MaybeUninit.html
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")]
     #[inline(always)]
-    #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "maybe_uninit_uninit")]
+    #[rustc_diagnostic_item = "maybe_uninit_uninit"]
     pub const fn uninit() -> MaybeUninit<T> {
         MaybeUninit { uninit: () }
     }
@@ -349,7 +351,7 @@ impl<T> MaybeUninit<T> {
     /// ```
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline]
-    #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "maybe_uninit_zeroed")]
+    #[rustc_diagnostic_item = "maybe_uninit_zeroed"]
     pub fn zeroed() -> MaybeUninit<T> {
         let mut u = MaybeUninit::<T>::uninit();
         unsafe {
@@ -490,7 +492,7 @@ impl<T> MaybeUninit<T> {
     /// ```
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
-    #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "assume_init")]
+    #[rustc_diagnostic_item = "assume_init"]
     pub unsafe fn assume_init(self) -> T {
         intrinsics::panic_if_uninhabited::<T>();
         ManuallyDrop::into_inner(self.value)
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index bba441464ff..4e8ba8131f7 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -271,6 +271,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[rustc_const_stable(feature = "const_size_of", since = "1.32.0")]
 pub const fn size_of<T>() -> usize {
     intrinsics::size_of::<T>()
 }
@@ -298,10 +299,6 @@ pub const fn size_of<T>() -> usize {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
-    #[cfg(bootstrap)]
-    // SAFETY: going away soon
-    unsafe { intrinsics::size_of_val(val) }
-    #[cfg(not(bootstrap))]
     intrinsics::size_of_val(val)
 }
 
@@ -346,10 +343,6 @@ pub fn min_align_of<T>() -> usize {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
 pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
-    #[cfg(bootstrap)]
-    // SAFETY: going away soon
-    unsafe { intrinsics::min_align_of_val(val) }
-    #[cfg(not(bootstrap))]
     intrinsics::min_align_of_val(val)
 }
 
@@ -371,6 +364,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[rustc_const_stable(feature = "const_align_of", since = "1.32.0")]
 pub const fn align_of<T>() -> usize {
     intrinsics::min_align_of::<T>()
 }
@@ -453,6 +447,7 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// ```
 #[inline]
 #[stable(feature = "needs_drop", since = "1.21.0")]
+#[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")]
 pub const fn needs_drop<T>() -> bool {
     intrinsics::needs_drop::<T>()
 }
@@ -498,7 +493,7 @@ pub const fn needs_drop<T>() -> bool {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
 #[allow(deprecated)]
-#[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "mem_zeroed")]
+#[rustc_diagnostic_item = "mem_zeroed"]
 pub unsafe fn zeroed<T>() -> T {
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::init()
@@ -510,7 +505,9 @@ pub unsafe fn zeroed<T>() -> T {
 /// **This function is deprecated.** Use [`MaybeUninit<T>`] instead.
 ///
 /// The reason for deprecation is that the function basically cannot be used
-/// correctly: [the Rust compiler assumes][inv] that values are properly initialized.
+/// correctly: it has the same effect as [`MaybeUninit::uninit().assume_init()`][uninit].
+/// As the [`assume_init` documentation][assume_init] explains,
+/// [the Rust compiler assumes][inv] that values are properly initialized.
 /// As a consequence, calling e.g. `mem::uninitialized::<bool>()` causes immediate
 /// undefined behavior for returning a `bool` that is not definitely either `true`
 /// or `false`. Worse, truly uninitialized memory like what gets returned here
@@ -521,13 +518,15 @@ pub unsafe fn zeroed<T>() -> T {
 /// until they are, it is advisable to avoid them.)
 ///
 /// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [uninit]: union.MaybeUninit.html#method.uninit
+/// [assume_init]: union.MaybeUninit.html#method.assume_init
 /// [inv]: union.MaybeUninit.html#initialization-invariant
 #[inline]
 #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
 #[allow(deprecated)]
-#[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "mem_uninitialized")]
+#[rustc_diagnostic_item = "mem_uninitialized"]
 pub unsafe fn uninitialized<T>() -> T {
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::uninit()
@@ -867,11 +866,5 @@ impl<T> fmt::Debug for Discriminant<T> {
 /// ```
 #[stable(feature = "discriminant_value", since = "1.21.0")]
 pub fn discriminant<T>(v: &T) -> Discriminant<T> {
-    #[cfg(bootstrap)]
-    // SAFETY: going away soon
-    unsafe {
-        Discriminant(intrinsics::discriminant_value(v), PhantomData)
-    }
-    #[cfg(not(bootstrap))]
     Discriminant(intrinsics::discriminant_value(v), PhantomData)
 }
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index ac06f95e244..9e379e63810 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -7,7 +7,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[cfg(not(bootstrap))]
 use crate::convert::FloatToInt;
 #[cfg(not(test))]
 use crate::intrinsics;
@@ -423,7 +422,6 @@ impl f32 {
     /// * Not be `NaN`
     /// * Not be infinite
     /// * Be representable in the return type `Int`, after truncating off its fractional part
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
     #[inline]
     pub unsafe fn approx_unchecked_to<Int>(self) -> Int where Self: FloatToInt<Int> {
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 5446ce3e3b3..540c6a529d7 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -7,7 +7,6 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[cfg(not(bootstrap))]
 use crate::convert::FloatToInt;
 #[cfg(not(test))]
 use crate::intrinsics;
@@ -436,7 +435,6 @@ impl f64 {
     /// * Not be `NaN`
     /// * Not be infinite
     /// * Be representable in the return type `Int`, after truncating off its fractional part
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "float_approx_unchecked_to", issue = "67058")]
     #[inline]
     pub unsafe fn approx_unchecked_to<Int>(self) -> Int
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index d1f518d52dd..6c864f74b1f 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -4,6 +4,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::convert::Infallible;
 use crate::fmt;
 use crate::intrinsics;
 use crate::mem;
@@ -60,9 +61,10 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 ///
                 /// The value must not be zero.
                 #[$stability]
+                #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
                 #[inline]
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
-                    $Ty(n)
+                    Self(n)
                 }
 
                 /// Creates a non-zero if the given value is not zero.
@@ -71,7 +73,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 pub fn new(n: $Int) -> Option<Self> {
                     if n != 0 {
                         // SAFETY: we just checked that there's no `0`
-                        Some(unsafe { $Ty(n) })
+                        Some(unsafe { Self(n) })
                     } else {
                         None
                     }
@@ -80,6 +82,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 /// Returns the value as a primitive type.
                 #[$stability]
                 #[inline]
+                #[rustc_const_stable(feature = "nonzero", since = "1.34.0")]
                 pub const fn get(self) -> $Int {
                     self.0
                 }
@@ -135,7 +138,7 @@ NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize }
 
 /// Provides intentionally-wrapped arithmetic on `T`.
 ///
-/// Operations like `+` on `u32` values is intended to never overflow,
+/// Operations like `+` on `u32` values are intended to never overflow,
 /// and in some debug configurations overflow is detected and results
 /// in a panic. While most arithmetic falls into this category, some
 /// code explicitly expects and relies upon modular arithmetic (e.g.,
@@ -255,6 +258,7 @@ $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline(always)]
             #[rustc_promotable]
+            #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
             pub const fn min_value() -> Self {
                 !0 ^ ((!0 as $UnsignedT) >> 1) as Self
             }
@@ -274,6 +278,7 @@ $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline(always)]
             #[rustc_promotable]
+            #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
             pub const fn max_value() -> Self {
                 !Self::min_value()
             }
@@ -323,6 +328,7 @@ $EndFeature, "
 ```
 "),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
         }
@@ -338,6 +344,7 @@ Basic usage:
 ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn count_zeros(self) -> u32 {
                 (!self).count_ones()
@@ -358,6 +365,7 @@ assert_eq!(n.leading_zeros(), 0);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn leading_zeros(self) -> u32 {
                 (self as $UnsignedT).leading_zeros()
@@ -378,6 +386,7 @@ assert_eq!(n.trailing_zeros(), 2);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn trailing_zeros(self) -> u32 {
                 (self as $UnsignedT).trailing_zeros()
@@ -401,6 +410,7 @@ let m = ", $rot_result, ";
 assert_eq!(n.rotate_left(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -427,6 +437,7 @@ let m = ", $rot_op, ";
 assert_eq!(n.rotate_right(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -450,6 +461,7 @@ let m = n.swap_bytes();
 assert_eq!(m, ", $swapped, ");
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn swap_bytes(self) -> Self {
                 (self as $UnsignedT).swap_bytes() as Self
@@ -470,6 +482,7 @@ let m = n.reverse_bits();
 assert_eq!(m, ", $reversed, ");
 ```"),
             #[stable(feature = "reverse_bits", since = "1.37.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             #[must_use]
             pub const fn reverse_bits(self) -> Self {
@@ -497,6 +510,7 @@ if cfg!(target_endian = \"big\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
             #[inline]
             pub const fn from_be(x: Self) -> Self {
                 #[cfg(target_endian = "big")]
@@ -530,6 +544,7 @@ if cfg!(target_endian = \"little\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
             #[inline]
             pub const fn from_le(x: Self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -563,6 +578,7 @@ if cfg!(target_endian = \"big\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
             #[inline]
             pub const fn to_be(self) -> Self { // or not to be?
                 #[cfg(target_endian = "big")]
@@ -596,6 +612,7 @@ if cfg!(target_endian = \"little\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")]
             #[inline]
             pub const fn to_le(self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -948,7 +965,7 @@ $EndFeature, "
 ```"),
 
             #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -974,7 +991,7 @@ assert_eq!(", stringify!($SelfT), "::max_value().saturating_sub(-1), ", stringif
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1114,6 +1131,7 @@ assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!(
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1137,6 +1155,7 @@ stringify!($SelfT), "::max_value());",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1159,6 +1178,7 @@ assert_eq!(11i8.wrapping_mul(12), -124);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1303,6 +1323,7 @@ assert_eq!(", stringify!($SelfT), "::min_value().wrapping_neg(), ", stringify!($
 $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn wrapping_neg(self) -> Self {
                 self.overflowing_neg().0
@@ -1328,6 +1349,7 @@ assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);",
 $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1359,6 +1381,7 @@ assert_eq!((-128i16).wrapping_shr(64), -128);",
 $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1392,6 +1415,7 @@ assert_eq!((-128i8).wrapping_abs() as u8, 128);",
 $EndFeature, "
 ```"),
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn wrapping_abs(self) -> Self {
                 // sign is -1 (all ones) for negative numbers, 0 otherwise.
@@ -1466,6 +1490,7 @@ assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($Sel
 "::MIN, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1493,6 +1518,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($Sel
 "::MAX, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1518,6 +1544,7 @@ assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1685,6 +1712,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($Self
 ```"),
             #[inline]
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 ((!self).wrapping_add(1), self == Self::min_value())
             }
@@ -1707,6 +1735,7 @@ assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1732,6 +1761,7 @@ assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1760,6 +1790,7 @@ assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (", string
 $EndFeature, "
 ```"),
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn overflowing_abs(self) -> (Self, bool) {
                 (self.wrapping_abs(), self == Self::min_value())
@@ -1964,6 +1995,7 @@ assert_eq!((-10", stringify!($SelfT), ").abs(), 10);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             #[rustc_inherit_overflow_checks]
             pub const fn abs(self) -> Self {
@@ -2006,7 +2038,7 @@ assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_int_sign")]
+            #[rustc_const_unstable(feature = "const_int_sign", issue = "53718")]
             #[inline]
             pub const fn signum(self) -> Self {
                 (self > 0) as Self - (self < 0) as Self
@@ -2027,6 +2059,7 @@ assert!(!(-10", stringify!($SelfT), ").is_positive());",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn is_positive(self) -> bool { self > 0 }
         }
@@ -2045,6 +2078,7 @@ assert!(!10", stringify!($SelfT), ".is_negative());",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")]
             #[inline]
             pub const fn is_negative(self) -> bool { self < 0 }
         }
@@ -2062,7 +2096,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
 assert_eq!(bytes, ", $be_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_be().to_ne_bytes()
@@ -2082,7 +2116,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
 assert_eq!(bytes, ", $le_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_le().to_ne_bytes()
@@ -2117,7 +2151,7 @@ assert_eq!(
 );
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
@@ -2151,7 +2185,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_be(Self::from_ne_bytes(bytes))
@@ -2184,7 +2218,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_le(Self::from_ne_bytes(bytes))
@@ -2227,7 +2261,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
@@ -2321,6 +2355,7 @@ Basic usage:
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_promotable]
             #[inline(always)]
+            #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
             pub const fn min_value() -> Self { 0 }
         }
 
@@ -2338,6 +2373,7 @@ stringify!($MaxV), ");", $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_promotable]
             #[inline(always)]
+            #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
             pub const fn max_value() -> Self { !0 }
         }
 
@@ -2384,6 +2420,7 @@ Basic usage:
 assert_eq!(n.count_ones(), 3);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn count_ones(self) -> u32 {
                 intrinsics::ctpop(self as $ActualT) as u32
@@ -2401,6 +2438,7 @@ Basic usage:
 ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn count_zeros(self) -> u32 {
                 (!self).count_ones()
@@ -2420,6 +2458,7 @@ Basic usage:
 assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn leading_zeros(self) -> u32 {
                 intrinsics::ctlz(self as $ActualT) as u32
@@ -2440,6 +2479,7 @@ Basic usage:
 assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn trailing_zeros(self) -> u32 {
                 intrinsics::cttz(self) as u32
@@ -2463,6 +2503,7 @@ let m = ", $rot_result, ";
 assert_eq!(n.rotate_left(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -2489,6 +2530,7 @@ let m = ", $rot_op, ";
 assert_eq!(n.rotate_right(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -2512,6 +2554,7 @@ let m = n.swap_bytes();
 assert_eq!(m, ", $swapped, ");
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn swap_bytes(self) -> Self {
                 intrinsics::bswap(self as $ActualT) as Self
@@ -2532,6 +2575,7 @@ let m = n.reverse_bits();
 assert_eq!(m, ", $reversed, ");
 ```"),
             #[stable(feature = "reverse_bits", since = "1.37.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             #[must_use]
             pub const fn reverse_bits(self) -> Self {
@@ -2559,6 +2603,7 @@ if cfg!(target_endian = \"big\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn from_be(x: Self) -> Self {
                 #[cfg(target_endian = "big")]
@@ -2592,6 +2637,7 @@ if cfg!(target_endian = \"little\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn from_le(x: Self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -2625,6 +2671,7 @@ if cfg!(target_endian = \"big\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn to_be(self) -> Self { // or not to be?
                 #[cfg(target_endian = "big")]
@@ -2658,6 +2705,7 @@ if cfg!(target_endian = \"little\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_math", since = "1.32.0")]
             #[inline]
             pub const fn to_le(self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -2963,7 +3011,7 @@ assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")]
             #[inline]
             pub const fn saturating_add(self, rhs: Self) -> Self {
                 intrinsics::saturating_add(self, rhs)
@@ -2985,7 +3033,7 @@ assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")]
             #[inline]
             pub const fn saturating_sub(self, rhs: Self) -> Self {
                 intrinsics::saturating_sub(self, rhs)
@@ -3057,6 +3105,7 @@ assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::ma
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3079,6 +3128,7 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::ma
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3102,6 +3152,7 @@ $EndFeature, "
         /// assert_eq!(25u8.wrapping_mul(12), 44);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
         #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
         #[inline]
@@ -3231,6 +3282,7 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
         /// assert_eq!((-128i8).wrapping_neg(), -128);
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
         #[inline]
         pub const fn wrapping_neg(self) -> Self {
             self.overflowing_neg().0
@@ -3257,6 +3309,7 @@ Basic usage:
 assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3290,6 +3343,7 @@ Basic usage:
 assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3359,6 +3413,7 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
 assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3387,6 +3442,7 @@ assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT),
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3414,6 +3470,7 @@ $EndFeature, "
         /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
         /// ```
         #[stable(feature = "wrapping", since = "1.7.0")]
+        #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
         #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
         #[inline]
@@ -3559,6 +3616,7 @@ assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!(
 ```"),
             #[inline]
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 ((!self).wrapping_add(1), self != 0)
             }
@@ -3582,6 +3640,7 @@ Basic usage
 assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3608,6 +3667,7 @@ Basic usage
 assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3773,6 +3833,7 @@ Basic usage:
 assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")]
             #[inline]
             pub const fn is_power_of_two(self) -> bool {
                 self.count_ones() == 1
@@ -3884,7 +3945,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
 assert_eq!(bytes, ", $be_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_be().to_ne_bytes()
@@ -3904,7 +3965,7 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
 assert_eq!(bytes, ", $le_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_le().to_ne_bytes()
@@ -3939,7 +4000,7 @@ assert_eq!(
 );
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
@@ -3973,7 +4034,7 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_be(Self::from_ne_bytes(bytes))
@@ -4006,7 +4067,7 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_le(Self::from_ne_bytes(bytes))
@@ -4049,7 +4110,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[rustc_const_unstable(feature = "const_int_conversion", issue = "53718")]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
@@ -4724,8 +4785,18 @@ impl fmt::Display for TryFromIntError {
 }
 
 #[stable(feature = "try_from", since = "1.34.0")]
+impl From<Infallible> for TryFromIntError {
+    fn from(x: Infallible) -> TryFromIntError {
+        match x {}
+    }
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
 impl From<!> for TryFromIntError {
     fn from(never: !) -> TryFromIntError {
+        // Match rather than coerce to make sure that code like
+        // `From<Infallible> for TryFromIntError` above will keep working
+        // when `Infallible` becomes an alias to `!`.
         match never {}
     }
 }
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
index 0ddfbd02aa5..82fa6acfbd6 100644
--- a/src/libcore/num/wrapping.rs
+++ b/src/libcore/num/wrapping.rs
@@ -530,6 +530,7 @@ assert_eq!(n.trailing_zeros(), 3);
             /// assert_eq!(m, Wrapping(-22016));
             /// ```
             #[stable(feature = "reverse_bits", since = "1.37.0")]
+            #[rustc_const_stable(feature = "const_reverse_bits", since = "1.37.0")]
             #[inline]
             #[must_use]
             pub const fn reverse_bits(self) -> Self {
diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs
index a2250337a4d..be6d8edb99f 100644
--- a/src/libcore/ops/range.rs
+++ b/src/libcore/ops/range.rs
@@ -398,6 +398,7 @@ impl<Idx> RangeInclusive<Idx> {
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
+    #[rustc_const_stable(feature = "const_range_new", since = "1.32.0")]
     pub const fn new(start: Idx, end: Idx) -> Self {
         Self { start, end, is_empty: None }
     }
@@ -421,6 +422,7 @@ impl<Idx> RangeInclusive<Idx> {
     /// assert_eq!((3..=5).start(), &3);
     /// ```
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
+    #[rustc_const_stable(feature = "const_inclusive_range_methods", since = "1.32.0")]
     #[inline]
     pub const fn start(&self) -> &Idx {
         &self.start
@@ -445,6 +447,7 @@ impl<Idx> RangeInclusive<Idx> {
     /// assert_eq!((3..=5).end(), &5);
     /// ```
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
+    #[rustc_const_stable(feature = "const_inclusive_range_methods", since = "1.32.0")]
     #[inline]
     pub const fn end(&self) -> &Idx {
         &self.end
diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs
index 22ba97b91df..996a01d413c 100644
--- a/src/libcore/ops/try.rs
+++ b/src/libcore/ops/try.rs
@@ -5,26 +5,23 @@
 /// extracting those success or failure values from an existing instance and
 /// creating a new instance from a success or failure value.
 #[unstable(feature = "try_trait", issue = "42327")]
-#[cfg_attr(
-    not(bootstrap),
-    rustc_on_unimplemented(
-        on(
-            all(
-                any(from_method = "from_error", from_method = "from_ok"),
-                from_desugaring = "QuestionMark"
-            ),
-            message = "the `?` operator can only be used in {ItemContext} \
-                       that returns `Result` or `Option` \
-                       (or another type that implements `{Try}`)",
-            label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
-            enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
+#[rustc_on_unimplemented(
+    on(
+        all(
+            any(from_method = "from_error", from_method = "from_ok"),
+            from_desugaring = "QuestionMark"
         ),
-        on(
-            all(from_method = "into_result", from_desugaring = "QuestionMark"),
-            message = "the `?` operator can only be applied to values \
-                       that implement `{Try}`",
-            label = "the `?` operator cannot be applied to type `{Self}`"
-        )
+        message = "the `?` operator can only be used in {ItemContext} \
+                    that returns `Result` or `Option` \
+                    (or another type that implements `{Try}`)",
+        label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+        enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
+    ),
+    on(
+        all(from_method = "into_result", from_desugaring = "QuestionMark"),
+        message = "the `?` operator can only be applied to values \
+                    that implement `{Try}`",
+        label = "the `?` operator cannot be applied to type `{Self}`"
     )
 )]
 #[doc(alias = "?")]
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
index e924ee20369..c9a1c4b0049 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -1,8 +1,6 @@
 //! Panic support in the standard library.
 
-#![unstable(feature = "core_panic_info",
-            reason = "newly available in libcore",
-            issue = "44489")]
+#![stable(feature = "core_panic_info", since = "1.41.0")]
 
 use crate::any::Any;
 use crate::fmt;
@@ -39,10 +37,10 @@ pub struct PanicInfo<'a> {
 }
 
 impl<'a> PanicInfo<'a> {
-    #![unstable(feature = "panic_internals",
-                reason = "internal details of the implementation of the `panic!` \
-                          and related macros",
-                issue = "0")]
+    #[unstable(feature = "panic_internals",
+               reason = "internal details of the implementation of the `panic!` \
+                         and related macros",
+               issue = "0")]
     #[doc(hidden)]
     #[inline]
     pub fn internal_constructor(
@@ -57,6 +55,10 @@ impl<'a> PanicInfo<'a> {
         }
     }
 
+    #[unstable(feature = "panic_internals",
+               reason = "internal details of the implementation of the `panic!` \
+                         and related macros",
+               issue = "0")]
     #[doc(hidden)]
     #[inline]
     pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
@@ -90,7 +92,7 @@ impl<'a> PanicInfo<'a> {
     /// returns that message ready to be used for example with [`fmt::write`]
     ///
     /// [`fmt::write`]: ../fmt/fn.write.html
-    #[unstable(feature = "panic_info_message", issue = "44489")]
+    #[unstable(feature = "panic_info_message", issue = "66745")]
     pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
         self.message
     }
@@ -220,7 +222,6 @@ impl<'a> Location<'a> {
     /// assert_ne!(this_location.line(), another_location.line());
     /// assert_ne!(this_location.column(), another_location.column());
     /// ```
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "track_caller",
                reason = "uses #[track_caller] which is not yet stable",
                issue = "47809")]
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 24ffa348329..776165e7bd7 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -198,6 +198,7 @@ unsafe fn real_drop_in_place<T: ?Sized>(to_drop: &mut T) {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[rustc_const_stable(feature = "const_ptr_null", since = "1.32.0")]
 pub const fn null<T>() -> *const T {
     0 as *const T
 }
@@ -215,6 +216,7 @@ pub const fn null<T>() -> *const T {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[rustc_const_stable(feature = "const_ptr_null", since = "1.32.0")]
 pub const fn null_mut<T>() -> *mut T {
     0 as *mut T
 }
@@ -1060,6 +1062,7 @@ impl<T: ?Sized> *const T {
 
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
+    #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
     #[inline]
     pub const fn cast<U>(self) -> *const U {
         self as _
@@ -1307,7 +1310,7 @@ impl<T: ?Sized> *const T {
     /// }
     /// ```
     #[unstable(feature = "ptr_offset_from", issue = "41079")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     #[inline]
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
@@ -1763,6 +1766,7 @@ impl<T: ?Sized> *mut T {
 
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
+    #[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
     #[inline]
     pub const fn cast<U>(self) -> *mut U {
         self as _
@@ -2049,7 +2053,7 @@ impl<T: ?Sized> *mut T {
     /// }
     /// ```
     #[unstable(feature = "ptr_offset_from", issue = "41079")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
     #[inline]
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index a121389bef3..6946fd2413e 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -66,6 +66,7 @@ impl<T: Sized> NonNull<T> {
     /// sentinel value. Types that lazily allocate must track initialization by
     /// some other means.
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.32.0")]
     #[inline]
     pub const fn dangling() -> Self {
         unsafe {
@@ -82,6 +83,7 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// `ptr` must be non-null.
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.32.0")]
     #[inline]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
         NonNull { pointer: ptr as _ }
@@ -96,6 +98,7 @@ impl<T: ?Sized> NonNull<T> {
 
     /// Acquires the underlying `*mut` pointer.
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")]
     #[inline]
     pub const fn as_ptr(self) -> *mut T {
         self.pointer as *mut T
@@ -125,6 +128,7 @@ impl<T: ?Sized> NonNull<T> {
 
     /// Casts to a pointer of another type.
     #[stable(feature = "nonnull_cast", since = "1.27.0")]
+    #[rustc_const_stable(feature = "const_nonnull_cast", since = "1.32.0")]
     #[inline]
     pub const fn cast<U>(self) -> NonNull<U> {
         unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 1a0845f3a6d..fb4dc62d8c1 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -520,7 +520,6 @@ impl<T, E> Result<T, E> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(result_map_or)]
     /// let x: Result<_, &str> = Ok("foo");
     /// assert_eq!(x.map_or(42, |v| v.len()), 3);
     ///
@@ -528,7 +527,7 @@ impl<T, E> Result<T, E> {
     /// assert_eq!(x.map_or(42, |v| v.len()), 42);
     /// ```
     #[inline]
-    #[unstable(feature = "result_map_or", issue = "66293")]
+    #[stable(feature = "result_map_or", since = "1.41.0")]
     pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
         match self {
             Ok(t) => f(t),
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index c8fe9f98613..05baa1899b3 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -62,6 +62,7 @@ impl<T> [T] {
     /// assert_eq!(a.len(), 3);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")]
     #[inline]
     // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
     #[allow(unused_attributes)]
@@ -81,6 +82,7 @@ impl<T> [T] {
     /// assert!(!a.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.32.0")]
     #[inline]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
@@ -376,6 +378,7 @@ impl<T> [T] {
     ///
     /// [`as_mut_ptr`]: #method.as_mut_ptr
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")]
     #[inline]
     pub const fn as_ptr(&self) -> *const T {
         self as *const [T] as *const T
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index b2a420f3c43..3da992dca30 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -8,7 +8,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use self::pattern::Pattern;
-use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
+use self::pattern::{Searcher, SearchStep, ReverseSearcher, DoubleEndedSearcher};
 
 use crate::char;
 use crate::fmt::{self, Write};
@@ -2090,6 +2090,7 @@ impl str {
     /// assert_eq!("ƒoo".chars().count(), 3);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_str_len", since = "1.32.0")]
     #[inline]
     pub const fn len(&self) -> usize {
         self.as_bytes().len()
@@ -2110,6 +2111,7 @@ impl str {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_str_is_empty", since = "1.32.0")]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -2166,6 +2168,7 @@ impl str {
     /// assert_eq!(b"bors", bytes);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")]
     #[inline(always)]
     // SAFETY: const sound because we transmute two types with the same layout
     #[allow(unused_attributes)]
@@ -2239,6 +2242,7 @@ impl str {
     /// let ptr = s.as_ptr();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")]
     #[inline]
     pub const fn as_ptr(&self) -> *const u8 {
         self as *const str as *const u8
@@ -3791,6 +3795,77 @@ impl str {
         }
     }
 
+    /// Returns a string slice with the prefix removed.
+    ///
+    /// If the string starts with the pattern `prefix`, `Some` is returned with the substring where
+    /// the prefix is removed. Unlike `trim_start_matches`, this method removes the prefix exactly
+    /// once.
+    ///
+    /// If the string does not start with `prefix`, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_strip)]
+    ///
+    /// assert_eq!("foobar".strip_prefix("foo"), Some("bar"));
+    /// assert_eq!("foobar".strip_prefix("bar"), None);
+    /// assert_eq!("foofoo".strip_prefix("foo"), Some("foo"));
+    /// ```
+    #[must_use = "this returns the remaining substring as a new slice, \
+                  without modifying the original"]
+    #[unstable(feature = "str_strip", reason = "newly added", issue = "67302")]
+    pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> {
+        let mut matcher = prefix.into_searcher(self);
+        if let SearchStep::Match(start, len) = matcher.next() {
+            debug_assert_eq!(start, 0, "The first search step from Searcher \
+                must include the first character");
+            unsafe {
+                // Searcher is known to return valid indices.
+                Some(self.get_unchecked(len..))
+            }
+        } else {
+            None
+        }
+    }
+
+    /// Returns a string slice with the suffix removed.
+    ///
+    /// If the string ends with the pattern `suffix`, `Some` is returned with the substring where
+    /// the suffix is removed. Unlike `trim_end_matches`, this method removes the suffix exactly
+    /// once.
+    ///
+    /// If the string does not end with `suffix`, `None` is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_strip)]
+    /// assert_eq!("barfoo".strip_suffix("foo"), Some("bar"));
+    /// assert_eq!("barfoo".strip_suffix("bar"), None);
+    /// assert_eq!("foofoo".strip_suffix("foo"), Some("foo"));
+    /// ```
+    #[must_use = "this returns the remaining substring as a new slice, \
+                  without modifying the original"]
+    #[unstable(feature = "str_strip", reason = "newly added", issue = "67302")]
+    pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str>
+    where
+        P: Pattern<'a>,
+        <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>,
+    {
+        let mut matcher = suffix.into_searcher(self);
+        if let SearchStep::Match(start, end) = matcher.next_back() {
+            debug_assert_eq!(end, self.len(), "The first search step from ReverseSearcher \
+                must include the last character");
+            unsafe {
+                // Searcher is known to return valid indices.
+                Some(self.get_unchecked(..start))
+            }
+        } else {
+            None
+        }
+    }
+
     /// Returns a string slice with all suffixes that match a pattern
     /// repeatedly removed.
     ///
diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs
index 1037da14b5f..b7ebd5f88b5 100644
--- a/src/libcore/str/pattern.rs
+++ b/src/libcore/str/pattern.rs
@@ -445,21 +445,13 @@ impl<'a> Pattern<'a> for char {
 
     #[inline]
     fn is_prefix_of(self, haystack: &'a str) -> bool {
-        if let Some(ch) = haystack.chars().next() {
-            self == ch
-        } else {
-            false
-        }
+        self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack)
     }
 
     #[inline]
     fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a>
     {
-        if let Some(ch) = haystack.chars().next_back() {
-            self == ch
-        } else {
-            false
-        }
+        self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack)
     }
 }
 
@@ -710,16 +702,13 @@ impl<'a, 'b> Pattern<'a> for &'b str {
     /// Checks whether the pattern matches at the front of the haystack
     #[inline]
     fn is_prefix_of(self, haystack: &'a str) -> bool {
-        haystack.is_char_boundary(self.len()) &&
-            self == &haystack[..self.len()]
+        haystack.as_bytes().starts_with(self.as_bytes())
     }
 
     /// Checks whether the pattern matches at the back of the haystack
     #[inline]
     fn is_suffix_of(self, haystack: &'a str) -> bool {
-        self.len() <= haystack.len() &&
-            haystack.is_char_boundary(haystack.len() - self.len()) &&
-            self == &haystack[haystack.len() - self.len()..]
+        haystack.as_bytes().ends_with(self.as_bytes())
     }
 }
 
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 6e1aac00c7b..1f09895597a 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -331,6 +331,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_atomic_new", since = "1.32.0")]
     pub const fn new(v: bool) -> AtomicBool {
         AtomicBool { v: UnsafeCell::new(v as u8) }
     }
@@ -855,6 +856,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_atomic_new", since = "1.32.0")]
     pub const fn new(p: *mut T) -> AtomicPtr<T> {
         AtomicPtr { p: UnsafeCell::new(p) }
     }
@@ -1183,6 +1185,7 @@ macro_rules! atomic_int {
      $stable_access:meta,
      $stable_from:meta,
      $stable_nand:meta,
+     $const_stable:meta,
      $stable_init_const:meta,
      $s_int_type:expr, $int_ref:expr,
      $extra_feature:expr,
@@ -1258,8 +1261,9 @@ let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
 ```"),
                 #[inline]
                 #[$stable]
+                #[$const_stable]
                 pub const fn new(v: $int_type) -> Self {
-                    $atomic_type {v: UnsafeCell::new(v)}
+                    Self {v: UnsafeCell::new(v)}
                 }
             }
 
@@ -1978,6 +1982,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i8", "../../../std/primitive.i8.html",
     "",
@@ -1995,6 +2000,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u8", "../../../std/primitive.u8.html",
     "",
@@ -2012,6 +2018,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i16", "../../../std/primitive.i16.html",
     "",
@@ -2029,6 +2036,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u16", "../../../std/primitive.u16.html",
     "",
@@ -2046,6 +2054,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i32", "../../../std/primitive.i32.html",
     "",
@@ -2063,6 +2072,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u32", "../../../std/primitive.u32.html",
     "",
@@ -2080,6 +2090,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i64", "../../../std/primitive.i64.html",
     "",
@@ -2097,6 +2108,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u64", "../../../std/primitive.u64.html",
     "",
@@ -2114,6 +2126,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i128", "../../../std/primitive.i128.html",
     "#![feature(integer_atomics)]\n\n",
@@ -2131,6 +2144,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u128", "../../../std/primitive.u128.html",
     "#![feature(integer_atomics)]\n\n",
@@ -2163,6 +2177,7 @@ atomic_int!{
     stable(feature = "atomic_access", since = "1.15.0"),
     stable(feature = "atomic_from", since = "1.23.0"),
     stable(feature = "atomic_nand", since = "1.27.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     stable(feature = "rust1", since = "1.0.0"),
     "isize", "../../../std/primitive.isize.html",
     "",
@@ -2180,6 +2195,7 @@ atomic_int!{
     stable(feature = "atomic_access", since = "1.15.0"),
     stable(feature = "atomic_from", since = "1.23.0"),
     stable(feature = "atomic_nand", since = "1.27.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     stable(feature = "rust1", since = "1.0.0"),
     "usize", "../../../std/primitive.usize.html",
     "",
diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs
index 0759ff93ea8..b070b665b4d 100644
--- a/src/libcore/task/wake.rs
+++ b/src/libcore/task/wake.rs
@@ -39,6 +39,7 @@ impl RawWaker {
     /// function in the `vtable` of the underlying `RawWaker` will be called.
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
+    #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
     pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
         RawWaker { data, vtable }
     }
@@ -151,6 +152,7 @@ impl RawWakerVTable {
     // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
     // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
     #[rustc_allow_const_fn_ptr]
+    #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
     pub const fn new(
         clone: unsafe fn(*const ()) -> RawWaker,
         wake: unsafe fn(*const ()),
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index 70ec1e42fd7..c1d405239f9 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -130,6 +130,7 @@ impl Duration {
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
+    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub fn new(secs: u64, nanos: u32) -> Duration {
         let secs =
             secs.checked_add((nanos / NANOS_PER_SEC) as u64).expect("overflow in Duration::new");
@@ -152,6 +153,7 @@ impl Duration {
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     #[rustc_promotable]
+    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_secs(secs: u64) -> Duration {
         Duration { secs, nanos: 0 }
     }
@@ -171,6 +173,7 @@ impl Duration {
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     #[rustc_promotable]
+    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_millis(millis: u64) -> Duration {
         Duration {
             secs: millis / MILLIS_PER_SEC,
@@ -193,6 +196,7 @@ impl Duration {
     #[stable(feature = "duration_from_micros", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
+    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_micros(micros: u64) -> Duration {
         Duration {
             secs: micros / MICROS_PER_SEC,
@@ -215,6 +219,7 @@ impl Duration {
     #[stable(feature = "duration_extras", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
+    #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_nanos(nanos: u64) -> Duration {
         Duration {
             secs: nanos / (NANOS_PER_SEC as u64),
@@ -251,6 +256,7 @@ impl Duration {
     ///
     /// [`subsec_nanos`]: #method.subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
+    #[rustc_const_stable(feature = "duration", since = "1.32.0")]
     #[inline]
     pub const fn as_secs(&self) -> u64 {
         self.secs
@@ -272,6 +278,7 @@ impl Duration {
     /// assert_eq!(duration.subsec_millis(), 432);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
     #[inline]
     pub const fn subsec_millis(&self) -> u32 {
         self.nanos / NANOS_PER_MILLI
@@ -293,6 +300,7 @@ impl Duration {
     /// assert_eq!(duration.subsec_micros(), 234_567);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
     #[inline]
     pub const fn subsec_micros(&self) -> u32 {
         self.nanos / NANOS_PER_MICRO
@@ -314,6 +322,7 @@ impl Duration {
     /// assert_eq!(duration.subsec_nanos(), 10_000_000);
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
+    #[rustc_const_stable(feature = "duration", since = "1.32.0")]
     #[inline]
     pub const fn subsec_nanos(&self) -> u32 {
         self.nanos
@@ -330,6 +339,7 @@ impl Duration {
     /// assert_eq!(duration.as_millis(), 5730);
     /// ```
     #[stable(feature = "duration_as_u128", since = "1.33.0")]
+    #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")]
     #[inline]
     pub const fn as_millis(&self) -> u128 {
         self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
@@ -346,6 +356,7 @@ impl Duration {
     /// assert_eq!(duration.as_micros(), 5730023);
     /// ```
     #[stable(feature = "duration_as_u128", since = "1.33.0")]
+    #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")]
     #[inline]
     pub const fn as_micros(&self) -> u128 {
         self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
@@ -362,6 +373,7 @@ impl Duration {
     /// assert_eq!(duration.as_nanos(), 5730023852);
     /// ```
     #[stable(feature = "duration_as_u128", since = "1.33.0")]
+    #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")]
     #[inline]
     pub const fn as_nanos(&self) -> u128 {
         self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e13f6cabb52..3f8085f2344 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -477,11 +477,11 @@ impl<'a> LoweringContext<'a> {
                 });
             }
 
-            fn visit_trait_item(&mut self, item: &'tcx TraitItem) {
+            fn visit_trait_item(&mut self, item: &'tcx AssocItem) {
                 self.lctx.allocate_hir_id_counter(item.id);
 
                 match item.kind {
-                    TraitItemKind::Method(_, None) => {
+                    AssocItemKind::Fn(_, None) => {
                         // Ignore patterns in trait methods without bodies
                         self.with_hir_id_owner(None, |this| {
                             visit::walk_trait_item(this, item)
@@ -493,7 +493,7 @@ impl<'a> LoweringContext<'a> {
                 }
             }
 
-            fn visit_impl_item(&mut self, item: &'tcx ImplItem) {
+            fn visit_impl_item(&mut self, item: &'tcx AssocItem) {
                 self.lctx.allocate_hir_id_counter(item.id);
                 self.with_hir_id_owner(Some(item.id), |this| {
                     visit::walk_impl_item(this, item);
@@ -1211,7 +1211,7 @@ impl<'a> LoweringContext<'a> {
                             let ct = self.with_new_scopes(|this| {
                                 hir::AnonConst {
                                     hir_id: this.lower_node_id(node_id),
-                                    body: this.lower_const_body(&path_expr),
+                                    body: this.lower_const_body(path_expr.span, Some(&path_expr)),
                                 }
                             });
                             return GenericArg::Const(ConstArg {
@@ -1253,6 +1253,14 @@ impl<'a> LoweringContext<'a> {
         ty
     }
 
+    fn ty(&mut self, span: Span, kind: hir::TyKind) -> hir::Ty {
+        hir::Ty { hir_id: self.next_id(), kind, span }
+    }
+
+    fn ty_tup(&mut self, span: Span, tys: HirVec<hir::Ty>) -> hir::Ty {
+        self.ty(span, hir::TyKind::Tup(tys))
+    }
+
     fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
@@ -1418,7 +1426,13 @@ impl<'a> LoweringContext<'a> {
                 }
             }
             TyKind::Mac(_) => bug!("`TyKind::Mac` should have been expanded by now"),
-            TyKind::CVarArgs => bug!("`TyKind::CVarArgs` should have been handled elsewhere"),
+            TyKind::CVarArgs => {
+                self.sess.delay_span_bug(
+                    t.span,
+                    "`TyKind::CVarArgs` should have been handled elsewhere",
+                );
+                hir::TyKind::Err
+            }
         };
 
         hir::Ty {
@@ -2084,32 +2098,19 @@ impl<'a> LoweringContext<'a> {
                     .iter()
                     .map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed()))
                     .collect();
-                let mk_tup = |this: &mut Self, tys, span| {
-                    hir::Ty { kind: hir::TyKind::Tup(tys), hir_id: this.next_id(), span }
+                let output_ty = match output {
+                    FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
+                    FunctionRetTy::Default(_) => P(this.ty_tup(span, hir::HirVec::new())),
+                };
+                let args = hir_vec![GenericArg::Type(this.ty_tup(span, inputs))];
+                let binding = hir::TypeBinding {
+                    hir_id: this.next_id(),
+                    ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
+                    span: output_ty.span,
+                    kind: hir::TypeBindingKind::Equality { ty: output_ty },
                 };
                 (
-                    hir::GenericArgs {
-                        args: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))],
-                        bindings: hir_vec![
-                            hir::TypeBinding {
-                                hir_id: this.next_id(),
-                                ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
-                                kind: hir::TypeBindingKind::Equality {
-                                    ty: output
-                                        .as_ref()
-                                        .map(|ty| this.lower_ty(
-                                            &ty,
-                                            ImplTraitContext::disallowed()
-                                        ))
-                                        .unwrap_or_else(||
-                                            P(mk_tup(this, hir::HirVec::new(), span))
-                                        ),
-                                },
-                                span: output.as_ref().map_or(span, |ty| ty.span),
-                            }
-                        ],
-                        parenthesized: true,
-                    },
+                    hir::GenericArgs { args, bindings: hir_vec![binding], parenthesized: true },
                     false,
                 )
             }
@@ -2474,17 +2475,13 @@ impl<'a> LoweringContext<'a> {
             })
         );
 
-        // Create the `Foo<...>` refernece itself. Note that the `type
+        // Create the `Foo<...>` reference itself. Note that the `type
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited.  It's
         // only the lifetime parameters that we must supply.
         let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args.into());
-
-        hir::FunctionRetTy::Return(P(hir::Ty {
-            kind: opaque_ty_ref,
-            span: opaque_ty_span,
-            hir_id: self.next_id(),
-        }))
+        let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
+        hir::FunctionRetTy::Return(P(opaque_ty))
     }
 
     /// Transforms `-> T` into `Future<Output = T>`
@@ -2496,16 +2493,8 @@ impl<'a> LoweringContext<'a> {
     ) -> hir::GenericBound {
         // Compute the `T` in `Future<Output = T>` from the return type.
         let output_ty = match output {
-            FunctionRetTy::Ty(ty) => {
-                self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id)))
-            }
-            FunctionRetTy::Default(ret_ty_span) => {
-                P(hir::Ty {
-                    hir_id: self.next_id(),
-                    kind: hir::TyKind::Tup(hir_vec![]),
-                    span: *ret_ty_span,
-                })
-            }
+            FunctionRetTy::Ty(ty) => self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id))),
+            FunctionRetTy::Default(ret_ty_span) => P(self.ty_tup(*ret_ty_span, hir_vec![])),
         };
 
         // "<Output = T>"
@@ -2852,19 +2841,23 @@ impl<'a> LoweringContext<'a> {
         let mut rest = None;
 
         let mut iter = pats.iter().enumerate();
-        while let Some((idx, pat)) = iter.next() {
-            // Interpret the first `..` pattern as a subtuple pattern.
+        for (idx, pat) in iter.by_ref() {
+            // Interpret the first `..` pattern as a sub-tuple pattern.
+            // Note that unlike for slice patterns,
+            // where `xs @ ..` is a legal sub-slice pattern,
+            // it is not a legal sub-tuple pattern.
             if pat.is_rest() {
                 rest = Some((idx, pat.span));
                 break;
             }
-            // It was not a subslice pattern so lower it normally.
+            // It was not a sub-tuple pattern so lower it normally.
             elems.push(self.lower_pat(pat));
         }
 
-        while let Some((_, pat)) = iter.next() {
-            // There was a previous subtuple pattern; make sure we don't allow more.
+        for (_, pat) in iter {
+            // There was a previous sub-tuple pattern; make sure we don't allow more...
             if pat.is_rest() {
+                // ...but there was one again, so error.
                 self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
             } else {
                 elems.push(self.lower_pat(pat));
@@ -2874,6 +2867,12 @@ impl<'a> LoweringContext<'a> {
         (elems.into(), rest.map(|(ddpos, _)| ddpos))
     }
 
+    /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
+    /// `hir::PatKind::Slice(before, slice, after)`.
+    ///
+    /// When encountering `($binding_mode $ident @)? ..` (`slice`),
+    /// this is interpreted as a sub-slice pattern semantically.
+    /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
     fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
         let mut before = Vec::new();
         let mut after = Vec::new();
@@ -2881,14 +2880,17 @@ impl<'a> LoweringContext<'a> {
         let mut prev_rest_span = None;
 
         let mut iter = pats.iter();
-        while let Some(pat) = iter.next() {
-            // Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
+        // Lower all the patterns until the first occurence of a sub-slice pattern.
+        for pat in iter.by_ref() {
             match pat.kind {
+                // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
                 PatKind::Rest => {
                     prev_rest_span = Some(pat.span);
                     slice = Some(self.pat_wild_with_node_id_of(pat));
                     break;
                 },
+                // Found a sub-slice pattern `$binding_mode $ident @ ..`.
+                // Record, lower it to `$binding_mode $ident @ _`, and stop here.
                 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
                     prev_rest_span = Some(sub.span);
                     let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
@@ -2896,14 +2898,13 @@ impl<'a> LoweringContext<'a> {
                     slice = Some(self.pat_with_node_id_of(pat, node));
                     break;
                 },
-                _ => {}
+                // It was not a subslice pattern so lower it normally.
+                _ => before.push(self.lower_pat(pat)),
             }
-
-            // It was not a subslice pattern so lower it normally.
-            before.push(self.lower_pat(pat));
         }
 
-        while let Some(pat) = iter.next() {
+        // Lower all the patterns after the first sub-slice pattern.
+        for pat in iter {
             // There was a previous subslice pattern; make sure we don't allow more.
             let rest_span = match pat.kind {
                 PatKind::Rest => Some(pat.span),
@@ -2915,8 +2916,10 @@ impl<'a> LoweringContext<'a> {
                 _ => None,
             };
             if let Some(rest_span) = rest_span {
+                // We have e.g., `[a, .., b, ..]`. That's no good, error!
                 self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
             } else {
+                // Lower the pattern normally.
                 after.push(self.lower_pat(pat));
             }
         }
@@ -3003,7 +3006,7 @@ impl<'a> LoweringContext<'a> {
         self.with_new_scopes(|this| {
             hir::AnonConst {
                 hir_id: this.lower_node_id(c.id),
-                body: this.lower_const_body(&c.value),
+                body: this.lower_const_body(c.value.span, Some(&c.value)),
             }
         })
     }
diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs
index ff9d8c85df8..46c944fa678 100644
--- a/src/librustc/hir/lowering/item.rs
+++ b/src/librustc/hir/lowering/item.rs
@@ -86,7 +86,7 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
         }
     }
 
-    fn visit_trait_item(&mut self, item: &'tcx TraitItem) {
+    fn visit_trait_item(&mut self, item: &'tcx AssocItem) {
         self.lctx.with_hir_id_owner(item.id, |lctx| {
             let hir_item = lctx.lower_trait_item(item);
             let id = hir::TraitItemId { hir_id: hir_item.hir_id };
@@ -97,7 +97,7 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
         visit::walk_trait_item(self, item);
     }
 
-    fn visit_impl_item(&mut self, item: &'tcx ImplItem) {
+    fn visit_impl_item(&mut self, item: &'tcx AssocItem) {
         self.lctx.with_hir_id_owner(item.id, |lctx| {
             let hir_item = lctx.lower_impl_item(item);
             let id = hir::ImplItemId { hir_id: hir_item.hir_id };
@@ -250,7 +250,7 @@ impl LoweringContext<'_> {
             return None;
         }
 
-        let kind = self.lower_item_kind(i.id, &mut ident, &attrs, &mut vis, &i.kind);
+        let kind = self.lower_item_kind(i.span, i.id, &mut ident, &attrs, &mut vis, &i.kind);
 
         Some(hir::Item {
             hir_id: self.lower_node_id(i.id),
@@ -264,6 +264,7 @@ impl LoweringContext<'_> {
 
     fn lower_item_kind(
         &mut self,
+        span: Span,
         id: NodeId,
         ident: &mut Ident,
         attrs: &hir::HirVec<Attribute>,
@@ -292,7 +293,7 @@ impl LoweringContext<'_> {
                         }
                     ),
                     m,
-                    self.lower_const_body(e),
+                    self.lower_const_body(span, Some(e)),
                 )
             }
             ItemKind::Const(ref t, ref e) => {
@@ -305,7 +306,7 @@ impl LoweringContext<'_> {
                             ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
                         }
                     ),
-                    self.lower_const_body(e)
+                    self.lower_const_body(span, Some(e))
                 )
             }
             ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => {
@@ -317,7 +318,12 @@ impl LoweringContext<'_> {
                     // `impl Future<Output = T>` here because lower_body
                     // only cares about the input argument patterns in the function
                     // declaration (decl), not the return types.
-                    let body_id = this.lower_maybe_async_body(&decl, header.asyncness.node, body);
+                    let body_id = this.lower_maybe_async_body(
+                        span,
+                        &decl,
+                        header.asyncness.node,
+                        Some(body),
+                    );
 
                     let (generics, decl) = this.add_in_band_defs(
                         generics,
@@ -807,20 +813,20 @@ impl LoweringContext<'_> {
         }
     }
 
-    fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
+    fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem {
         let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
-            TraitItemKind::Const(ref ty, ref default) => (
+            AssocItemKind::Const(ref ty, ref default) => (
                 self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
                 hir::TraitItemKind::Const(
                     self.lower_ty(ty, ImplTraitContext::disallowed()),
                     default
                         .as_ref()
-                        .map(|x| self.lower_const_body(x)),
+                        .map(|x| self.lower_const_body(i.span, Some(x))),
                 ),
             ),
-            TraitItemKind::Method(ref sig, None) => {
+            AssocItemKind::Fn(ref sig, None) => {
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) = self.lower_method_sig(
                     &i.generics,
@@ -831,8 +837,8 @@ impl LoweringContext<'_> {
                 );
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
             }
-            TraitItemKind::Method(ref sig, Some(ref body)) => {
-                let body_id = self.lower_fn_body_block(&sig.decl, body);
+            AssocItemKind::Fn(ref sig, Some(ref body)) => {
+                let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body));
                 let (generics, sig) = self.lower_method_sig(
                     &i.generics,
                     sig,
@@ -842,7 +848,7 @@ impl LoweringContext<'_> {
                 );
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
             }
-            TraitItemKind::Type(ref bounds, ref default) => {
+            AssocItemKind::TyAlias(ref bounds, ref default) => {
                 let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
                 let kind = hir::TraitItemKind::Type(
                     self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
@@ -853,7 +859,7 @@ impl LoweringContext<'_> {
 
                 (generics, kind)
             },
-            TraitItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
+            AssocItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"),
         };
 
         hir::TraitItem {
@@ -866,21 +872,21 @@ impl LoweringContext<'_> {
         }
     }
 
-    fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
+    fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
         let (kind, has_default) = match i.kind {
-            TraitItemKind::Const(_, ref default) => {
+            AssocItemKind::Const(_, ref default) => {
                 (hir::AssocItemKind::Const, default.is_some())
             }
-            TraitItemKind::Type(_, ref default) => {
+            AssocItemKind::TyAlias(_, ref default) => {
                 (hir::AssocItemKind::Type, default.is_some())
             }
-            TraitItemKind::Method(ref sig, ref default) => (
+            AssocItemKind::Fn(ref sig, ref default) => (
                 hir::AssocItemKind::Method {
                     has_self: sig.decl.has_self(),
                 },
                 default.is_some(),
             ),
-            TraitItemKind::Macro(..) => unimplemented!(),
+            AssocItemKind::Macro(..) => unimplemented!(),
         };
         hir::TraitItemRef {
             id: hir::TraitItemId { hir_id: self.lower_node_id(i.id) },
@@ -891,21 +897,29 @@ impl LoweringContext<'_> {
         }
     }
 
-    fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
+    /// Construct `ExprKind::Err` for the given `span`.
+    fn expr_err(&mut self, span: Span) -> hir::Expr {
+        self.expr(span, hir::ExprKind::Err, ThinVec::new())
+    }
+
+    fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem {
         let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
-            ImplItemKind::Const(ref ty, ref expr) => (
+            AssocItemKind::Const(ref ty, ref expr) => (
                 self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
                 hir::ImplItemKind::Const(
                     self.lower_ty(ty, ImplTraitContext::disallowed()),
-                    self.lower_const_body(expr),
+                    self.lower_const_body(i.span, expr.as_deref()),
                 ),
             ),
-            ImplItemKind::Method(ref sig, ref body) => {
+            AssocItemKind::Fn(ref sig, ref body) => {
                 self.current_item = Some(i.span);
                 let body_id = self.lower_maybe_async_body(
-                    &sig.decl, sig.header.asyncness.node, body
+                    i.span,
+                    &sig.decl,
+                    sig.header.asyncness.node,
+                    body.as_deref(),
                 );
                 let impl_trait_return_allow = !self.is_in_trait_impl;
                 let (generics, sig) = self.lower_method_sig(
@@ -918,21 +932,26 @@ impl LoweringContext<'_> {
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
-            ImplItemKind::TyAlias(ref ty) => {
+            AssocItemKind::TyAlias(_, ref ty) => {
                 let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
-                let kind = match ty.kind.opaque_top_hack() {
+                let kind = match ty {
                     None => {
-                        let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
-                        hir::ImplItemKind::TyAlias(ty)
+                        hir::ImplItemKind::TyAlias(P(self.ty(i.span, hir::TyKind::Err)))
                     }
-                    Some(bs) => {
-                        let bounds = self.lower_param_bounds(bs, ImplTraitContext::disallowed());
-                        hir::ImplItemKind::OpaqueTy(bounds)
+                    Some(ty) => match ty.kind.opaque_top_hack() {
+                        None => {
+                            let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
+                            hir::ImplItemKind::TyAlias(ty)
+                        }
+                        Some(bs) => {
+                            let bs = self.lower_param_bounds(bs, ImplTraitContext::disallowed());
+                            hir::ImplItemKind::OpaqueTy(bs)
+                        }
                     }
                 };
                 (generics, kind)
             },
-            ImplItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"),
+            AssocItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"),
         };
 
         hir::ImplItem {
@@ -949,7 +968,7 @@ impl LoweringContext<'_> {
         // [1] since `default impl` is not yet implemented, this is always true in impls
     }
 
-    fn lower_impl_item_ref(&mut self, i: &ImplItem) -> hir::ImplItemRef {
+    fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
         hir::ImplItemRef {
             id: hir::ImplItemId { hir_id: self.lower_node_id(i.id) },
             ident: i.ident,
@@ -957,15 +976,18 @@ impl LoweringContext<'_> {
             vis: self.lower_visibility(&i.vis, Some(i.id)),
             defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
             kind: match &i.kind {
-                ImplItemKind::Const(..) => hir::AssocItemKind::Const,
-                ImplItemKind::TyAlias(ty) => match ty.kind.opaque_top_hack() {
+                AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+                AssocItemKind::TyAlias(_, ty) => match ty
+                    .as_deref()
+                    .and_then(|ty| ty.kind.opaque_top_hack())
+                {
                     None => hir::AssocItemKind::Type,
                     Some(_) => hir::AssocItemKind::OpaqueTy,
                 },
-                ImplItemKind::Method(sig, _) => hir::AssocItemKind::Method {
+                AssocItemKind::Fn(sig, _) => hir::AssocItemKind::Method {
                     has_self: sig.decl.has_self(),
                 },
-                ImplItemKind::Macro(..) => unimplemented!(),
+                AssocItemKind::Macro(..) => unimplemented!(),
             },
         }
 
@@ -1063,23 +1085,39 @@ impl LoweringContext<'_> {
         ))
     }
 
-    fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId {
-        self.lower_fn_body(decl, |this| this.lower_block_expr(body))
+    fn lower_fn_body_block(
+        &mut self,
+        span: Span,
+        decl: &FnDecl,
+        body: Option<&Block>,
+    ) -> hir::BodyId {
+        self.lower_fn_body(decl, |this| this.lower_block_expr_opt(span, body))
+    }
+
+    fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr {
+        match block {
+            Some(block) => self.lower_block_expr(block),
+            None => self.expr_err(span),
+        }
     }
 
-    pub(super) fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId {
-        self.lower_body(|this| (hir_vec![], this.lower_expr(expr)))
+    pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
+        self.lower_body(|this| (hir_vec![], match expr {
+            Some(expr) => this.lower_expr(expr),
+            None => this.expr_err(span),
+        }))
     }
 
     fn lower_maybe_async_body(
         &mut self,
+        span: Span,
         decl: &FnDecl,
         asyncness: IsAsync,
-        body: &Block,
+        body: Option<&Block>,
     ) -> hir::BodyId {
         let closure_id = match asyncness {
             IsAsync::Async { closure_id, .. } => closure_id,
-            IsAsync::NotAsync => return self.lower_fn_body_block(decl, body),
+            IsAsync::NotAsync => return self.lower_fn_body_block(span, decl, body),
         };
 
         self.lower_body(|this| {
@@ -1213,15 +1251,16 @@ impl LoweringContext<'_> {
                 parameters.push(new_parameter);
             }
 
+            let body_span = body.map_or(span, |b| b.span);
             let async_expr = this.make_async_expr(
                 CaptureBy::Value,
                 closure_id,
                 None,
-                body.span,
+                body_span,
                 hir::AsyncGeneratorKind::Fn,
                 |this| {
                     // Create a block from the user's function body:
-                    let user_body = this.lower_block_expr(body);
+                    let user_body = this.lower_block_expr_opt(body_span, body);
 
                     // Transform into `drop-temps { <user-body> }`, an expression:
                     let desugared_span = this.mark_span_with_reason(
@@ -1251,7 +1290,7 @@ impl LoweringContext<'_> {
                     );
                     this.expr_block(P(body), ThinVec::new())
                 });
-            (HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new()))
+            (HirVec::from(parameters), this.expr(body_span, async_expr, ThinVec::new()))
         })
     }
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 5bf5a93ad01..69e772697f8 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -1016,8 +1016,8 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    pub fn name(&self, id: HirId) -> Name {
-        match self.get(id) {
+    pub fn opt_name(&self, id: HirId) -> Option<Name> {
+        Some(match self.get(id) {
             Node::Item(i) => i.ident.name,
             Node::ForeignItem(fi) => fi.ident.name,
             Node::ImplItem(ii) => ii.ident.name,
@@ -1028,7 +1028,14 @@ impl<'hir> Map<'hir> {
             Node::GenericParam(param) => param.name.ident().name,
             Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
             Node::Ctor(..) => self.name(self.get_parent_item(id)),
-            _ => bug!("no name for {}", self.node_to_string(id))
+            _ => return None,
+        })
+    }
+
+    pub fn name(&self, id: HirId) -> Name {
+        match self.opt_name(id) {
+            Some(name) => name,
+            None => bug!("no name for {}", self.node_to_string(id)),
         }
     }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 66bb3a8d883..6b354b01518 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1048,8 +1048,15 @@ pub enum PatKind {
     /// A range pattern (e.g., `1..=2` or `1..2`).
     Range(P<Expr>, P<Expr>, RangeEnd),
 
-    /// `[a, b, ..i, y, z]` is represented as:
-    ///     `PatKind::Slice(box [a, b], Some(i), box [y, z])`.
+    /// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
+    ///
+    /// Here, `slice` is lowered from the syntax `($binding_mode $ident @)? ..`.
+    /// If `slice` exists, then `after` can be non-empty.
+    ///
+    /// The representation for e.g., `[a, b, .., c, d]` is:
+    /// ```
+    /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
+    /// ```
     Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
 }
 
diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs
index ece438266c0..cd2e32de9d5 100644
--- a/src/librustc/ich/mod.rs
+++ b/src/librustc/ich/mod.rs
@@ -12,21 +12,13 @@ mod impls_hir;
 mod impls_ty;
 mod impls_syntax;
 
-pub const ATTR_DIRTY: Symbol = sym::rustc_dirty;
-pub const ATTR_CLEAN: Symbol = sym::rustc_clean;
-pub const ATTR_IF_THIS_CHANGED: Symbol = sym::rustc_if_this_changed;
-pub const ATTR_THEN_THIS_WOULD_NEED: Symbol = sym::rustc_then_this_would_need;
-pub const ATTR_PARTITION_REUSED: Symbol = sym::rustc_partition_reused;
-pub const ATTR_PARTITION_CODEGENED: Symbol = sym::rustc_partition_codegened;
-pub const ATTR_EXPECTED_CGU_REUSE: Symbol = sym::rustc_expected_cgu_reuse;
-
 pub const IGNORED_ATTRIBUTES: &[Symbol] = &[
     sym::cfg,
-    ATTR_IF_THIS_CHANGED,
-    ATTR_THEN_THIS_WOULD_NEED,
-    ATTR_DIRTY,
-    ATTR_CLEAN,
-    ATTR_PARTITION_REUSED,
-    ATTR_PARTITION_CODEGENED,
-    ATTR_EXPECTED_CGU_REUSE,
+    sym::rustc_if_this_changed,
+    sym::rustc_then_this_would_need,
+    sym::rustc_dirty,
+    sym::rustc_clean,
+    sym::rustc_partition_reused,
+    sym::rustc_partition_codegened,
+    sym::rustc_expected_cgu_reuse,
 ];
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 58c1498faa9..c9d57706d55 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -70,6 +70,7 @@ use std::{cmp, fmt};
 mod note;
 
 mod need_type_info;
+pub use need_type_info::TypeAnnotationNeeded;
 
 pub mod nice_region_error;
 
diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs
index 32eecdf01a3..ebb94cc72ff 100644
--- a/src/librustc/infer/error_reporting/need_type_info.rs
+++ b/src/librustc/infer/error_reporting/need_type_info.rs
@@ -1,13 +1,15 @@
-use crate::hir::def::Namespace;
+use crate::hir::def::{DefKind, Namespace};
 use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat};
 use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::infer::InferCtxt;
 use crate::infer::type_variable::TypeVariableOriginKind;
-use crate::ty::{self, Ty, Infer, TyVar};
+use crate::ty::{self, Ty, Infer, TyVar, DefIdTree};
 use crate::ty::print::Print;
 use syntax::source_map::DesugaringKind;
+use syntax::symbol::kw;
 use syntax_pos::Span;
 use errors::{Applicability, DiagnosticBuilder};
+use std::borrow::Cow;
 
 use rustc_error_codes::*;
 
@@ -19,6 +21,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> {
     found_arg_pattern: Option<&'tcx Pat>,
     found_ty: Option<Ty<'tcx>>,
     found_closure: Option<&'tcx ExprKind>,
+    found_method_call: Option<&'tcx Expr>,
 }
 
 impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
@@ -35,6 +38,7 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> {
             found_arg_pattern: None,
             found_ty: None,
             found_closure: None,
+            found_method_call: None,
         }
     }
 
@@ -93,11 +97,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
-        if let (ExprKind::Closure(_, _fn_decl, _id, _sp, _), Some(_)) = (
-            &expr.kind,
-            self.node_matches_type(expr.hir_id),
-        ) {
-            self.found_closure = Some(&expr.kind);
+        if self.node_matches_type(expr.hir_id).is_some() {
+            match expr.kind {
+                ExprKind::Closure(..) => self.found_closure = Some(&expr.kind),
+                ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
+                _ => {}
+            }
         }
         intravisit::walk_expr(self, expr);
     }
@@ -109,8 +114,11 @@ fn closure_return_type_suggestion(
     err: &mut DiagnosticBuilder<'_>,
     output: &FunctionRetTy,
     body: &Body,
+    descr: &str,
     name: &str,
     ret: &str,
+    parent_name: Option<String>,
+    parent_descr: Option<&str>,
 ) {
     let (arrow, post) = match output {
         FunctionRetTy::DefaultReturn(_) => ("-> ", " "),
@@ -132,7 +140,12 @@ fn closure_return_type_suggestion(
         suggestion,
         Applicability::HasPlaceholders,
     );
-    err.span_label(span, InferCtxt::missing_type_msg(&name));
+    err.span_label(span, InferCtxt::missing_type_msg(
+        &name,
+        &descr,
+        parent_name,
+        parent_descr
+    ));
 }
 
 /// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -147,17 +160,57 @@ fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
         .unwrap_or_default()
 }
 
+pub enum TypeAnnotationNeeded {
+    E0282,
+    E0283,
+    E0284,
+}
+
+impl Into<errors::DiagnosticId> for TypeAnnotationNeeded {
+    fn into(self) -> errors::DiagnosticId {
+        syntax::diagnostic_used!(E0282);
+        syntax::diagnostic_used!(E0283);
+        syntax::diagnostic_used!(E0284);
+        errors::DiagnosticId::Error(match self {
+            Self::E0282 => "E0282".to_string(),
+            Self::E0283 => "E0283".to_string(),
+            Self::E0284 => "E0284".to_string(),
+        })
+    }
+}
+
 impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn extract_type_name(
         &self,
         ty: Ty<'tcx>,
         highlight: Option<ty::print::RegionHighlightMode>,
-    ) -> (String, Option<Span>) {
+    ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
         if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind {
             let ty_vars = self.type_variables.borrow();
             let var_origin = ty_vars.var_origin(ty_vid);
-            if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind {
-                return (name.to_string(), Some(var_origin.span));
+            if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind {
+                let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
+                let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id {
+                    let parent_name = self.tcx.def_key(parent_def_id).disambiguated_data.data
+                        .get_opt_name().map(|parent_symbol| parent_symbol.to_string());
+
+                    let type_parent_desc = self.tcx.def_kind(parent_def_id)
+                        .map(|parent_def_kind| parent_def_kind.descr(parent_def_id));
+
+                    (parent_name, type_parent_desc)
+                } else {
+                    (None, None)
+                };
+
+                if name != kw::SelfUpper {
+                    return (
+                        name.to_string(),
+                        Some(var_origin.span),
+                        "type parameter".into(),
+                        parent_name,
+                        parent_desc,
+                    );
+                }
             }
         }
 
@@ -167,7 +220,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             printer.region_highlight_mode = highlight;
         }
         let _ = ty.print(printer);
-        (s, None)
+        (s, None, ty.prefix_string(), None, None)
     }
 
     pub fn need_type_info_err(
@@ -175,9 +228,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         body_id: Option<hir::BodyId>,
         span: Span,
         ty: Ty<'tcx>,
+        error_code: TypeAnnotationNeeded,
     ) -> DiagnosticBuilder<'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
-        let (name, name_sp) = self.extract_type_name(&ty, None);
+        let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
+
 
         let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir());
         let ty_to_string = |ty: Ty<'tcx>| -> String {
@@ -185,8 +240,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
             let ty_vars = self.type_variables.borrow();
             let getter = move |ty_vid| {
-                if let TypeVariableOriginKind::TypeParameterDefinition(name) =
-                    ty_vars.var_origin(ty_vid).kind {
+                let var_origin = ty_vars.var_origin(ty_vid);
+                if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind {
                     return Some(name.to_string());
                 }
                 None
@@ -210,6 +265,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             // 3 |     let _ = x.sum() as f64;
             //   |               ^^^ cannot infer type for `S`
             span
+        } else if let Some(
+            ExprKind::MethodCall(_, call_span, _),
+        ) = local_visitor.found_method_call.map(|e| &e.kind) {
+            // Point at the call instead of the whole expression:
+            // error[E0284]: type annotations needed
+            //  --> file.rs:2:5
+            //   |
+            // 2 |     vec![Ok(2)].into_iter().collect()?;
+            //   |                             ^^^^^^^ cannot infer type
+            //   |
+            //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
+            if span.contains(*call_span) {
+                *call_span
+            } else {
+                span
+            }
         } else {
             span
         };
@@ -247,12 +318,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         //   |         consider giving `b` the explicit type `std::result::Result<i32, E>`, where
         //   |         the type parameter `E` is specified
         // ```
-        let mut err = struct_span_err!(
-            self.tcx.sess,
+        let error_code = error_code.into();
+        let mut err = self.tcx.sess.struct_span_err_with_code(
             err_span,
-            E0282,
-            "type annotations needed{}",
-            ty_msg,
+            &format!("type annotations needed{}", ty_msg),
+            error_code,
         );
 
         let suffix = match local_visitor.found_ty {
@@ -267,8 +337,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                             &mut err,
                             &decl.output,
                             &body,
+                            &descr,
                             &name,
                             &ret,
+                            parent_name,
+                            parent_descr,
                         );
                         // We don't want to give the other suggestions when the problem is the
                         // closure return type.
@@ -334,6 +407,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 format!("consider giving this pattern {}", suffix)
             };
             err.span_label(pattern.span, msg);
+        } else if let Some(e) = local_visitor.found_method_call {
+            if let ExprKind::MethodCall(segment, ..) = &e.kind {
+                // Suggest specifiying type params or point out the return type of the call:
+                //
+                // error[E0282]: type annotations needed
+                //   --> $DIR/type-annotations-needed-expr.rs:2:39
+                //    |
+                // LL |     let _ = x.into_iter().sum() as f64;
+                //    |                           ^^^
+                //    |                           |
+                //    |                           cannot infer type for `S`
+                //    |                           help: consider specifying the type argument in
+                //    |                           the method call: `sum::<S>`
+                //    |
+                //    = note: type must be known at this point
+                //
+                // or
+                //
+                // error[E0282]: type annotations needed
+                //   --> $DIR/issue-65611.rs:59:20
+                //    |
+                // LL |     let x = buffer.last().unwrap().0.clone();
+                //    |             -------^^^^--
+                //    |             |      |
+                //    |             |      cannot infer type for `T`
+                //    |             this method call resolves to `std::option::Option<&T>`
+                //    |
+                //    = note: type must be known at this point
+                self.annotate_method_call(segment, e, &mut err);
+            }
         }
         // Instead of the following:
         // error[E0282]: type annotations needed
@@ -351,17 +454,70 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         //   |               ^^^ cannot infer type for `S`
         //   |
         //   = note: type must be known at this point
-        let span = name_sp.unwrap_or(span);
+        let span = name_sp.unwrap_or(err_span);
         if !err.span.span_labels().iter().any(|span_label| {
                 span_label.label.is_some() && span_label.span == span
             }) && local_visitor.found_arg_pattern.is_none()
-        { // Avoid multiple labels pointing at `span`.
-            err.span_label(span, InferCtxt::missing_type_msg(&name));
+        {
+            // Avoid multiple labels pointing at `span`.
+            err.span_label(
+                span,
+                InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)
+            );
         }
 
         err
     }
 
+    /// If the `FnSig` for the method call can be found and type arguments are identified as
+    /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
+    fn annotate_method_call(
+        &self,
+        segment: &hir::ptr::P<hir::PathSegment>,
+        e: &Expr,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if let (Ok(snippet), Some(tables), None) = (
+            self.tcx.sess.source_map().span_to_snippet(segment.ident.span),
+            self.in_progress_tables,
+            &segment.args,
+        ) {
+            let borrow = tables.borrow();
+            if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) {
+                let generics = self.tcx.generics_of(did);
+                if !generics.params.is_empty() {
+                    err.span_suggestion(
+                        segment.ident.span,
+                        &format!(
+                            "consider specifying the type argument{} in the method call",
+                            if generics.params.len() > 1 {
+                                "s"
+                            } else {
+                                ""
+                            },
+                        ),
+                        format!("{}::<{}>", snippet, generics.params.iter()
+                            .map(|p| p.name.to_string())
+                            .collect::<Vec<String>>()
+                            .join(", ")),
+                        Applicability::HasPlaceholders,
+                    );
+                } else {
+                    let sig = self.tcx.fn_sig(did);
+                    let bound_output = sig.output();
+                    let output = bound_output.skip_binder();
+                    err.span_label(e.span, &format!("this method call resolves to `{:?}`", output));
+                    let kind = &output.kind;
+                    if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind {
+                        if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
+                            err.span_label(span, &format!("`{:?}` defined here", output));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     pub fn need_type_info_err_in_generator(
         &self,
         kind: hir::GeneratorKind,
@@ -369,19 +525,42 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
         let ty = self.resolve_vars_if_possible(&ty);
-        let name = self.extract_type_name(&ty, None).0;
+        let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
+
         let mut err = struct_span_err!(
             self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind,
         );
-        err.span_label(span, InferCtxt::missing_type_msg(&name));
+        err.span_label(span, InferCtxt::missing_type_msg(
+            &name,
+            &descr,
+            parent_name,
+            parent_descr
+        ));
         err
     }
 
-    fn missing_type_msg(type_name: &str) -> String {
+    fn missing_type_msg(
+        type_name: &str,
+        descr: &str,
+        parent_name: Option<String>,
+        parent_descr: Option<&str>,
+    ) -> Cow<'static, str> {
         if type_name == "_" {
-            "cannot infer type".to_owned()
+            "cannot infer type".into()
         } else {
-            format!("cannot infer type for `{}`", type_name)
+            let parent_desc = if let Some(parent_name) = parent_name {
+                let parent_type_descr = if let Some(parent_descr) = parent_descr {
+                    format!(" the {}", parent_descr)
+                } else {
+                    "".into()
+                };
+
+                format!(" declared on{} `{}`", parent_type_descr, parent_name)
+            } else {
+                "".to_string()
+            };
+
+            format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into()
         }
     }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 73977878af3..996a722e157 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1135,7 +1135,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     self.universe(),
                     false,
                     TypeVariableOrigin {
-                        kind: TypeVariableOriginKind::TypeParameterDefinition(param.name),
+                        kind: TypeVariableOriginKind::TypeParameterDefinition(
+                            param.name,
+                            Some(param.def_id)
+                        ),
                         span,
                     },
                 );
diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs
index 613f66d7ffd..ea4a28c22a9 100644
--- a/src/librustc/infer/resolve.rs
+++ b/src/librustc/infer/resolve.rs
@@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
                 if let ty::TyVar(ty_vid) = infer_ty {
                     let ty_vars = self.infcx.type_variables.borrow();
                     if let TypeVariableOrigin {
-                        kind: TypeVariableOriginKind::TypeParameterDefinition(_),
+                        kind: TypeVariableOriginKind::TypeParameterDefinition(_, _),
                         span,
                     } = *ty_vars.var_origin(ty_vid)
                     {
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index f79a30c7ae8..5a12de25f4b 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -1,6 +1,7 @@
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use crate::ty::{self, Ty, TyVid};
+use crate::hir::def_id::DefId;
 
 use std::cmp;
 use std::marker::PhantomData;
@@ -49,7 +50,7 @@ pub enum TypeVariableOriginKind {
     MiscVariable,
     NormalizeProjectionType,
     TypeInference,
-    TypeParameterDefinition(Symbol),
+    TypeParameterDefinition(Symbol, Option<DefId>),
 
     /// One of the upvars or closure kind parameters in a `ClosureSubsts`
     /// (before it has been determined).
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 24b87ffc80c..641e6a4f614 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -37,7 +37,7 @@
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![cfg_attr(windows, feature(libc))]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(exhaustive_patterns)]
 #![feature(overlapping_marker_traits)]
 #![feature(extern_types)]
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 7f72154e42c..0fdd509a0bb 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -1249,7 +1249,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         ast_visit::walk_poly_trait_ref(self, t, m);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
+    fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) {
         self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
             run_early_pass!(cx, check_trait_item, trait_item);
             ast_visit::walk_trait_item(cx, trait_item);
@@ -1257,7 +1257,7 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         });
     }
 
-    fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
+    fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) {
         self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
             run_early_pass!(cx, check_impl_item, impl_item);
             ast_visit::walk_impl_item(cx, impl_item);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index a8d88686679..0054f149f8c 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -258,10 +258,10 @@ macro_rules! early_lint_methods {
                 c: Span,
                 d: ast::NodeId
             );
-            fn check_trait_item(a: &ast::TraitItem);
-            fn check_trait_item_post(a: &ast::TraitItem);
-            fn check_impl_item(a: &ast::ImplItem);
-            fn check_impl_item_post(a: &ast::ImplItem);
+            fn check_trait_item(a: &ast::AssocItem);
+            fn check_trait_item_post(a: &ast::AssocItem);
+            fn check_impl_item(a: &ast::AssocItem);
+            fn check_impl_item_post(a: &ast::AssocItem);
             fn check_struct_def(a: &ast::VariantData);
             fn check_struct_def_post(a: &ast::VariantData);
             fn check_struct_field(a: &ast::StructField);
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 54aafe2114d..51756084f24 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -19,7 +19,7 @@ use syntax_pos::{Span, MultiSpan};
 use syntax::ast::{Attribute, CRATE_NODE_ID};
 use syntax::errors::Applicability;
 use syntax::feature_gate::{feature_err, feature_err_issue};
-use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
+use syntax::attr::{self, Stability, Deprecation, RustcDeprecation, ConstStability};
 use crate::ty::{self, TyCtxt};
 use crate::util::nodemap::{FxHashSet, FxHashMap};
 
@@ -91,6 +91,7 @@ pub struct Index<'tcx> {
     /// This is mostly a cache, except the stabilities of local items
     /// are filled by the annotator.
     stab_map: FxHashMap<HirId, &'tcx Stability>,
+    const_stab_map: FxHashMap<HirId, &'tcx ConstStability>,
     depr_map: FxHashMap<HirId, DeprecationEntry>,
 
     /// Maps for each crate whether it is part of the staged API.
@@ -123,8 +124,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged API; \
                                                  use `#[rustc_deprecated]` instead");
             }
-            if let Some(mut stab) = attr::find_stability(&self.tcx.sess.parse_sess,
-                                                         attrs, item_sp) {
+            let (stab, const_stab) = attr::find_stability(
+                &self.tcx.sess.parse_sess, attrs, item_sp,
+            );
+            if let Some(const_stab) = const_stab {
+                let const_stab = self.tcx.intern_const_stability(const_stab);
+                self.index.const_stab_map.insert(hir_id, const_stab);
+            }
+            if let Some(mut stab) = stab {
                 // Error if prohibited, or can't inherit anything from a container.
                 if kind == AnnotationKind::Prohibited ||
                    (kind == AnnotationKind::Container &&
@@ -189,9 +196,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         } else {
             // Emit errors for non-staged-api crates.
+            let unstable_attrs = [
+                sym::unstable, sym::stable,
+                sym::rustc_deprecated,
+                sym::rustc_const_unstable,
+                sym::rustc_const_stable,
+            ];
             for attr in attrs {
                 let name = attr.name_or_empty();
-                if [sym::unstable, sym::stable, sym::rustc_deprecated].contains(&name) {
+                if unstable_attrs.contains(&name) {
                     attr::mark_used(attr);
                     struct_span_err!(
                         self.tcx.sess,
@@ -399,6 +412,7 @@ impl<'tcx> Index<'tcx> {
         let mut index = Index {
             staged_api,
             stab_map: Default::default(),
+            const_stab_map: Default::default(),
             depr_map: Default::default(),
             active_features: Default::default(),
         };
@@ -440,9 +454,6 @@ impl<'tcx> Index<'tcx> {
                     },
                     feature: sym::rustc_private,
                     rustc_depr: None,
-                    const_stability: None,
-                    promotable: false,
-                    allow_const_fn_ptr: false,
                 });
                 annotator.parent_stab = Some(stability);
             }
@@ -460,6 +471,10 @@ impl<'tcx> Index<'tcx> {
         self.stab_map.get(&id).cloned()
     }
 
+    pub fn local_const_stability(&self, id: HirId) -> Option<&'tcx ConstStability> {
+        self.const_stab_map.get(&id).cloned()
+    }
+
     pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> {
         self.depr_map.get(&id).cloned()
     }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index ba8feb4ee73..3b4adbaf78c 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2060,6 +2060,11 @@ pub enum Rvalue<'tcx> {
     /// &x or &mut x
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
 
+    /// Create a raw pointer to the given place
+    /// Can be generated by raw address of expressions (`&raw const x`),
+    /// or when casting a reference to a raw pointer.
+    AddressOf(Mutability, Place<'tcx>),
+
     /// length of a [X] or [X;n] value
     Len(Place<'tcx>),
 
@@ -2214,6 +2219,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                 write!(fmt, "&{}{}{:?}", region, kind_str, place)
             }
 
+            AddressOf(mutability, ref place) => {
+                let kind_str = match mutability {
+                    Mutability::Mut => "mut",
+                    Mutability::Not => "const",
+                };
+
+                write!(fmt, "&raw {} {:?}", kind_str, place)
+            }
+
             Aggregate(ref kind, ref places) => {
                 fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
                     let mut tuple_fmt = fmt.debug_tuple("");
@@ -3085,6 +3099,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
             Ref(region, bk, ref place) => {
                 Ref(region.fold_with(folder), bk, place.fold_with(folder))
             }
+            AddressOf(mutability, ref place) => {
+                AddressOf(mutability, place.fold_with(folder))
+            }
             Len(ref place) => Len(place.fold_with(folder)),
             Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
             BinaryOp(op, ref rhs, ref lhs) => {
@@ -3125,6 +3142,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
             Use(ref op) => op.visit_with(visitor),
             Repeat(ref op, _) => op.visit_with(visitor),
             Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
+            AddressOf(_, ref place) => place.visit_with(visitor),
             Len(ref place) => place.visit_with(visitor),
             Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
             BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 445fa6ea8ca..a24b1d863d6 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -172,6 +172,13 @@ impl<'tcx> Rvalue<'tcx> {
                     }
                 )
             }
+            Rvalue::AddressOf(mutability, ref place) => {
+                let place_ty = place.ty(local_decls, tcx).ty;
+                tcx.mk_ptr(ty::TypeAndMut {
+                    ty: place_ty,
+                    mutbl: mutability.into(),
+                })
+            }
             Rvalue::Len(..) => tcx.types.usize,
             Rvalue::Cast(.., ty) => ty,
             Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 5d273fe85b6..fa96b51347d 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -570,6 +570,18 @@ macro_rules! make_mir_visitor {
                         self.visit_place(path, ctx, location);
                     }
 
+                    Rvalue::AddressOf(m, path) => {
+                        let ctx = match m {
+                            Mutability::Mut => PlaceContext::MutatingUse(
+                                MutatingUseContext::AddressOf
+                            ),
+                            Mutability::Not => PlaceContext::NonMutatingUse(
+                                NonMutatingUseContext::AddressOf
+                            ),
+                        };
+                        self.visit_place(path, ctx, location);
+                    }
+
                     Rvalue::Len(path) => {
                         self.visit_place(
                             path,
@@ -1031,6 +1043,8 @@ pub enum NonMutatingUseContext {
     ShallowBorrow,
     /// Unique borrow.
     UniqueBorrow,
+    /// AddressOf for *const pointer.
+    AddressOf,
     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
     /// For example, the projection `x.y` is not marked as a mutation in these cases:
     ///
@@ -1054,6 +1068,8 @@ pub enum MutatingUseContext {
     Drop,
     /// Mutable borrow.
     Borrow,
+    /// AddressOf for *mut pointer.
+    AddressOf,
     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
     /// For example, the projection `x.y` is marked as a mutation in these cases:
     ///
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 538b13c79ce..cc02165f605 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -533,6 +533,7 @@ rustc_queries! {
             eval_always
         }
         query lookup_stability(_: DefId) -> Option<&'tcx attr::Stability> {}
+        query lookup_const_stability(_: DefId) -> Option<&'tcx attr::ConstStability> {}
         query lookup_deprecation_entry(_: DefId) -> Option<DeprecationEntry> {}
         query item_attrs(_: DefId) -> Lrc<[ast::Attribute]> {}
     }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 6a111895b56..4839974d625 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -22,6 +22,7 @@ use crate::hir;
 use crate::hir::Node;
 use crate::hir::def_id::DefId;
 use crate::infer::{self, InferCtxt};
+use crate::infer::error_reporting::TypeAnnotationNeeded as ErrorCode;
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::session::DiagnosticMessageId;
 use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
@@ -1952,7 +1953,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             return;
         }
 
-        match predicate {
+        let mut err = match predicate {
             ty::Predicate::Trait(ref data) => {
                 let trait_ref = data.to_poly_trait_ref();
                 let self_ty = trait_ref.self_ty();
@@ -1986,59 +1987,109 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 // avoid inundating the user with unnecessary errors, but we now
                 // check upstream for type errors and dont add the obligations to
                 // begin with in those cases.
-                if
-                    self.tcx.lang_items().sized_trait()
+                if self.tcx.lang_items().sized_trait()
                     .map_or(false, |sized_id| sized_id == trait_ref.def_id())
                 {
-                    self.need_type_info_err(body_id, span, self_ty).emit();
-                } else {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0283,
-                        "type annotations needed: cannot resolve `{}`",
-                        predicate,
-                    );
-                    self.note_obligation_cause(&mut err, obligation);
-                    err.emit();
+                    self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
+                    return;
+                }
+                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283);
+                err.note(&format!("cannot resolve `{}`", predicate));
+                if let (Ok(ref snippet), ObligationCauseCode::BindingObligation(ref def_id, _)) = (
+                    self.tcx.sess.source_map().span_to_snippet(span),
+                    &obligation.cause.code,
+                ) {
+                    let generics = self.tcx.generics_of(*def_id);
+                    if !generics.params.is_empty() && !snippet.ends_with('>'){
+                        // FIXME: To avoid spurious suggestions in functions where type arguments
+                        // where already supplied, we check the snippet to make sure it doesn't
+                        // end with a turbofish. Ideally we would have access to a `PathSegment`
+                        // instead. Otherwise we would produce the following output:
+                        //
+                        // error[E0283]: type annotations needed
+                        //   --> $DIR/issue-54954.rs:3:24
+                        //    |
+                        // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+                        //    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+                        //    |                        |
+                        //    |                        cannot infer type
+                        //    |                        help: consider specifying the type argument
+                        //    |                        in the function call:
+                        //    |                        `Tt::const_val::<[i8; 123]>::<T>`
+                        // ...
+                        // LL |     const fn const_val<T: Sized>() -> usize {
+                        //    |              --------- - required by this bound in `Tt::const_val`
+                        //    |
+                        //    = note: cannot resolve `_: Tt`
+
+                        err.span_suggestion(
+                            span,
+                            &format!(
+                                "consider specifying the type argument{} in the function call",
+                                if generics.params.len() > 1 {
+                                    "s"
+                                } else {
+                                    ""
+                                },
+                            ),
+                            format!("{}::<{}>", snippet, generics.params.iter()
+                                .map(|p| p.name.to_string())
+                                .collect::<Vec<String>>()
+                                .join(", ")),
+                            Applicability::HasPlaceholders,
+                        );
+                    }
                 }
+                err
             }
 
             ty::Predicate::WellFormed(ty) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
-                if !ty.references_error() && !self.tcx.sess.has_errors() {
-                    self.need_type_info_err(body_id, span, ty).emit();
+                if ty.references_error() || self.tcx.sess.has_errors() {
+                    return;
                 }
+                self.need_type_info_err(body_id, span, ty, ErrorCode::E0282)
             }
 
             ty::Predicate::Subtype(ref data) => {
                 if data.references_error() || self.tcx.sess.has_errors() {
                     // no need to overload user in such cases
-                } else {
-                    let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
-                    // both must be type variables, or the other would've been instantiated
-                    assert!(a.is_ty_var() && b.is_ty_var());
-                    self.need_type_info_err(body_id,
-                                            obligation.cause.span,
-                                            a).emit();
+                    return
                 }
+                let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
+                // both must be type variables, or the other would've been instantiated
+                assert!(a.is_ty_var() && b.is_ty_var());
+                self.need_type_info_err(body_id, span, a, ErrorCode::E0282)
+            }
+            ty::Predicate::Projection(ref data) => {
+                let trait_ref = data.to_poly_trait_ref(self.tcx);
+                let self_ty = trait_ref.self_ty();
+                if predicate.references_error() {
+                    return;
+                }
+                let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284);
+                err.note(&format!("cannot resolve `{}`", predicate));
+                err
             }
 
             _ => {
-                if !self.tcx.sess.has_errors() {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        obligation.cause.span,
-                        E0284,
-                        "type annotations needed: cannot resolve `{}`",
-                        predicate,
-                    );
-                    self.note_obligation_cause(&mut err, obligation);
-                    err.emit();
+                if self.tcx.sess.has_errors() {
+                    return;
                 }
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0284,
+                    "type annotations needed: cannot resolve `{}`",
+                    predicate,
+                );
+                err.span_label(span, &format!("cannot resolve `{}`", predicate));
+                err
             }
-        }
+        };
+        self.note_obligation_cause(&mut err, obligation);
+        err.emit();
     }
 
     /// Returns `true` if the trait predicate may apply for *some* assignment
@@ -2062,7 +2113,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     self.var_map.entry(ty).or_insert_with(||
                         infcx.next_ty_var(
                             TypeVariableOrigin {
-                                kind: TypeVariableOriginKind::TypeParameterDefinition(name),
+                                kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
                                 span: DUMMY_SP,
                             }
                         )
@@ -2353,7 +2404,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             let message = if let Some(name) = last_generator
                 .and_then(|generator_did| self.tcx.parent(generator_did))
                 .and_then(|parent_did| self.tcx.hir().as_local_hir_id(parent_did))
-                .map(|parent_hir_id| self.tcx.hir().name(parent_hir_id))
+                .and_then(|parent_hir_id| self.tcx.hir().opt_name(parent_hir_id))
             {
                 format!("future returned by `{}` is not {}", name, trait_name)
             } else {
diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs
index bc12412312d..fca53db1475 100644
--- a/src/librustc/ty/cast.rs
+++ b/src/librustc/ty/cast.rs
@@ -28,8 +28,6 @@ pub enum CastTy<'tcx> {
     FnPtr,
     /// Raw pointers
     Ptr(ty::TypeAndMut<'tcx>),
-    /// References
-    RPtr(ty::TypeAndMut<'tcx>),
 }
 
 /// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
@@ -63,7 +61,6 @@ impl<'tcx> CastTy<'tcx> {
             ty::Adt(d,_) if d.is_enum() && d.is_payloadfree() =>
                 Some(CastTy::Int(IntTy::CEnum)),
             ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
-            ty::Ref(_, ty, mutbl) => Some(CastTy::RPtr(ty::TypeAndMut { ty, mutbl })),
             ty::FnPtr(..) => Some(CastTy::FnPtr),
             _ => None,
         }
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index b3ef3217ec6..10c6a349ec8 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -76,9 +76,6 @@ pub fn encode_with_shorthand<E, T, M>(encoder: &mut E,
 
     // The shorthand encoding uses the same usize as the
     // discriminant, with an offset so they can't conflict.
-    #[cfg(bootstrap)]
-    let discriminant = unsafe { intrinsics::discriminant_value(variant) };
-    #[cfg(not(bootstrap))]
     let discriminant = intrinsics::discriminant_value(variant);
     assert!(discriminant < SHORTHAND_OFFSET as u64);
     let shorthand = start + SHORTHAND_OFFSET;
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index 268015a5624..897a3678c40 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -30,7 +30,12 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
     pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
         if self.is_const_fn_raw(def_id) {
-            self.lookup_stability(def_id)?.const_stability
+            let const_stab = self.lookup_const_stability(def_id)?;
+            if const_stab.level.is_unstable() {
+                Some(const_stab.feature)
+            } else {
+                None
+            }
         } else {
             None
         }
@@ -83,15 +88,36 @@ impl<'tcx> TyCtxt<'tcx> {
         }
 
         if self.features().staged_api {
-            // in order for a libstd function to be considered min_const_fn
-            // it needs to be stable and have no `rustc_const_unstable` attribute
-            match self.lookup_stability(def_id) {
-                // stable functions with unstable const fn aren't `min_const_fn`
-                Some(&attr::Stability { const_stability: Some(_), .. }) => false,
-                // unstable functions don't need to conform
-                Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
-                // everything else needs to conform, because it would be callable from
-                // other `min_const_fn` functions
+            // In order for a libstd function to be considered min_const_fn
+            // it needs to be stable and have no `rustc_const_unstable` attribute.
+            match self.lookup_const_stability(def_id) {
+                // `rustc_const_unstable` functions don't need to conform.
+                Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
+                None => if let Some(stab) = self.lookup_stability(def_id) {
+                    if stab.level.is_stable() {
+                        self.sess.span_err(
+                            self.def_span(def_id),
+                            "stable const functions must have either `rustc_const_stable` or \
+                            `rustc_const_unstable` attribute",
+                        );
+                        // While we errored above, because we don't know if we need to conform, we
+                        // err on the "safe" side and require min_const_fn.
+                        true
+                    } else {
+                        // Unstable functions need not conform to min_const_fn.
+                        false
+                    }
+                } else {
+                    // Internal functions are forced to conform to min_const_fn.
+                    // Annotate the internal function with a const stability attribute if
+                    // you need to use unstable features.
+                    // Note: this is an arbitrary choice that does not affect stability or const
+                    // safety or anything, it just changes whether we need to annotate some
+                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
+                    true
+                },
+                // Everything else needs to conform, because it would be callable from
+                // other `min_const_fn` functions.
                 _ => true,
             }
         } else {
@@ -188,7 +214,7 @@ pub fn provide(providers: &mut Providers<'_>) {
     }
 
     fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
+        tcx.is_const_fn(def_id) && match tcx.lookup_const_stability(def_id) {
             Some(stab) => {
                 if cfg!(debug_assertions) && stab.promotable {
                     let sig = tcx.fn_sig(def_id);
@@ -207,7 +233,7 @@ pub fn provide(providers: &mut Providers<'_>) {
 
     fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         tcx.is_const_fn(def_id) &&
-            tcx.lookup_stability(def_id)
+            tcx.lookup_const_stability(def_id)
                 .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
     }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f7e422b0403..595ea40b2ff 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1066,8 +1066,12 @@ pub struct GlobalCtxt<'tcx> {
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
+    /// `#[stable]` and `#[unstable]` attributes
     stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
 
+    /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
+    const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
+
     /// Stores the value of constants (and deduplicates the actual memory)
     allocation_interner: ShardedHashMap<&'tcx Allocation, ()>,
 
@@ -1129,6 +1133,12 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
+    pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
+        self.const_stability_interner.intern(stab, |stab| {
+            self.arena.alloc(stab)
+        })
+    }
+
     pub fn intern_layout(self, layout: LayoutDetails) -> &'tcx LayoutDetails {
         self.layout_interner.intern(layout, |layout| {
             self.arena.alloc(layout)
@@ -1269,6 +1279,7 @@ impl<'tcx> TyCtxt<'tcx> {
             data_layout,
             layout_interner: Default::default(),
             stability_interner: Default::default(),
+            const_stability_interner: Default::default(),
             allocation_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames.clone()),
@@ -2058,6 +2069,7 @@ impl<'tcx> TyCtxt<'tcx> {
         println!("InternalSubsts interner: #{}", self.interners.substs.len());
         println!("Region interner: #{}", self.interners.region.len());
         println!("Stability interner: #{}", self.stability_interner.len());
+        println!("Const Stability interner: #{}", self.const_stability_interner.len());
         println!("Allocation interner: #{}", self.allocation_interner.len());
         println!("Layout interner: #{}", self.layout_interner.len());
     }
@@ -2992,6 +3004,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
         tcx.stability().local_stability(id)
     };
+    providers.lookup_const_stability = |tcx, id| {
+        assert_eq!(id.krate, LOCAL_CRATE);
+        let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
+        tcx.stability().local_const_stability(id)
+    };
     providers.lookup_deprecation_entry = |tcx, id| {
         assert_eq!(id.krate, LOCAL_CRATE);
         let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 78a31f4e544..15bbfa7860f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -212,6 +212,17 @@ pub enum AssocKind {
     Type
 }
 
+impl AssocKind {
+    pub fn suggestion_descr(&self) -> &'static str {
+        match self {
+            ty::AssocKind::Method => "method call",
+            ty::AssocKind::Type |
+            ty::AssocKind::OpaqueTy => "associated type",
+            ty::AssocKind::Const => "associated constant",
+        }
+    }
+}
+
 impl AssocItem {
     pub fn def_kind(&self) -> DefKind {
         match self.kind {
diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml
index 867bbd22cfb..71cfacfa560 100644
--- a/src/librustc_codegen_llvm/Cargo.toml
+++ b/src/librustc_codegen_llvm/Cargo.toml
@@ -7,8 +7,28 @@ edition = "2018"
 [lib]
 name = "rustc_codegen_llvm"
 path = "lib.rs"
-crate-type = ["dylib"]
 test = false
+doctest = false
 
 [dependencies]
+bitflags = "1.0"
+flate2 = "1.0"
+libc = "0.2"
+log = "0.4"
+rustc = { path = "../librustc" }
+rustc-demangle = "0.1"
+rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
+rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_errors = { path = "../librustc_errors" }
+rustc_feature = { path = "../librustc_feature" }
+rustc_fs_util = { path = "../librustc_fs_util" }
+rustc_incremental = { path = "../librustc_incremental" }
+rustc_index = { path = "../librustc_index" }
 rustc_llvm = { path = "../librustc_llvm" }
+rustc_session = { path = "../librustc_session" }
+rustc_target = { path = "../librustc_target" }
+smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
+syntax = { path = "../libsyntax" }
+syntax_expand = { path = "../libsyntax_expand" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 1f3c8e1953e..2607a497326 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -8,6 +8,7 @@ use crate::value::Value;
 use rustc_codegen_ssa::MemFlags;
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::mir::operand::OperandValue;
+use rustc::bug;
 use rustc_codegen_ssa::traits::*;
 use rustc_target::abi::call::ArgAbi;
 use rustc_target::abi::{HasDataLayout, LayoutOf};
diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs
index 11b6e0befa1..e1d56b9be7a 100644
--- a/src/librustc_codegen_llvm/allocator.rs
+++ b/src/librustc_codegen_llvm/allocator.rs
@@ -4,6 +4,7 @@ use crate::attributes;
 use libc::c_uint;
 use rustc::ty::TyCtxt;
 use syntax::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc::bug;
 
 use crate::ModuleLlvm;
 use crate::llvm::{self, False, True};
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index abdd2e3e8db..fa43e082919 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -12,7 +12,7 @@ use syntax_pos::Span;
 
 use std::ffi::{CStr, CString};
 use libc::{c_uint, c_char};
-
+use log::debug;
 
 impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn codegen_inline_asm(
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 6779cce1f8a..3f2a51b45bd 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -12,6 +12,7 @@ use rustc::ty::query::Providers;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::abi::call::Conv;
+use rustc_data_structures::const_cstr;
 use rustc_target::spec::PanicStrategy;
 use rustc_codegen_ssa::traits::*;
 
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 858dd59b261..0e4e4e2f983 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -4,11 +4,12 @@ use crate::back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitc
 use crate::llvm::archive_ro::ArchiveRO;
 use crate::llvm::{self, True, False};
 use crate::{ModuleLlvm, LlvmCodegenBackend};
+use rustc::bug;
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput};
 use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule};
 use rustc_codegen_ssa::traits::*;
-use errors::{FatalError, Handler};
+use rustc_errors::{FatalError, Handler};
 use rustc::dep_graph::WorkProduct;
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc::hir::def_id::LOCAL_CRATE;
@@ -17,6 +18,7 @@ use rustc::session::config::{self, Lto};
 use rustc::util::common::time_ext;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, ModuleKind};
+use log::{info, debug};
 
 use std::ffi::{CStr, CString};
 use std::ptr;
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index ada29c350ad..796ea7aac36 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -10,6 +10,7 @@ use crate::type_::Type;
 use crate::context::{is_pie_binary, get_reloc_model};
 use crate::common;
 use crate::LlvmCodegenBackend;
+use rustc::bug;
 use rustc::hir::def_id::LOCAL_CRATE;
 use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler};
 use rustc_codegen_ssa::traits::*;
@@ -20,7 +21,8 @@ use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, CompiledModule};
 use rustc::util::common::time_ext;
 use rustc_fs_util::{path_to_c_string, link_or_copy};
 use rustc_data_structures::small_c_str::SmallCStr;
-use errors::{Handler, FatalError};
+use rustc_errors::{Handler, FatalError};
+use log::debug;
 
 use std::ffi::CString;
 use std::fs;
@@ -55,7 +57,7 @@ pub const TLS_MODEL_ARGS : [(&str, llvm::ThreadLocalMode); 4] = [
     ("local-exec", llvm::ThreadLocalMode::LocalExec),
 ];
 
-pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
+pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
     match llvm::last_error() {
         Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
         None => handler.fatal(&msg),
@@ -63,7 +65,7 @@ pub fn llvm_err(handler: &errors::Handler, msg: &str) -> FatalError {
 }
 
 pub fn write_output_file(
-        handler: &errors::Handler,
+        handler: &rustc_errors::Handler,
         target: &'ll llvm::TargetMachine,
         pm: &llvm::PassManager<'ll>,
         m: &'ll llvm::Module,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 6f72466c559..7509584df27 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -23,6 +23,8 @@ use std::ffi::CStr;
 use std::ops::{Deref, Range};
 use std::ptr;
 use std::iter::TrustedLen;
+use rustc_data_structures::const_cstr;
+use log::debug;
 
 // All Builders must have an llfn associated with them
 #[must_use]
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index e0db7cae99e..c0be87b117d 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -10,6 +10,7 @@ use crate::llvm;
 use crate::context::CodegenCx;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 use rustc::ty::{TypeFoldable, Instance};
 use rustc::ty::layout::{FnAbiExt, HasTyCtxt};
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index 419e99d55d7..ff03c1f76d8 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -8,6 +8,8 @@ use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
+use rustc::bug;
+use log::debug;
 
 use crate::consts::const_alloc_to_llvm;
 use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 297aff93a9d..11a105c1828 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -16,6 +16,8 @@ use rustc::ty::{self, Ty, Instance};
 use rustc_codegen_ssa::traits::*;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
+use rustc::{bug, span_bug};
+use log::debug;
 
 use rustc::ty::layout::{self, Size, Align, LayoutOf};
 
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 39ea1f6f5dc..2c894a5d740 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -12,6 +12,7 @@ use rustc_codegen_ssa::traits::*;
 
 use rustc_data_structures::base_n;
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc::bug;
 use rustc::mir::mono::CodegenUnit;
 use rustc::session::config::{self, DebugInfo};
 use rustc::session::Session;
@@ -23,6 +24,7 @@ use rustc::util::nodemap::FxHashMap;
 use rustc_target::spec::{HasTargetSpec, Target};
 use rustc_codegen_ssa::base::wants_msvc_seh;
 use crate::callee::get_fn;
+use rustc_data_structures::const_cstr;
 
 use std::ffi::CStr;
 use std::cell::{Cell, RefCell};
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
index 9ed1c1730a6..739437ac27b 100644
--- a/src/librustc_codegen_llvm/debuginfo/gdb.rs
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -7,6 +7,7 @@ use crate::builder::Builder;
 use crate::value::Value;
 use rustc::session::config::DebugInfo;
 use rustc_codegen_ssa::traits::*;
+use rustc::bug;
 
 use syntax::attr;
 use syntax::symbol::sym;
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 1847e4e9fa9..8327ff257c2 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -35,10 +35,13 @@ use rustc::session::config::{self, DebugInfo};
 use rustc::util::nodemap::FxHashMap;
 use rustc_fs_util::path_to_c_string;
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::const_cstr;
 use rustc_target::abi::HasDataLayout;
 use syntax::ast;
 use syntax::symbol::{Interner, Symbol};
 use syntax_pos::{self, Span, FileName};
+use rustc::{bug, span_bug};
+use log::debug;
 
 use libc::{c_uint, c_longlong};
 use std::collections::hash_map::Entry;
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index a3782ecd92d..1de298de75f 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -33,6 +33,7 @@ use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope,
 use libc::c_uint;
 use std::cell::RefCell;
 use std::ffi::CString;
+use log::debug;
 
 use smallvec::SmallVec;
 use syntax_pos::{self, BytePos, Span, Pos};
diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
index ccb3bde1cbe..82183fa9bd7 100644
--- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs
+++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs
@@ -8,6 +8,7 @@ use crate::llvm;
 use crate::llvm::debuginfo::DIScope;
 use crate::builder::Builder;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 use libc::c_uint;
 use syntax_pos::{Span, Pos};
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index fa9fc465368..5144b92ea10 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -22,6 +22,7 @@ use rustc::ty::Ty;
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 /// Declare a function.
 ///
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 1767ad118e7..900f2d2defc 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -19,6 +19,7 @@ use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc::hir;
 use rustc_target::abi::HasDataLayout;
 use syntax::ast;
+use rustc::{bug, span_bug};
 
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs
index 00a84f8d80f..1e1d74cfa9a 100644
--- a/src/librustc_codegen_llvm/lib.rs
+++ b/src/librustc_codegen_llvm/lib.rs
@@ -24,33 +24,11 @@
 use back::write::{create_target_machine, create_informational_target_machine};
 use syntax_pos::symbol::Symbol;
 
-extern crate rustc_demangle;
-extern crate flate2;
-#[macro_use] extern crate bitflags;
-extern crate libc;
-#[macro_use] extern crate rustc;
-extern crate rustc_target;
-#[macro_use] extern crate rustc_data_structures;
-extern crate rustc_feature;
-extern crate rustc_index;
-extern crate rustc_incremental;
-extern crate rustc_codegen_utils;
-extern crate rustc_codegen_ssa;
-extern crate rustc_fs_util;
-extern crate rustc_driver as _;
-
-#[macro_use] extern crate log;
-extern crate smallvec;
-extern crate syntax;
-extern crate syntax_pos;
-extern crate rustc_errors as errors;
-extern crate rustc_session;
-
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput};
 use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
 use rustc_codegen_ssa::CompiledModule;
-use errors::{FatalError, Handler};
+use rustc_errors::{FatalError, Handler};
 use rustc::dep_graph::WorkProduct;
 use syntax::expand::allocator::AllocatorKind;
 pub use llvm_util::target_features;
@@ -339,12 +317,6 @@ impl CodegenBackend for LlvmCodegenBackend {
     }
 }
 
-/// This is the entrypoint for a hot plugged rustc_codegen_llvm
-#[no_mangle]
-pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
-    LlvmCodegenBackend::new()
-}
-
 pub struct ModuleLlvm {
     llcx: &'static mut llvm::Context,
     llmod_raw: *const llvm::Module,
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 5da3275e28e..b8a1003b118 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -544,6 +544,7 @@ pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_voi
 
 pub mod debuginfo {
     use super::{InvariantOpaque, Metadata};
+    use bitflags::bitflags;
 
     #[repr(C)]
     pub struct DIBuilder<'a>(InvariantOpaque<'a>);
diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs
index d2d41876239..975756753d6 100644
--- a/src/librustc_codegen_llvm/llvm/mod.rs
+++ b/src/librustc_codegen_llvm/llvm/mod.rs
@@ -10,11 +10,11 @@ pub use self::Linkage::*;
 
 use std::str::FromStr;
 use std::string::FromUtf8Error;
-use std::slice;
 use std::ffi::CStr;
 use std::cell::RefCell;
-use libc::{c_uint, c_char, size_t};
+use libc::c_uint;
 use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_llvm::RustString;
 
 pub mod archive_ro;
 pub mod diagnostic;
@@ -81,21 +81,6 @@ impl FromStr for ArchiveKind {
     }
 }
 
-#[repr(C)]
-pub struct RustString {
-    bytes: RefCell<Vec<u8>>,
-}
-
-/// Appending to a Rust string -- used by RawRustStringOstream.
-#[no_mangle]
-pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
-                                                 ptr: *const c_char,
-                                                 size: size_t) {
-    let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
-
-    sr.bytes.borrow_mut().extend_from_slice(slice);
-}
-
 pub fn SetInstructionCallConv(instr: &'a Value, cc: CallConv) {
     unsafe {
         LLVMSetInstructionCallConv(instr, cc as c_uint);
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index 72612c4704e..40739387b00 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -8,6 +8,7 @@ use libc::c_int;
 use std::ffi::CString;
 use rustc_feature::UnstableFeatures;
 use syntax::symbol::sym;
+use rustc::bug;
 
 use std::str;
 use std::slice;
diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs
index cd725588811..bbe42e3b50a 100644
--- a/src/librustc_codegen_llvm/metadata.rs
+++ b/src/librustc_codegen_llvm/metadata.rs
@@ -6,6 +6,8 @@ use rustc_target::spec::Target;
 
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_codegen_ssa::METADATA_FILENAME;
+use log::debug;
+use rustc_data_structures::rustc_erase_owner;
 
 use std::path::Path;
 use std::slice;
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index cbc8af4fd27..9f6bdd23900 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -9,6 +9,7 @@ use rustc::mir::mono::{Linkage, Visibility};
 use rustc::ty::{TypeFoldable, Instance};
 use rustc::ty::layout::{FnAbiExt, LayoutOf};
 use rustc_codegen_ssa::traits::*;
+use log::debug;
 
 pub use rustc::mir::mono::MonoItem;
 
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index f936367572e..e6677f3d25b 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -5,6 +5,7 @@ use crate::llvm::{Bool, False, True};
 use crate::context::CodegenCx;
 use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
+use rustc::bug;
 
 use crate::common;
 use crate::type_of::LayoutLlvmExt;
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index d77bbb27921..f9cbf4bbe45 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -6,6 +6,8 @@ use rustc::ty::layout::{self, Align, LayoutOf, FnAbiExt, PointeeInfo, Size, TyLa
 use rustc_target::abi::TyLayoutMethods;
 use rustc::ty::print::obsolete::DefPathBasedNames;
 use rustc_codegen_ssa::traits::*;
+use log::debug;
+use rustc::bug;
 
 use std::fmt::Write;
 
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 6c627085b2e..7bcd9816786 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -340,10 +340,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
             PlaceContext::MutatingUse(MutatingUseContext::Store) |
             PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
             PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
+            PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
             PlaceContext::MutatingUse(MutatingUseContext::Projection) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
             PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
                 self.not_ssa(local);
             }
diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs
index 5e13cabced0..5b21dfbdf1c 100644
--- a/src/librustc_codegen_ssa/mir/place.rs
+++ b/src/librustc_codegen_ssa/mir/place.rs
@@ -448,7 +448,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let cx = self.cx;
         let tcx = self.cx.tcx();
 
-        let result = match &place_ref {
+        let result = match place_ref {
             mir::PlaceRef {
                 base: mir::PlaceBase::Local(index),
                 projection: [],
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 488ae8dbf90..09405cc02b3 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -7,7 +7,7 @@ use crate::MemFlags;
 use crate::common::{self, RealPredicate, IntPredicate};
 use crate::traits::*;
 
-use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
+use rustc::ty::{self, Ty, TyCtxt, adjustment::{PointerCast}, Instance};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
 use rustc::mir;
@@ -341,9 +341,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     llval
                                 }
                             }
+                            (CastTy::Int(_), CastTy::Float) => {
+                                if signed {
+                                    bx.sitofp(llval, ll_t_out)
+                                } else {
+                                    bx.uitofp(llval, ll_t_out)
+                                }
+                            }
                             (CastTy::Ptr(_), CastTy::Ptr(_)) |
-                            (CastTy::FnPtr, CastTy::Ptr(_)) |
-                            (CastTy::RPtr(_), CastTy::Ptr(_)) =>
+                            (CastTy::FnPtr, CastTy::Ptr(_)) =>
                                 bx.pointercast(llval, ll_t_out),
                             (CastTy::Ptr(_), CastTy::Int(_)) |
                             (CastTy::FnPtr, CastTy::Int(_)) =>
@@ -352,8 +358,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
                                 bx.inttoptr(usize_llval, ll_t_out)
                             }
-                            (CastTy::Int(_), CastTy::Float) =>
-                                cast_int_to_float(&mut bx, signed, llval, ll_t_in, ll_t_out),
                             (CastTy::Float, CastTy::Int(IntTy::I)) =>
                                 cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out),
                             (CastTy::Float, CastTy::Int(_)) =>
@@ -370,24 +374,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::Ref(_, bk, ref place) => {
-                let cg_place = self.codegen_place(&mut bx, &place.as_ref());
-
-                let ty = cg_place.layout.ty;
+                let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ref(
+                    tcx.lifetimes.re_erased,
+                    ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
+                );
+                self.codegen_place_to_pointer(bx, place, mk_ref)
+            }
 
-                // Note: places are indirect, so storing the `llval` into the
-                // destination effectively creates a reference.
-                let val = if !bx.cx().type_has_metadata(ty) {
-                    OperandValue::Immediate(cg_place.llval)
-                } else {
-                    OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
-                };
-                (bx, OperandRef {
-                    val,
-                    layout: self.cx.layout_of(self.cx.tcx().mk_ref(
-                        self.cx.tcx().lifetimes.re_erased,
-                        ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
-                    )),
-                })
+            mir::Rvalue::AddressOf(mutability, ref place) => {
+                let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ptr(
+                    ty::TypeAndMut { ty, mutbl: mutability.into() }
+                );
+                self.codegen_place_to_pointer(bx, place, mk_ptr)
             }
 
             mir::Rvalue::Len(ref place) => {
@@ -543,6 +541,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         cg_value.len(bx.cx())
     }
 
+    /// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref`
+    fn codegen_place_to_pointer(
+        &mut self,
+        mut bx: Bx,
+        place: &mir::Place<'tcx>,
+        mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
+    ) -> (Bx, OperandRef<'tcx, Bx::Value>) {
+        let cg_place = self.codegen_place(&mut bx, &place.as_ref());
+
+        let ty = cg_place.layout.ty;
+
+        // Note: places are indirect, so storing the `llval` into the
+        // destination effectively creates a reference.
+        let val = if !bx.cx().type_has_metadata(ty) {
+            OperandValue::Immediate(cg_place.llval)
+        } else {
+            OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
+        };
+        (bx, OperandRef {
+            val,
+            layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)),
+        })
+    }
+
     pub fn codegen_scalar_binop(
         &mut self,
         bx: &mut Bx,
@@ -699,6 +721,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
         match *rvalue {
             mir::Rvalue::Ref(..) |
+            mir::Rvalue::AddressOf(..) |
             mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
@@ -720,40 +743,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     }
 }
 
-fn cast_int_to_float<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    signed: bool,
-    x: Bx::Value,
-    int_ty: Bx::Type,
-    float_ty: Bx::Type
-) -> Bx::Value {
-    // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding.
-    // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity).
-    // LLVM's uitofp produces undef in those cases, so we manually check for that case.
-    let is_u128_to_f32 = !signed &&
-        bx.cx().int_width(int_ty) == 128 &&
-        bx.cx().float_width(float_ty) == 32;
-    if is_u128_to_f32 {
-        // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity,
-        // and for everything else LLVM's uitofp works just fine.
-        use rustc_apfloat::ieee::Single;
-        const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1)
-                                            << (Single::MAX_EXP - Single::PRECISION as i16);
-        let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP);
-        let overflow = bx.icmp(IntPredicate::IntUGE, x, max);
-        let infinity_bits = bx.cx().const_u32(ieee::Single::INFINITY.to_bits() as u32);
-        let infinity = bx.bitcast(infinity_bits, float_ty);
-        let fp = bx.uitofp(x, float_ty);
-        bx.select(overflow, infinity, fp)
-    } else {
-        if signed {
-            bx.sitofp(x, float_ty)
-        } else {
-            bx.uitofp(x, float_ty)
-        }
-    }
-}
-
 fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &mut Bx,
     signed: bool,
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index f2739a3b30c..fb2099e71a3 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -8,7 +8,7 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(core_intrinsics)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(nll)]
 #![feature(in_band_lifetimes)]
 
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 8a5badd0afc..b1931ca459f 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -128,21 +128,19 @@ type ObligationTreeIdGenerator =
     ::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
-    /// The list of obligations. In between calls to
-    /// `process_obligations`, this list only contains nodes in the
-    /// `Pending` or `Success` state (with a non-zero number of
-    /// incomplete children). During processing, some of those nodes
-    /// may be changed to the error state, or we may find that they
-    /// are completed (That is, `num_incomplete_children` drops to 0).
-    /// At the end of processing, those nodes will be removed by a
-    /// call to `compress`.
+    /// The list of obligations. In between calls to `process_obligations`,
+    /// this list only contains nodes in the `Pending` or `Success` state.
     ///
     /// `usize` indices are used here and throughout this module, rather than
-    /// `rustc_index::newtype_index!` indices, because this code is hot enough that the
-    /// `u32`-to-`usize` conversions that would be required are significant,
-    /// and space considerations are not important.
+    /// `rustc_index::newtype_index!` indices, because this code is hot enough
+    /// that the `u32`-to-`usize` conversions that would be required are
+    /// significant, and space considerations are not important.
     nodes: Vec<Node<O>>,
 
+    /// The process generation is 1 on the first call to `process_obligations`,
+    /// 2 on the second call, etc.
+    gen: u32,
+
     /// A cache of predicates that have been successfully completed.
     done_cache: FxHashSet<O::Predicate>,
 
@@ -211,31 +209,61 @@ impl<O> Node<O> {
 /// represents the current state of processing for the obligation (of
 /// type `O`) associated with this node.
 ///
-/// Outside of ObligationForest methods, nodes should be either Pending
-/// or Waiting.
+/// The non-`Error` state transitions are as follows.
+/// ```
+/// (Pre-creation)
+///  |
+///  |     register_obligation_at() (called by process_obligations() and
+///  v                               from outside the crate)
+/// Pending
+///  |
+///  |     process_obligations()
+///  v
+/// Success(not_waiting())
+///  |  |
+///  |  |  mark_still_waiting_nodes()
+///  |  v
+///  | Success(still_waiting())
+///  |  |
+///  |  |  compress()
+///  v  v
+/// (Removed)
+/// ```
+/// The `Error` state can be introduced in several places, via `error_at()`.
+///
+/// Outside of `ObligationForest` methods, nodes should be either `Pending` or
+/// `Success`.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 enum NodeState {
-    /// Obligations for which selection had not yet returned a
-    /// non-ambiguous result.
+    /// This obligation has not yet been selected successfully. Cannot have
+    /// subobligations.
     Pending,
 
-    /// This obligation was selected successfully, but may or
-    /// may not have subobligations.
-    Success,
-
-    /// This obligation was selected successfully, but it has
-    /// a pending subobligation.
-    Waiting,
+    /// This obligation was selected successfully, but it may be waiting on one
+    /// or more pending subobligations, as indicated by the `WaitingState`.
+    Success(WaitingState),
 
-    /// This obligation, along with its subobligations, are complete,
-    /// and will be removed in the next collection.
-    Done,
-
-    /// This obligation was resolved to an error. Error nodes are
-    /// removed from the vector by the compression step.
+    /// This obligation was resolved to an error. It will be removed by the
+    /// next compression step.
     Error,
 }
 
+/// Indicates when a `Success` node was last (if ever) waiting on one or more
+/// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`.
+/// - 0: "Not waiting". This is a special value, set by `process_obligation`,
+///   and usable because generation counting starts at 1.
+/// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but
+///   waiting no longer. In other words, finished.
+/// - ObligationForest::gen: "Still waiting" in this generation.
+///
+/// Things to note about this encoding:
+/// - Every time `ObligationForest::gen` is incremented, all the "still
+///   waiting" nodes automatically become "was waiting".
+/// - `ObligationForest::is_still_waiting` is very cheap.
+///
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
+struct WaitingState(u32);
+
 #[derive(Debug)]
 pub struct Outcome<O, E> {
     /// Obligations that were completely evaluated, including all
@@ -272,6 +300,7 @@ impl<O: ForestObligation> ObligationForest<O> {
     pub fn new() -> ObligationForest<O> {
         ObligationForest {
             nodes: vec![],
+            gen: 0,
             done_cache: Default::default(),
             active_cache: Default::default(),
             node_rewrites: RefCell::new(vec![]),
@@ -300,10 +329,7 @@ impl<O: ForestObligation> ObligationForest<O> {
 
         match self.active_cache.entry(obligation.as_predicate().clone()) {
             Entry::Occupied(o) => {
-                let index = *o.get();
-                debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
-                       obligation, parent, index);
-                let node = &mut self.nodes[index];
+                let node = &mut self.nodes[*o.get()];
                 if let Some(parent_index) = parent {
                     // If the node is already in `active_cache`, it has already
                     // had its chance to be marked with a parent. So if it's
@@ -320,9 +346,6 @@ impl<O: ForestObligation> ObligationForest<O> {
                 }
             }
             Entry::Vacant(v) => {
-                debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}",
-                       obligation, parent, self.nodes.len());
-
                 let obligation_tree_id = match parent {
                     Some(parent_index) => self.nodes[parent_index].obligation_tree_id,
                     None => self.obligation_tree_id_generator.next().unwrap(),
@@ -382,6 +405,18 @@ impl<O: ForestObligation> ObligationForest<O> {
             .insert(node.obligation.as_predicate().clone());
     }
 
+    fn not_waiting() -> WaitingState {
+        WaitingState(0)
+    }
+
+    fn still_waiting(&self) -> WaitingState {
+        WaitingState(self.gen)
+    }
+
+    fn is_still_waiting(&self, waiting: WaitingState) -> bool {
+        waiting.0 == self.gen
+    }
+
     /// Performs a pass through the obligation list. This must
     /// be called in a loop until `outcome.stalled` is false.
     ///
@@ -390,7 +425,7 @@ impl<O: ForestObligation> ObligationForest<O> {
                                   -> Outcome<O, P::Error>
         where P: ObligationProcessor<Obligation=O>
     {
-        debug!("process_obligations(len={})", self.nodes.len());
+        self.gen += 1;
 
         let mut errors = vec![];
         let mut stalled = true;
@@ -407,8 +442,6 @@ impl<O: ForestObligation> ObligationForest<O> {
         while index < self.nodes.len() {
             let node = &mut self.nodes[index];
 
-            debug!("process_obligations: node {} == {:?}", index, node);
-
             // `processor.process_obligation` can modify the predicate within
             // `node.obligation`, and that predicate is the key used for
             // `self.active_cache`. This means that `self.active_cache` can get
@@ -418,18 +451,15 @@ impl<O: ForestObligation> ObligationForest<O> {
                 index += 1;
                 continue;
             }
-            let result = processor.process_obligation(&mut node.obligation);
 
-            debug!("process_obligations: node {} got result {:?}", index, result);
-
-            match result {
+            match processor.process_obligation(&mut node.obligation) {
                 ProcessResult::Unchanged => {
                     // No change in state.
                 }
                 ProcessResult::Changed(children) => {
                     // We are not (yet) stalled.
                     stalled = false;
-                    node.state.set(NodeState::Success);
+                    node.state.set(NodeState::Success(Self::not_waiting()));
 
                     for child in children {
                         let st = self.register_obligation_at(
@@ -464,12 +494,10 @@ impl<O: ForestObligation> ObligationForest<O> {
             };
         }
 
-        self.mark_as_waiting();
+        self.mark_still_waiting_nodes();
         self.process_cycles(processor);
         let completed = self.compress(do_completed);
 
-        debug!("process_obligations: complete");
-
         Outcome {
             completed,
             errors,
@@ -477,56 +505,6 @@ impl<O: ForestObligation> ObligationForest<O> {
         }
     }
 
-    /// Mark all `NodeState::Success` nodes as `NodeState::Done` and
-    /// report all cycles between them. This should be called
-    /// after `mark_as_waiting` marks all nodes with pending
-    /// subobligations as NodeState::Waiting.
-    fn process_cycles<P>(&self, processor: &mut P)
-        where P: ObligationProcessor<Obligation=O>
-    {
-        let mut stack = vec![];
-
-        debug!("process_cycles()");
-
-        for (index, node) in self.nodes.iter().enumerate() {
-            // For some benchmarks this state test is extremely
-            // hot. It's a win to handle the no-op cases immediately to avoid
-            // the cost of the function call.
-            if node.state.get() == NodeState::Success {
-                self.find_cycles_from_node(&mut stack, processor, index);
-            }
-        }
-
-        debug!("process_cycles: complete");
-
-        debug_assert!(stack.is_empty());
-    }
-
-    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
-        where P: ObligationProcessor<Obligation=O>
-    {
-        let node = &self.nodes[index];
-        if node.state.get() == NodeState::Success {
-            match stack.iter().rposition(|&n| n == index) {
-                None => {
-                    stack.push(index);
-                    for &index in node.dependents.iter() {
-                        self.find_cycles_from_node(stack, processor, index);
-                    }
-                    stack.pop();
-                    node.state.set(NodeState::Done);
-                }
-                Some(rpos) => {
-                    // Cycle detected.
-                    processor.process_backedge(
-                        stack[rpos..].iter().map(GetObligation(&self.nodes)),
-                        PhantomData
-                    );
-                }
-            }
-        }
-    }
-
     /// Returns a vector of obligations for `p` and all of its
     /// ancestors, putting them into the error state in the process.
     fn error_at(&self, mut index: usize) -> Vec<O> {
@@ -560,21 +538,28 @@ impl<O: ForestObligation> ObligationForest<O> {
         trace
     }
 
+    /// Mark all `Success` nodes that depend on a pending node as still
+    /// waiting. Upon completion, any `Success` nodes that aren't still waiting
+    /// can be removed by `compress`.
+    fn mark_still_waiting_nodes(&self) {
+        for node in &self.nodes {
+            if node.state.get() == NodeState::Pending {
+                // This call site is hot.
+                self.inlined_mark_dependents_as_still_waiting(node);
+            }
+        }
+    }
+
     // This always-inlined function is for the hot call site.
     #[inline(always)]
-    fn inlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
+    fn inlined_mark_dependents_as_still_waiting(&self, node: &Node<O>) {
         for &index in node.dependents.iter() {
             let node = &self.nodes[index];
-            match node.state.get() {
-                NodeState::Waiting | NodeState::Error => {}
-                NodeState::Success => {
-                    node.state.set(NodeState::Waiting);
-                    // This call site is cold.
-                    self.uninlined_mark_neighbors_as_waiting_from(node);
-                }
-                NodeState::Pending | NodeState::Done => {
+            if let NodeState::Success(waiting) = node.state.get() {
+                if !self.is_still_waiting(waiting) {
+                    node.state.set(NodeState::Success(self.still_waiting()));
                     // This call site is cold.
-                    self.uninlined_mark_neighbors_as_waiting_from(node);
+                    self.uninlined_mark_dependents_as_still_waiting(node);
                 }
             }
         }
@@ -582,31 +567,65 @@ impl<O: ForestObligation> ObligationForest<O> {
 
     // This never-inlined function is for the cold call site.
     #[inline(never)]
-    fn uninlined_mark_neighbors_as_waiting_from(&self, node: &Node<O>) {
-        self.inlined_mark_neighbors_as_waiting_from(node)
+    fn uninlined_mark_dependents_as_still_waiting(&self, node: &Node<O>) {
+        self.inlined_mark_dependents_as_still_waiting(node)
     }
 
-    /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
-    fn mark_as_waiting(&self) {
-        for node in &self.nodes {
-            if node.state.get() == NodeState::Waiting {
-                node.state.set(NodeState::Success);
+    /// Report cycles between all `Success` nodes that aren't still waiting.
+    /// This must be called after `mark_still_waiting_nodes`.
+    fn process_cycles<P>(&self, processor: &mut P)
+        where P: ObligationProcessor<Obligation=O>
+    {
+        let mut stack = vec![];
+
+        for (index, node) in self.nodes.iter().enumerate() {
+            // For some benchmarks this state test is extremely hot. It's a win
+            // to handle the no-op cases immediately to avoid the cost of the
+            // function call.
+            if let NodeState::Success(waiting) = node.state.get() {
+                if !self.is_still_waiting(waiting) {
+                    self.find_cycles_from_node(&mut stack, processor, index, index);
+                }
             }
         }
 
-        for node in &self.nodes {
-            if node.state.get() == NodeState::Pending {
-                // This call site is hot.
-                self.inlined_mark_neighbors_as_waiting_from(node);
+        debug_assert!(stack.is_empty());
+    }
+
+    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, min_index: usize,
+                                index: usize)
+        where P: ObligationProcessor<Obligation=O>
+    {
+        let node = &self.nodes[index];
+        if let NodeState::Success(waiting) = node.state.get() {
+            if !self.is_still_waiting(waiting) {
+                match stack.iter().rposition(|&n| n == index) {
+                    None => {
+                        stack.push(index);
+                        for &dep_index in node.dependents.iter() {
+                            // The index check avoids re-considering a node.
+                            if dep_index >= min_index {
+                                self.find_cycles_from_node(stack, processor, min_index, dep_index);
+                            }
+                        }
+                        stack.pop();
+                    }
+                    Some(rpos) => {
+                        // Cycle detected.
+                        processor.process_backedge(
+                            stack[rpos..].iter().map(GetObligation(&self.nodes)),
+                            PhantomData
+                        );
+                    }
+                }
             }
         }
     }
 
     /// Compresses the vector, removing all popped nodes. This adjusts the
-    /// indices and hence invalidates any outstanding indices.
-    ///
-    /// Beforehand, all nodes must be marked as `Done` and no cycles
-    /// on these nodes may be present. This is done by e.g., `process_cycles`.
+    /// indices and hence invalidates any outstanding indices. `process_cycles`
+    /// must be run beforehand to remove any cycles on not-still-waiting
+    /// `Success` nodes.
     #[inline(never)]
     fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
         let orig_nodes_len = self.nodes.len();
@@ -614,10 +633,10 @@ impl<O: ForestObligation> ObligationForest<O> {
         debug_assert!(node_rewrites.is_empty());
         node_rewrites.extend(0..orig_nodes_len);
         let mut dead_nodes = 0;
-        let mut removed_done_obligations: Vec<O> = vec![];
+        let mut removed_success_obligations: Vec<O> = vec![];
 
-        // Now move all Done/Error nodes to the end, preserving the order of
-        // the Pending/Waiting nodes.
+        // Move removable nodes to the end, preserving the order of the
+        // remaining nodes.
         //
         // LOOP INVARIANT:
         //     self.nodes[0..index - dead_nodes] are the first remaining nodes
@@ -626,13 +645,19 @@ impl<O: ForestObligation> ObligationForest<O> {
         for index in 0..orig_nodes_len {
             let node = &self.nodes[index];
             match node.state.get() {
-                NodeState::Pending | NodeState::Waiting => {
+                NodeState::Pending => {
+                    if dead_nodes > 0 {
+                        self.nodes.swap(index, index - dead_nodes);
+                        node_rewrites[index] -= dead_nodes;
+                    }
+                }
+                NodeState::Success(waiting) if self.is_still_waiting(waiting) => {
                     if dead_nodes > 0 {
                         self.nodes.swap(index, index - dead_nodes);
                         node_rewrites[index] -= dead_nodes;
                     }
                 }
-                NodeState::Done => {
+                NodeState::Success(_) => {
                     // This lookup can fail because the contents of
                     // `self.active_cache` are not guaranteed to match those of
                     // `self.nodes`. See the comment in `process_obligation`
@@ -646,7 +671,7 @@ impl<O: ForestObligation> ObligationForest<O> {
                     }
                     if do_completed == DoCompleted::Yes {
                         // Extract the success stories.
-                        removed_done_obligations.push(node.obligation.clone());
+                        removed_success_obligations.push(node.obligation.clone());
                     }
                     node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
@@ -660,7 +685,6 @@ impl<O: ForestObligation> ObligationForest<O> {
                     node_rewrites[index] = orig_nodes_len;
                     dead_nodes += 1;
                 }
-                NodeState::Success => unreachable!()
             }
         }
 
@@ -674,7 +698,7 @@ impl<O: ForestObligation> ObligationForest<O> {
         self.node_rewrites.replace(node_rewrites);
 
         if do_completed == DoCompleted::Yes {
-            Some(removed_done_obligations)
+            Some(removed_success_obligations)
         } else {
             None
         }
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index d1cb4cbeb9b..043cfc58974 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -32,3 +32,6 @@ rustc_serialize = { path = "../libserialize", package = "serialize" }
 rustc_resolve = { path = "../librustc_resolve" }
 syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
+
+[features]
+llvm = ['rustc_interface/llvm']
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 05945504db2..3230e048a3b 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -42,7 +42,7 @@ use rustc_metadata::locator;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use errors::{PResult, registry::Registry};
 use rustc_interface::{interface, Queries};
-use rustc_interface::util::get_codegen_sysroot;
+use rustc_interface::util::get_builtin_codegen_backend;
 use rustc_data_structures::sync::SeqCst;
 use rustc_feature::{find_gated_cfg, UnstableFeatures};
 use rustc_serialize::json::ToJson;
@@ -765,7 +765,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
         println!("commit-date: {}", unw(commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(release_str()));
-        get_codegen_sysroot("llvm")().print_version();
+        get_builtin_codegen_backend("llvm")().print_version();
     }
 }
 
@@ -1059,7 +1059,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        get_codegen_sysroot("llvm")().print_passes();
+        get_builtin_codegen_backend("llvm")().print_passes();
         return None;
     }
 
diff --git a/src/librustc_error_codes/error_codes/E0725.md b/src/librustc_error_codes/error_codes/E0725.md
index b96a5e694df..9bd321e5f82 100644
--- a/src/librustc_error_codes/error_codes/E0725.md
+++ b/src/librustc_error_codes/error_codes/E0725.md
@@ -4,8 +4,8 @@ command line flags.
 Erroneous code example:
 
 ```ignore (can't specify compiler flags from doctests)
-#![feature(specialization)] // error: the feature `specialization` is not in
-                            // the list of allowed features
+#![feature(never_type)] // error: the feature `never_type` is not in
+                        // the list of allowed features
 ```
 
 Delete the offending feature attribute, or add it to the list of allowed
diff --git a/src/librustc_error_codes/error_codes/E0743.md b/src/librustc_error_codes/error_codes/E0743.md
index aaf19d8478c..1780fe59cbd 100644
--- a/src/librustc_error_codes/error_codes/E0743.md
+++ b/src/librustc_error_codes/error_codes/E0743.md
@@ -1,11 +1,17 @@
-C-variadic has been used on a non-foreign function.
+The C-variadic type `...` has been nested inside another type.
 
 Erroneous code example:
 
 ```compile_fail,E0743
-fn foo2(x: u8, ...) {} // error!
+#![feature(c_variadic)]
+
+fn foo2(x: u8, y: &...) {} // error!
 ```
 
-Only foreign functions can use C-variadic (`...`). It is used to give an
-undefined number of parameters to a given function (like `printf` in C). The
-equivalent in Rust would be to use macros directly.
+Only foreign functions can use the C-variadic type (`...`).
+In such functions, `...` may only occur non-nested.
+That is, `y: &'a ...` is not allowed.
+
+A C-variadic type is used to give an undefined number
+of parameters to a given function (like `printf` in C).
+The equivalent in Rust would be to use macros directly.
diff --git a/src/librustc_error_codes/error_codes/E0744.md b/src/librustc_error_codes/error_codes/E0744.md
index b299102fd69..602fbc50a71 100644
--- a/src/librustc_error_codes/error_codes/E0744.md
+++ b/src/librustc_error_codes/error_codes/E0744.md
@@ -3,7 +3,7 @@ Control-flow expressions are not allowed inside a const context.
 At the moment, `if` and `match`, as well as the looping constructs `for`,
 `while`, and `loop`, are forbidden inside a `const`, `static`, or `const fn`.
 
-```compile_fail,E0744
+```compile_fail,E0658
 const _: i32 = {
     let mut x = 0;
     loop {
diff --git a/src/librustc_error_codes/error_codes/E0745.md b/src/librustc_error_codes/error_codes/E0745.md
index 39bebdcd375..6595691ce78 100644
--- a/src/librustc_error_codes/error_codes/E0745.md
+++ b/src/librustc_error_codes/error_codes/E0745.md
@@ -11,7 +11,7 @@ fn temp_address() {
 
 To avoid the error, first bind the temporary to a named local variable.
 
-```ignore (not yet implemented)
+```
 # #![feature(raw_ref_op)]
 fn temp_address() {
     let val = 2;
diff --git a/src/librustc_feature/accepted.rs b/src/librustc_feature/accepted.rs
index fec5a7f1a45..3f294dc02ed 100644
--- a/src/librustc_feature/accepted.rs
+++ b/src/librustc_feature/accepted.rs
@@ -253,8 +253,6 @@ declare_features! (
     (accepted, const_constructor, "1.40.0", Some(61456), None),
     /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
     (accepted, cfg_doctest, "1.40.0", Some(62210), None),
-    /// Allows the `!` type. Does not imply 'exhaustive_patterns' any more.
-    (accepted, never_type, "1.41.0", Some(35121), None),
     /// Allows relaxing the coherence rules such that
     /// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted.
     (accepted, re_rebalance_coherence, "1.41.0", Some(55437), None),
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 363621b3ca4..a386cbf56af 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -52,6 +52,17 @@ macro_rules! declare_features {
             pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) {
                 $(f(stringify!($feature), self.$feature);)+
             }
+
+            /// Is the given feature enabled?
+            ///
+            /// Panics if the symbol doesn't correspond to a declared feature.
+            pub fn enabled(&self, feature: Symbol) -> bool {
+                match feature {
+                    $( sym::$feature => self.$feature, )*
+
+                    _ => panic!("`{}` was not listed in `declare_features`", feature),
+                }
+            }
         }
     };
 }
@@ -111,10 +122,6 @@ declare_features! (
     /// macros disappear).
     (active, allow_internal_unsafe, "1.0.0", None, None),
 
-    /// Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which
-    /// lets a function to be `const` when opted into with `#![feature(foo)]`.
-    (active, rustc_const_unstable, "1.0.0", None, None),
-
     /// no-tracking-issue-end
 
     /// Allows using `#[link_name="llvm.*"]`.
@@ -307,6 +314,9 @@ declare_features! (
     /// Allows `X..Y` patterns.
     (active, exclusive_range_pattern, "1.11.0", Some(37854), None),
 
+    /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
+    (active, never_type, "1.13.0", Some(35121), None),
+
     /// Allows exhaustive pattern matching on types that contain uninhabited types.
     (active, exhaustive_patterns, "1.13.0", Some(51085), None),
 
@@ -526,6 +536,9 @@ declare_features! (
     /// Allows using `&mut` in constant functions.
     (active, const_mut_refs, "1.41.0", Some(57349), None),
 
+    /// Allows the use of `loop` and `while` in constants.
+    (active, const_loop, "1.41.0", Some(52000), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs
index 4fa0198d871..0a4fb8a224e 100644
--- a/src/librustc_feature/builtin_attrs.rs
+++ b/src/librustc_feature/builtin_attrs.rs
@@ -344,10 +344,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         unstable, Whitelisted,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#),
     ),
-    gated!(
-        rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
-        "the `#[rustc_const_unstable]` attribute is an internal feature",
-    ),
+    // FIXME(#14407)
+    ungated!(rustc_const_unstable, Whitelisted, template!(List: r#"feature = "name""#)),
+    // FIXME(#14407)
+    ungated!(rustc_const_stable, Whitelisted, template!(List: r#"feature = "name""#)),
     gated!(
         allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
         "allow_internal_unstable side-steps feature gating and stability checks",
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 07d426af6ee..e3e3b0b1748 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -44,11 +44,10 @@ use rustc_data_structures::graph::implementation::{
 };
 use rustc::hir;
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc::ich::{ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED};
 use std::env;
 use std::fs::{self, File};
 use std::io::Write;
-use syntax::ast;
+use syntax::{ast, symbol::sym};
 use syntax_pos::Span;
 
 pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
@@ -78,7 +77,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
             assert!(tcx.sess.opts.debugging_opts.query_dep_graph,
                     "cannot use the `#[{}]` or `#[{}]` annotations \
                     without supplying `-Z query-dep-graph`",
-                    ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED);
+                    sym::rustc_if_this_changed, sym::rustc_then_this_would_need);
         }
 
         // Check paths.
@@ -114,7 +113,7 @@ impl IfThisChanged<'tcx> {
         let def_id = self.tcx.hir().local_def_id(hir_id);
         let def_path_hash = self.tcx.def_path_hash(def_id);
         for attr in attrs {
-            if attr.check_name(ATTR_IF_THIS_CHANGED) {
+            if attr.check_name(sym::rustc_if_this_changed) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
                     None => def_path_hash.to_dep_node(DepKind::Hir),
@@ -130,7 +129,7 @@ impl IfThisChanged<'tcx> {
                     }
                 };
                 self.if_this_changed.push((attr.span, def_id, dep_node));
-            } else if attr.check_name(ATTR_THEN_THIS_WOULD_NEED) {
+            } else if attr.check_name(sym::rustc_then_this_would_need) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
                     Some(n) => {
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
index c2e3fa8f28d..1a675ea002c 100644
--- a/src/librustc_incremental/assert_module_sources.rs
+++ b/src/librustc_incremental/assert_module_sources.rs
@@ -28,8 +28,6 @@ use rustc::ty::TyCtxt;
 use std::collections::BTreeSet;
 use syntax::ast;
 use syntax::symbol::{Symbol, sym};
-use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED,
-                 ATTR_EXPECTED_CGU_REUSE};
 
 pub fn assert_module_sources(tcx: TyCtxt<'_>) {
     tcx.dep_graph.with_ignore(|| {
@@ -62,11 +60,11 @@ struct AssertModuleSource<'tcx> {
 
 impl AssertModuleSource<'tcx> {
     fn check_attr(&self, attr: &ast::Attribute) {
-        let (expected_reuse, comp_kind) = if attr.check_name(ATTR_PARTITION_REUSED) {
+        let (expected_reuse, comp_kind) = if attr.check_name(sym::rustc_partition_reused) {
             (CguReuse::PreLto, ComparisonKind::AtLeast)
-        } else if attr.check_name(ATTR_PARTITION_CODEGENED) {
+        } else if attr.check_name(sym::rustc_partition_codegened) {
             (CguReuse::No, ComparisonKind::Exact)
-        } else if attr.check_name(ATTR_EXPECTED_CGU_REUSE) {
+        } else if attr.check_name(sym::rustc_expected_cgu_reuse) {
             match &*self.field(attr, sym::kind).as_str() {
                 "no" => (CguReuse::No, ComparisonKind::Exact),
                 "pre-lto" => (CguReuse::PreLto, ComparisonKind::Exact),
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index ea156a94ea1..c919db070a6 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -22,7 +22,6 @@ use rustc::hir::Node as HirNode;
 use rustc::hir::def_id::DefId;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit;
-use rustc::ich::{ATTR_DIRTY, ATTR_CLEAN};
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashSet;
@@ -224,7 +223,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
 
         let mut all_attrs = FindAllAttrs {
             tcx,
-            attr_names: vec![ATTR_DIRTY, ATTR_CLEAN],
+            attr_names: vec![sym::rustc_dirty, sym::rustc_clean],
             found_attrs: vec![],
         };
         intravisit::walk_crate(&mut all_attrs, krate);
@@ -246,9 +245,9 @@ impl DirtyCleanVisitor<'tcx> {
     fn assertion_maybe(&mut self, item_id: hir::HirId, attr: &Attribute)
         -> Option<Assertion>
     {
-        let is_clean = if attr.check_name(ATTR_DIRTY) {
+        let is_clean = if attr.check_name(sym::rustc_dirty) {
             false
-        } else if attr.check_name(ATTR_CLEAN) {
+        } else if attr.check_name(sym::rustc_clean) {
             true
         } else {
             // skip: not rustc_clean/dirty
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index 7ab5ec2b232..58fd92822e9 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -25,6 +25,7 @@ rustc_traits = { path = "../librustc_traits" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
 rustc_codegen_utils = { path = "../librustc_codegen_utils" }
+rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true }
 rustc_metadata = { path = "../librustc_metadata" }
 rustc_mir = { path = "../librustc_mir" }
 rustc_passes = { path = "../librustc_passes" }
@@ -39,3 +40,6 @@ once_cell = "1"
 
 [dev-dependencies]
 rustc_target = { path = "../librustc_target" }
+
+[features]
+llvm = ['rustc_codegen_llvm']
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index beb2465bd4a..2365fc3ee2e 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -25,7 +25,7 @@ use syntax_pos::edition;
 pub type Result<T> = result::Result<T, ErrorReported>;
 
 /// Represents a compiler session.
-/// Can be used run `rustc_interface` queries.
+/// Can be used to run `rustc_interface` queries.
 /// Created by passing `Config` to `run_compiler`.
 pub struct Compiler {
     pub(crate) sess: Lrc<Session>,
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 8c225b83f40..4d686fc310f 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -16,11 +16,9 @@ use rustc_errors::registry::Registry;
 use rustc_metadata::dynamic_lib::DynamicLibrary;
 use rustc_resolve::{self, Resolver};
 use std::env;
-use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::io::{self, Write};
 use std::mem;
 use std::path::{Path, PathBuf};
-use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex, Once};
 use std::ops::DerefMut;
 use smallvec::SmallVec;
@@ -249,7 +247,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
             filename if filename.contains(".") => {
                 load_backend_from_dylib(filename.as_ref())
             }
-            codegen_name => get_codegen_sysroot(codegen_name),
+            codegen_name => get_builtin_codegen_backend(codegen_name),
         };
 
         unsafe {
@@ -384,83 +382,16 @@ fn sysroot_candidates() -> Vec<PathBuf> {
     }
 }
 
-pub fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
-    // For now we only allow this function to be called once as it'll dlopen a
-    // few things, which seems to work best if we only do that once. In
-    // general this assertion never trips due to the once guard in `get_codegen_backend`,
-    // but there's a few manual calls to this function in this file we protect
-    // against.
-    static LOADED: AtomicBool = AtomicBool::new(false);
-    assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
-            "cannot load the default codegen backend twice");
-
-    let target = session::config::host_triple();
-    let sysroot_candidates = sysroot_candidates();
-
-    let sysroot = sysroot_candidates.iter()
-        .map(|sysroot| {
-            let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
-            sysroot.join(libdir).with_file_name(
-                option_env!("CFG_CODEGEN_BACKENDS_DIR").unwrap_or("codegen-backends"))
-        })
-        .filter(|f| {
-            info!("codegen backend candidate: {}", f.display());
-            f.exists()
-        })
-        .next();
-    let sysroot = sysroot.unwrap_or_else(|| {
-        let candidates = sysroot_candidates.iter()
-            .map(|p| p.display().to_string())
-            .collect::<Vec<_>>()
-            .join("\n* ");
-        let err = format!("failed to find a `codegen-backends` folder \
-                           in the sysroot candidates:\n* {}", candidates);
-        early_error(ErrorOutputType::default(), &err);
-    });
-    info!("probing {} for a codegen backend", sysroot.display());
-
-    let d = sysroot.read_dir().unwrap_or_else(|e| {
-        let err = format!("failed to load default codegen backend, couldn't \
-                           read `{}`: {}", sysroot.display(), e);
-        early_error(ErrorOutputType::default(), &err);
-    });
-
-    let mut file: Option<PathBuf> = None;
-
-    let expected_name = format!("rustc_codegen_llvm-{}", backend_name);
-    for entry in d.filter_map(|e| e.ok()) {
-        let path = entry.path();
-        let filename = match path.file_name().and_then(|s| s.to_str()) {
-            Some(s) => s,
-            None => continue,
-        };
-        if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
-            continue
-        }
-        let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
-        if name != expected_name {
-            continue
-        }
-        if let Some(ref prev) = file {
-            let err = format!("duplicate codegen backends found\n\
-                               first:  {}\n\
-                               second: {}\n\
-            ", prev.display(), path.display());
-            early_error(ErrorOutputType::default(), &err);
-        }
-        file = Some(path.clone());
-    }
-
-    match file {
-        Some(ref s) => return load_backend_from_dylib(s),
-        None => {
-            let err = format!("failed to load default codegen backend for `{}`, \
-                               no appropriate codegen dylib found in `{}`",
-                              backend_name, sysroot.display());
-            early_error(ErrorOutputType::default(), &err);
+pub fn get_builtin_codegen_backend(backend_name: &str) -> fn() -> Box<dyn CodegenBackend> {
+    #[cfg(feature = "llvm")]
+    {
+        if backend_name == "llvm" {
+            return rustc_codegen_llvm::LlvmCodegenBackend::new;
         }
     }
 
+    let err = format!("unsupported builtin codegen backend `{}`", backend_name);
+    early_error(ErrorOutputType::default(), &err);
 }
 
 pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
@@ -712,8 +643,8 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
         ret
     }
 
-    fn should_ignore_fn(ret_ty: &ast::FnDecl) -> bool {
-        if let ast::FunctionRetTy::Ty(ref ty) = ret_ty.output {
+    fn should_ignore_fn(ret_ty: &ast::FunctionRetTy) -> bool {
+        if let ast::FunctionRetTy::Ty(ref ty) = ret_ty {
             fn involves_impl_trait(ty: &ast::Ty) -> bool {
                 match ty.kind {
                     ast::TyKind::ImplTrait(..) => true,
@@ -742,7 +673,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
                             },
                             Some(&ast::GenericArgs::Parenthesized(ref data)) => {
                                 any_involves_impl_trait(data.inputs.iter()) ||
-                                any_involves_impl_trait(data.output.iter())
+                                ReplaceBodyWithLoop::should_ignore_fn(&data.output)
                             }
                         }
                     }),
@@ -762,7 +693,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
 
     fn is_sig_const(sig: &ast::FnSig) -> bool {
         sig.header.constness.node == ast::Constness::Const ||
-            ReplaceBodyWithLoop::should_ignore_fn(&sig.decl)
+            ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output)
     }
 }
 
@@ -776,22 +707,17 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
         self.run(is_const, |s| noop_visit_item_kind(i, s))
     }
 
-    fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, i: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         let is_const = match i.kind {
-            ast::TraitItemKind::Const(..) => true,
-            ast::TraitItemKind::Method(ref sig, _) => Self::is_sig_const(sig),
+            ast::AssocItemKind::Const(..) => true,
+            ast::AssocItemKind::Fn(ref sig, _) => Self::is_sig_const(sig),
             _ => false,
         };
-        self.run(is_const, |s| noop_flat_map_trait_item(i, s))
+        self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
     }
 
-    fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
-        let is_const = match i.kind {
-            ast::ImplItemKind::Const(..) => true,
-            ast::ImplItemKind::Method(ref sig, _) => Self::is_sig_const(sig),
-            _ => false,
-        };
-        self.run(is_const, |s| noop_flat_map_impl_item(i, s))
+    fn flat_map_impl_item(&mut self, i: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
+        self.flat_map_trait_item(i)
     }
 
     fn visit_anon_const(&mut self, c: &mut ast::AnonConst) {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 10b00d35d9b..1fc89961889 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -268,8 +268,8 @@ impl EarlyLintPass for UnsafeCode {
         }
     }
 
-    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::TraitItem) {
-        if let ast::TraitItemKind::Method(ref sig, None) = item.kind {
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
+        if let ast::AssocItemKind::Fn(ref sig, None) = item.kind {
             if sig.header.unsafety == ast::Unsafety::Unsafe {
                 self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
             }
@@ -615,9 +615,9 @@ declare_lint_pass!(
 );
 
 impl EarlyLintPass for AnonymousParameters {
-    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::TraitItem) {
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
         match it.kind {
-            ast::TraitItemKind::Method(ref sig, _) => {
+            ast::AssocItemKind::Fn(ref sig, _) => {
                 for arg in sig.decl.inputs.iter() {
                     match arg.pat.kind {
                         ast::PatKind::Ident(_, ident, None) => {
diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml
index 0fe327d5dee..4fc02e348f6 100644
--- a/src/librustc_llvm/Cargo.toml
+++ b/src/librustc_llvm/Cargo.toml
@@ -13,6 +13,9 @@ path = "lib.rs"
 static-libstdcpp = []
 emscripten = []
 
+[dependencies]
+libc = "0.2"
+
 [build-dependencies]
 build_helper = { path = "../build_helper" }
 cc = "1.0.1"
diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs
index 647d473f015..9c8943a9559 100644
--- a/src/librustc_llvm/lib.rs
+++ b/src/librustc_llvm/lib.rs
@@ -5,6 +5,26 @@
 
 // NOTE: This crate only exists to allow linking on mingw targets.
 
+use std::cell::RefCell;
+use std::slice;
+use libc::{c_char, size_t};
+
+
+#[repr(C)]
+pub struct RustString {
+    pub bytes: RefCell<Vec<u8>>,
+}
+
+/// Appending to a Rust string -- used by RawRustStringOstream.
+#[no_mangle]
+pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
+                                                 ptr: *const c_char,
+                                                 size: size_t) {
+    let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
+
+    sr.bytes.borrow_mut().extend_from_slice(slice);
+}
+
 /// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
 /// N.B., this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s.
 pub fn initialize_available_targets() {
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 0107a22772f..a1f95e35cbe 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -852,6 +852,10 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
+    fn get_const_stability(&self, id: DefIndex) -> Option<attr::ConstStability> {
+        self.root.per_def.const_stability.get(self, id).map(|stab| stab.decode(self))
+    }
+
     fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
         self.root.per_def.deprecation.get(self, id)
             .filter(|_| !self.is_proc_macro(id))
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index 13db9a6fef9..4a6b25930c8 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -134,6 +134,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     lookup_stability => {
         cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
     }
+    lookup_const_stability => {
+        cdata.get_const_stability(def_id.index).map(|s| tcx.intern_const_stability(s))
+    }
     lookup_deprecation_entry => {
         cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
     }
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index fb70e10c84f..c1562a77342 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -866,6 +866,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- ast_item.span);
         record!(self.per_def.attributes[def_id] <- &ast_item.attrs);
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         match trait_item.kind {
             ty::AssocKind::Const |
@@ -946,6 +947,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- ast_item.span);
         record!(self.per_def.attributes[def_id] <- &ast_item.attrs);
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if impl_item.kind == ty::AssocKind::Method {
@@ -1025,6 +1027,13 @@ impl EncodeContext<'tcx> {
         }
     }
 
+    fn encode_const_stability(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_const_stability({:?})", def_id);
+        if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
+            record!(self.per_def.const_stability[def_id] <- stab)
+        }
+    }
+
     fn encode_deprecation(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_deprecation({:?})", def_id);
         if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
@@ -1186,6 +1195,7 @@ impl EncodeContext<'tcx> {
             _ => {}
         }
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         match item.kind {
             hir::ItemKind::Static(..) |
@@ -1545,6 +1555,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- nitem.span);
         record!(self.per_def.attributes[def_id] <- &nitem.attrs);
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 5abae429373..e13edc2d621 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -261,6 +261,7 @@ define_per_def_tables! {
     attributes: Table<DefIndex, Lazy<[ast::Attribute]>>,
     children: Table<DefIndex, Lazy<[DefIndex]>>,
     stability: Table<DefIndex, Lazy<attr::Stability>>,
+    const_stability: Table<DefIndex, Lazy<attr::ConstStability>>,
     deprecation: Table<DefIndex, Lazy<attr::Deprecation>>,
     ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
     fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index 938836db9ae..cc634101f0a 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -223,18 +223,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     fn report(&mut self, error: GroupedMoveError<'tcx>) {
         let (mut err, err_span) = {
-            let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
+            let (span, use_spans, original_path, kind,):
+            (
+                Span,
+                Option<UseSpans>,
+                &Place<'tcx>,
+                &IllegalMoveOriginKind<'_>,
+            ) =
                 match error {
                     GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
                     GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } => {
-                        (span, original_path, kind)
+                        (span, None, original_path, kind)
                     }
                     GroupedMoveError::OtherIllegalMove {
                         use_spans,
                         ref original_path,
                         ref kind
                     } => {
-                        (use_spans.args_or_use(), original_path, kind)
+                        (use_spans.args_or_use(), Some(use_spans), original_path, kind)
                     },
                 };
             debug!("report: original_path={:?} span={:?}, kind={:?} \
@@ -250,6 +256,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             original_path,
                             target_place,
                             span,
+                            use_spans,
                         )
                     }
                     IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
@@ -296,6 +303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         move_place: &Place<'tcx>,
         deref_target_place: &Place<'tcx>,
         span: Span,
+        use_spans: Option<UseSpans>,
     ) -> DiagnosticBuilder<'a> {
         // Inspect the type of the content behind the
         // borrow to provide feedback about why this
@@ -416,7 +424,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
             let is_option = move_ty.starts_with("std::option::Option");
             let is_result = move_ty.starts_with("std::result::Result");
-            if is_option || is_result {
+            if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
                 err.span_suggestion(
                     span,
                     &format!("consider borrowing the `{}`'s content", if is_option {
diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs
index 58fac5512d9..d5b9aaf9511 100644
--- a/src/librustc_mir/borrow_check/invalidation.rs
+++ b/src/librustc_mir/borrow_check/invalidation.rs
@@ -3,7 +3,7 @@ use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
 use rustc::mir::{Statement, StatementKind};
 use rustc::mir::TerminatorKind;
-use rustc::mir::{Operand, BorrowKind};
+use rustc::mir::{Operand, BorrowKind, Mutability};
 use rustc_data_structures::graph::dominators::Dominators;
 
 use crate::dataflow::indexes::BorrowIndex;
@@ -337,6 +337,22 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
                 );
             }
 
+            Rvalue::AddressOf(mutability, ref place) => {
+                let access_kind = match mutability {
+                    Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
+                        allow_two_phase_borrow: false,
+                    }))),
+                    Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
+                };
+
+                self.access_place(
+                    location,
+                    place,
+                    access_kind,
+                    LocalMutationIsAllowed::No,
+                );
+            }
+
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 11012ef2fc7..2554d5e729d 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1233,6 +1233,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 );
             }
 
+
+            Rvalue::AddressOf(mutability, ref place) => {
+                let access_kind = match mutability {
+                    Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
+                        allow_two_phase_borrow: false,
+                    }))),
+                    Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
+                };
+
+                self.access_place(
+                    location,
+                    (place, span),
+                    access_kind,
+                    LocalMutationIsAllowed::No,
+                    flow_state,
+                );
+
+                self.check_if_path_or_subpath_is_moved(
+                    location,
+                    InitializationRequiringAction::Borrow,
+                    (place.as_ref(), span),
+                    flow_state,
+                );
+            }
+
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 663536bc2b4..108279eeef4 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -2273,41 +2273,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let cast_ty_from = CastTy::from_ty(ty_from);
                         let cast_ty_to = CastTy::from_ty(ty);
                         match (cast_ty_from, cast_ty_to) {
-                            (Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
-                                if let hir::Mutability::Mutable = ptr_tm.mutbl {
-                                    if let Err(terr) = self.eq_types(
-                                        ref_tm.ty,
-                                        ptr_tm.ty,
-                                        location.to_locations(),
-                                        ConstraintCategory::Cast,
-                                    ) {
-                                        span_mirbug!(
-                                            self,
-                                            rvalue,
-                                            "equating {:?} with {:?} yields {:?}",
-                                            ref_tm.ty,
-                                            ptr_tm.ty,
-                                            terr
-                                        )
-                                    }
-                                } else {
-                                    if let Err(terr) = self.sub_types(
-                                        ref_tm.ty,
-                                        ptr_tm.ty,
-                                        location.to_locations(),
-                                        ConstraintCategory::Cast,
-                                    ) {
-                                        span_mirbug!(
-                                            self,
-                                            rvalue,
-                                            "relating {:?} with {:?} yields {:?}",
-                                            ref_tm.ty,
-                                            ptr_tm.ty,
-                                            terr
-                                        )
-                                    }
-                                }
-                            },
                             (None, _)
                             | (_, None)
                             | (_, Some(CastTy::FnPtr))
@@ -2320,7 +2285,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                 ty_from,
                                 ty,
                             ),
-                            _ => (),
+                            (Some(CastTy::Int(_)), Some(CastTy::Int(_)))
+                            | (Some(CastTy::Float), Some(CastTy::Int(_)))
+                            | (Some(CastTy::Int(_)), Some(CastTy::Float))
+                            | (Some(CastTy::Float), Some(CastTy::Float))
+                            | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_)))
+                            | (Some(CastTy::FnPtr), Some(CastTy::Int(_)))
+                            | (Some(CastTy::Int(_)), Some(CastTy::Ptr(_)))
+                            | (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_)))
+                            | (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
                         }
                     }
                 }
@@ -2371,7 +2344,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
 
-            Rvalue::Use(..)
+            Rvalue::AddressOf(..)
+            | Rvalue::Use(..)
             | Rvalue::Len(..)
             | Rvalue::BinaryOp(..)
             | Rvalue::CheckedBinaryOp(..)
@@ -2388,6 +2362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             Rvalue::Use(_)
             | Rvalue::Repeat(..)
             | Rvalue::Ref(..)
+            | Rvalue::AddressOf(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
             | Rvalue::BinaryOp(..)
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 3ed6b4ff346..6bd8d2f7c07 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -59,6 +59,18 @@ impl<'tcx> CFG<'tcx> {
         ));
     }
 
+    pub fn push_fake_read(
+        &mut self,
+        block: BasicBlock,
+        source_info: SourceInfo,
+        cause: FakeReadCause,
+        place: Place<'tcx>,
+    ) {
+        let kind = StatementKind::FakeRead(cause, box place);
+        let stmt = Statement { source_info, kind };
+        self.push(block, stmt);
+    }
+
     pub fn terminate(&mut self,
                      block: BasicBlock,
                      source_info: SourceInfo,
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index f66f1cb7366..15c7c92d7db 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -276,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Pointer { .. }
             | ExprKind::Repeat { .. }
             | ExprKind::Borrow { .. }
+            | ExprKind::AddressOf { .. }
             | ExprKind::Match { .. }
             | ExprKind::Loop { .. }
             | ExprKind::Block { .. }
@@ -484,7 +485,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     fn read_fake_borrows(
         &mut self,
-        block: BasicBlock,
+        bb: BasicBlock,
         fake_borrow_temps: &mut Vec<Local>,
         source_info: SourceInfo,
     ) {
@@ -492,16 +493,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // fake borrows so that they are live across those index
         // expressions.
         for temp in fake_borrow_temps {
-            self.cfg.push(
-                block,
-                Statement {
-                    source_info,
-                    kind: StatementKind::FakeRead(
-                        FakeReadCause::ForIndex,
-                        Box::new(Place::from(*temp)),
-                    )
-                }
-            );
+            self.cfg.push_fake_read(bb, source_info, FakeReadCause::ForIndex, Place::from(*temp));
         }
     }
 }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 37eb0cc9d96..24282a6617a 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -276,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::NeverToAny { .. }
             | ExprKind::Use { .. }
             | ExprKind::Borrow { .. }
+            | ExprKind::AddressOf { .. }
             | ExprKind::Adt { .. }
             | ExprKind::Loop { .. }
             | ExprKind::LogicalOp { .. }
diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs
index 270a1a64474..4d0039b2e8c 100644
--- a/src/librustc_mir/build/expr/category.rs
+++ b/src/librustc_mir/build/expr/category.rs
@@ -49,6 +49,7 @@ impl Category {
             | ExprKind::Use { .. }
             | ExprKind::Adt { .. }
             | ExprKind::Borrow { .. }
+            | ExprKind::AddressOf { .. }
             | ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
 
             ExprKind::Array { .. }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 07a44b190b2..6b33e8433f6 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -3,6 +3,7 @@
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::hair::*;
+use rustc::hir;
 use rustc::mir::*;
 use rustc::ty::{self, CanonicalUserTypeAnnotation};
 use rustc_data_structures::fx::FxHashMap;
@@ -295,6 +296,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.cfg.push_assign(block, source_info, destination, borrow);
                 block.unit()
             }
+            ExprKind::AddressOf {
+                mutability,
+                arg,
+            } => {
+                let address_of = match mutability {
+                    hir::Mutability::Immutable => Rvalue::AddressOf(
+                        Mutability::Not,
+                        unpack!(block = this.as_read_only_place(block, arg)),
+                    ),
+                    hir::Mutability::Mutable => Rvalue::AddressOf(
+                        Mutability::Mut,
+                        unpack!(block = this.as_place(block, arg)),
+                    ),
+                };
+                this.cfg.push_assign(block, source_info, destination, address_of);
+                block.unit()
+            }
             ExprKind::Adt {
                 adt_def,
                 variant_index,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 032ea7d8161..bf0b2439c00 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -69,8 +69,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// 3. Create the decision tree and record the places that we bind or test.
     /// 4. Determine the fake borrows that are needed from the above places.
     ///    Create the required temporaries for them.
-    /// 5. Create everything else: Create everything else: the guards and the
-    ///    arms.
+    /// 5. Create everything else: the guards and the arms.
     ///
     /// ## Fake Reads and borrows
     ///
@@ -132,13 +131,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // check safety.
 
         let source_info = self.source_info(scrutinee_span);
-        self.cfg.push(block, Statement {
-            source_info,
-            kind: StatementKind::FakeRead(
-                FakeReadCause::ForMatchedPlace,
-                box(scrutinee_place.clone()),
-            ),
-        });
+        let cause_matched_place = FakeReadCause::ForMatchedPlace;
+        self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place.clone());
 
         // Step 2. Create the otherwise and prebinding blocks.
 
@@ -314,16 +308,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
                 unpack!(block = self.into(&place, block, initializer));
 
-
                 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
                 let source_info = self.source_info(irrefutable_pat.span);
-                self.cfg.push(
-                    block,
-                    Statement {
-                        source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place)),
-                    },
-                );
+                self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
 
                 self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
                 block.unit()
@@ -359,13 +346,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
                 let pattern_source_info = self.source_info(irrefutable_pat.span);
-                self.cfg.push(
-                    block,
-                    Statement {
-                        source_info: pattern_source_info,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForLet, box(place.clone())),
-                    },
-                );
+                let cause_let = FakeReadCause::ForLet;
+                self.cfg.push_fake_read(block, pattern_source_info, cause_let, place.clone());
 
                 let ty_source_info = self.source_info(user_ty_span);
                 let user_ty = pat_ascription_ty.user_ty(
@@ -1516,13 +1498,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             );
 
             for &(_, temp) in fake_borrows {
-                self.cfg.push(post_guard_block, Statement {
-                    source_info: guard_end,
-                    kind: StatementKind::FakeRead(
-                        FakeReadCause::ForMatchGuard,
-                        box(Place::from(temp)),
-                    ),
-                });
+                let cause = FakeReadCause::ForMatchGuard;
+                self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(temp));
             }
 
             self.exit_scope(
@@ -1565,14 +1542,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // place they refer to can't be modified by the guard.
             for binding in by_value_bindings.clone() {
                 let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
-                let place = Place::from(local_id);
-                self.cfg.push(
-                    post_guard_block,
-                    Statement {
-                        source_info: guard_end,
-                        kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, box(place)),
-                    },
-                );
+                let cause = FakeReadCause::ForGuardBinding;
+                self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id));
             }
             self.bind_matched_candidate_for_arm_body(
                 post_guard_block,
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index fa0864e0de7..5522da6fbf0 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -335,6 +335,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                 }
             }
             Rvalue::Ref(..)
+            | Rvalue::AddressOf(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
             | Rvalue::NullaryOp(NullOp::SizeOf, _)
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 8c852854be1..6cbc25aa735 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -137,8 +137,11 @@ fn apply_adjustment<'a, 'tcx>(
                 arg: expr.to_ref(),
             }
         }
-        Adjust::Borrow(AutoBorrow::RawPtr(mutbl)) => {
-            raw_ref_shim(cx, expr.to_ref(), adjustment.target, mutbl, span, temp_lifetime)
+        Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
+            ExprKind::AddressOf {
+                mutability,
+                arg: expr.to_ref(),
+            }
         }
     };
 
@@ -262,17 +265,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             }
         }
 
-        hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutbl, ref arg) => {
-            cx.tcx.sess
-                .struct_span_err(
-                    expr.span,
-                    "raw borrows are not yet implemented"
-                )
-                .note("for more information, see https://github.com/rust-lang/rust/issues/64490")
-                .emit();
-
-            // Lower to an approximation to avoid further errors.
-            raw_ref_shim(cx, arg.to_ref(), expr_ty, mutbl, expr.span, temp_lifetime)
+        hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
+            ExprKind::AddressOf {
+                mutability,
+                arg: arg.to_ref(),
+            }
         }
 
         hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
@@ -1082,67 +1079,6 @@ fn convert_var(
 }
 
 
-/// Fake `&raw [mut|const] expr` using a borrow and a cast until `AddressOf`
-/// exists in MIR.
-fn raw_ref_shim<'tcx>(
-    cx: &mut Cx<'_, 'tcx>,
-    arg: ExprRef<'tcx>,
-    ty: Ty<'tcx>,
-    mutbl: hir::Mutability,
-    span: Span,
-    temp_lifetime: Option<region::Scope>,
-) -> ExprKind<'tcx> {
-    let arg_tm = if let ty::RawPtr(type_mutbl) = ty.kind {
-        type_mutbl
-    } else {
-        bug!("raw_ref_shim called with non-raw pointer type");
-    };
-    // Convert this to a suitable `&foo` and
-    // then an unsafe coercion.
-    let borrow_expr = Expr {
-        temp_lifetime,
-        ty: cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, arg_tm),
-        span,
-        kind: ExprKind::Borrow {
-            borrow_kind: mutbl.to_borrow_kind(),
-            arg,
-        },
-    };
-    let cast_expr = Expr {
-        temp_lifetime,
-        ty,
-        span,
-        kind: ExprKind::Cast { source: borrow_expr.to_ref() }
-    };
-
-    // To ensure that both implicit and explicit coercions are
-    // handled the same way, we insert an extra layer of indirection here.
-    // For explicit casts (e.g., 'foo as *const T'), the source of the 'Use'
-    // will be an ExprKind::Hair with the appropriate cast expression. Here,
-    // we make our Use source the generated Cast from the original coercion.
-    //
-    // In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by
-    // as_operand, not by as_rvalue - causing the cast result to be stored in a temporary.
-    // Ordinary, this is identical to using the cast directly as an rvalue. However, if the
-    // source of the cast was previously borrowed as mutable, storing the cast in a
-    // temporary gives the source a chance to expire before the cast is used. For
-    // structs with a self-referential *mut ptr, this allows assignment to work as
-    // expected.
-    //
-    // For example, consider the type 'struct Foo { field: *mut Foo }',
-    // The method 'fn bar(&mut self) { self.field = self }'
-    // triggers a coercion from '&mut self' to '*mut self'. In order
-    // for the assignment to be valid, the implicit borrow
-    // of 'self' involved in the coercion needs to end before the local
-    // containing the '*mut T' is assigned to 'self.field' - otherwise,
-    // we end up trying to assign to 'self.field' while we have another mutable borrow
-    // active.
-    //
-    // We only need to worry about this kind of thing for coercions from refs to ptrs,
-    // since they get rid of a borrow implicitly.
-    ExprKind::Use { source: cast_expr.to_ref() }
-}
-
 fn bin_op(op: hir::BinOpKind) -> BinOp {
     match op {
         hir::BinOpKind::Add => BinOp::Add,
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 47644d9ba83..46e0d2a17b3 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -212,6 +212,11 @@ pub enum ExprKind<'tcx> {
         borrow_kind: BorrowKind,
         arg: ExprRef<'tcx>,
     },
+    /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
+    AddressOf {
+        mutability: hir::Mutability,
+        arg: ExprRef<'tcx>,
+    },
     Break {
         label: region::Scope,
         value: Option<ExprRef<'tcx>>,
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 37a9381271a..c3720328506 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -238,7 +238,7 @@ use super::{FieldPat, Pat, PatKind, PatRange};
 use rustc::hir::def_id::DefId;
 use rustc::hir::{HirId, RangeEnd};
 use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx};
-use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef};
 
 use rustc::lint;
 use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
@@ -354,7 +354,7 @@ impl PatternFolder<'tcx> for LiteralExpander<'tcx> {
 }
 
 impl<'tcx> Pat<'tcx> {
-    fn is_wildcard(&self) -> bool {
+    pub(super) fn is_wildcard(&self) -> bool {
         match *self.kind {
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => true,
             _ => false,
@@ -596,9 +596,21 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
         }
     }
 
-    fn is_local(&self, ty: Ty<'tcx>) -> bool {
+    // Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
+    pub fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind {
-            ty::Adt(adt_def, ..) => adt_def.did.is_local(),
+            ty::Adt(def, ..) => {
+                def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local()
+            }
+            _ => false,
+        }
+    }
+
+    // Returns whether the given variant is from another crate and has its fields declared
+    // `#[non_exhaustive]`.
+    fn is_foreign_non_exhaustive_variant(&self, ty: Ty<'tcx>, variant: &VariantDef) -> bool {
+        match ty.kind {
+            ty::Adt(def, ..) => variant.is_field_list_non_exhaustive() && !def.did.is_local(),
             _ => false,
         }
     }
@@ -758,6 +770,10 @@ impl<'tcx> Constructor<'tcx> {
     // Returns the set of constructors covered by `self` but not by
     // anything in `other_ctors`.
     fn subtract_ctors(&self, other_ctors: &Vec<Constructor<'tcx>>) -> Vec<Constructor<'tcx>> {
+        if other_ctors.is_empty() {
+            return vec![self.clone()];
+        }
+
         match self {
             // Those constructors can only match themselves.
             Single | Variant(_) | ConstantValue(..) | FloatRange(..) => {
@@ -858,8 +874,7 @@ impl<'tcx> Constructor<'tcx> {
                         vec![Pat::wildcard_from_ty(substs.type_at(0))]
                     } else {
                         let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
-                        let is_non_exhaustive =
-                            variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
+                        let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(ty, variant);
                         variant
                             .fields
                             .iter()
@@ -1205,6 +1220,8 @@ impl<'tcx> Witness<'tcx> {
 ///
 /// We make sure to omit constructors that are statically impossible. E.g., for
 /// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
+/// Invariant: this returns an empty `Vec` if and only if the type is uninhabited (as determined by
+/// `cx.is_uninhabited()`).
 fn all_constructors<'a, 'tcx>(
     cx: &mut MatchCheckCtxt<'a, 'tcx>,
     pcx: PatCtxt<'tcx>,
@@ -1235,47 +1252,45 @@ fn all_constructors<'a, 'tcx>(
             vec![Slice(Slice { array_len: None, kind })]
         }
         ty::Adt(def, substs) if def.is_enum() => {
-            let ctors: Vec<_> = def
-                .variants
-                .iter()
-                .filter(|v| {
-                    !cx.tcx.features().exhaustive_patterns
-                        || !v
-                            .uninhabited_from(cx.tcx, substs, def.adt_kind())
+            let ctors: Vec<_> = if cx.tcx.features().exhaustive_patterns {
+                // If `exhaustive_patterns` is enabled, we exclude variants known to be
+                // uninhabited.
+                def.variants
+                    .iter()
+                    .filter(|v| {
+                        !v.uninhabited_from(cx.tcx, substs, def.adt_kind())
                             .contains(cx.tcx, cx.module)
-                })
-                .map(|v| Variant(v.def_id))
-                .collect();
-
-            // If our scrutinee is *privately* an empty enum, we must treat it as though it had an
-            // "unknown" constructor (in that case, all other patterns obviously can't be variants)
-            // to avoid exposing its emptyness. See the `match_privately_empty` test for details.
-            // FIXME: currently the only way I know of something can be a privately-empty enum is
-            // when the exhaustive_patterns feature flag is not present, so this is only needed for
-            // that case.
-            let is_privately_empty = ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
-            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
-            // additionnal "unknown" constructor.
-            let is_declared_nonexhaustive =
-                def.is_variant_list_non_exhaustive() && !cx.is_local(pcx.ty);
-
-            if is_privately_empty || is_declared_nonexhaustive {
-                // There is no point in enumerating all possible variants, because the user can't
-                // actually match against them themselves. So we return only the fictitious
-                // constructor.
-                // E.g., in an example like:
-                // ```
-                //     let err: io::ErrorKind = ...;
-                //     match err {
-                //         io::ErrorKind::NotFound => {},
-                //     }
-                // ```
-                // we don't want to show every possible IO error, but instead have only `_` as the
-                // witness.
-                vec![NonExhaustive]
+                    })
+                    .map(|v| Variant(v.def_id))
+                    .collect()
             } else {
-                ctors
-            }
+                def.variants.iter().map(|v| Variant(v.def_id)).collect()
+            };
+
+            // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
+            // additional "unknown" constructor.
+            // There is no point in enumerating all possible variants, because the user can't
+            // actually match against them all themselves. So we always return only the fictitious
+            // constructor.
+            // E.g., in an example like:
+            // ```
+            //     let err: io::ErrorKind = ...;
+            //     match err {
+            //         io::ErrorKind::NotFound => {},
+            //     }
+            // ```
+            // we don't want to show every possible IO error, but instead have only `_` as the
+            // witness.
+            let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
+
+            // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
+            // as though it had an "unknown" constructor to avoid exposing its emptyness. Note that
+            // an empty match will still be considered exhaustive because that case is handled
+            // separately in `check_match`.
+            let is_secretly_empty =
+                def.variants.is_empty() && !cx.tcx.features().exhaustive_patterns;
+
+            if is_secretly_empty || is_declared_nonexhaustive { vec![NonExhaustive] } else { ctors }
         }
         ty::Char => {
             vec![
@@ -1605,6 +1620,7 @@ pub fn is_useful<'p, 'tcx>(
     v: &PatStack<'p, 'tcx>,
     witness_preference: WitnessPreference,
     hir_id: HirId,
+    is_top_level: bool,
 ) -> Usefulness<'tcx, 'p> {
     let &Matrix(ref rows) = matrix;
     debug!("is_useful({:#?}, {:#?})", matrix, v);
@@ -1632,7 +1648,7 @@ pub fn is_useful<'p, 'tcx>(
         let mut unreachable_pats = Vec::new();
         let mut any_is_useful = false;
         for v in vs {
-            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id);
+            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
             match res {
                 Useful(pats) => {
                     any_is_useful = true;
@@ -1732,7 +1748,7 @@ pub fn is_useful<'p, 'tcx>(
         } else {
             let matrix = matrix.specialize_wildcard();
             let v = v.to_tail();
-            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id);
+            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
 
             // In this case, there's at least one "free"
             // constructor that is only matched against by
@@ -1761,7 +1777,10 @@ pub fn is_useful<'p, 'tcx>(
             // `(<direction-1>, <direction-2>, true)` - we are
             // satisfied with `(_, _, true)`. In this case,
             // `used_ctors` is empty.
-            if missing_ctors.all_ctors_are_missing() {
+            // The exception is: if we are at the top-level, for example in an empty match, we
+            // sometimes prefer reporting the list of constructors instead of just `_`.
+            let report_ctors_rather_than_wildcard = is_top_level && !IntRange::is_integral(pcx.ty);
+            if missing_ctors.all_ctors_are_missing() && !report_ctors_rather_than_wildcard {
                 // All constructors are unused. Add a wild pattern
                 // rather than each individual constructor.
                 usefulness.apply_wildcard(pcx.ty)
@@ -1793,7 +1812,7 @@ fn is_useful_specialized<'p, 'tcx>(
         cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
     let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
     v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
-        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
+        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
         .map(|u| u.apply_constructor(cx, &ctor, lty))
         .unwrap_or(NotUseful)
 }
@@ -2308,7 +2327,7 @@ fn specialize_one_pattern<'p, 'tcx>(
 
         PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
             let ref variant = adt_def.variants[variant_index];
-            let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty);
+            let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant);
             Some(Variant(variant.def_id))
                 .filter(|variant_constructor| variant_constructor == constructor)
                 .map(|_| {
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 737af3e1358..8156cfe7ab5 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -148,8 +148,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
                         self.tables,
                     );
                     patcx.include_lint_checks();
-                    let pattern: &_ =
-                        cx.pattern_arena.alloc(expand_pattern(cx, patcx.lower_pattern(&arm.pat)));
+                    let pattern = patcx.lower_pattern(&arm.pat);
+                    let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
                     if !patcx.errors.is_empty() {
                         patcx.report_inlining_errors(arm.pat.span);
                         have_errors = true;
@@ -166,73 +166,12 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
             // Fourth, check for unreachable arms.
             let matrix = check_arms(cx, &inlined_arms, source);
 
-            // Then, if the match has no arms, check whether the scrutinee
-            // is uninhabited.
-            let pat_ty = self.tables.node_type(scrut.hir_id);
-            let module = self.tcx.hir().get_module_parent(scrut.hir_id);
-            let mut def_span = None;
-            let mut missing_variants = vec![];
-            if inlined_arms.is_empty() {
-                let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
-                    self.tcx.is_ty_uninhabited_from(module, pat_ty)
-                } else {
-                    match pat_ty.kind {
-                        ty::Never => true,
-                        ty::Adt(def, _) => {
-                            def_span = self.tcx.hir().span_if_local(def.did);
-                            if def.variants.len() < 4 && !def.variants.is_empty() {
-                                // keep around to point at the definition of non-covered variants
-                                missing_variants =
-                                    def.variants.iter().map(|variant| variant.ident).collect();
-                            }
-
-                            let is_non_exhaustive_and_non_local =
-                                def.is_variant_list_non_exhaustive() && !def.did.is_local();
-
-                            !(is_non_exhaustive_and_non_local) && def.variants.is_empty()
-                        }
-                        _ => false,
-                    }
-                };
-                if !scrutinee_is_uninhabited {
-                    // We know the type is inhabited, so this must be wrong
-                    let mut err = create_e0004(
-                        self.tcx.sess,
-                        scrut.span,
-                        format!(
-                            "non-exhaustive patterns: {}",
-                            match missing_variants.len() {
-                                0 => format!("type `{}` is non-empty", pat_ty),
-                                1 => format!(
-                                    "pattern `{}` of type `{}` is not handled",
-                                    missing_variants[0].name, pat_ty,
-                                ),
-                                _ => format!(
-                                    "multiple patterns of type `{}` are not handled",
-                                    pat_ty
-                                ),
-                            }
-                        ),
-                    );
-                    err.help(
-                        "ensure that all possible cases are being handled, \
-                         possibly by adding wildcards or more match arms",
-                    );
-                    if let Some(sp) = def_span {
-                        err.span_label(sp, format!("`{}` defined here", pat_ty));
-                    }
-                    // point at the definition of non-covered enum variants
-                    for variant in &missing_variants {
-                        err.span_label(variant.span, "variant not covered");
-                    }
-                    err.emit();
-                }
-                // If the type *is* uninhabited, it's vacuously exhaustive
-                return;
-            }
-
+            // Fifth, check if the match is exhaustive.
             let scrut_ty = self.tables.node_type(scrut.hir_id);
-            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id);
+            // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
+            // since an empty matrix can occur when there are arms, if those arms all have guards.
+            let is_empty_match = inlined_arms.is_empty();
+            check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
         })
     }
 
@@ -390,7 +329,7 @@ fn check_arms<'p, 'tcx>(
     for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
         let v = PatStack::from_pattern(pat);
 
-        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id) {
+        match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
             NotUseful => {
                 match source {
                     hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
@@ -478,7 +417,8 @@ fn check_not_useful<'p, 'tcx>(
     hir_id: HirId,
 ) -> Result<(), Vec<super::Pat<'tcx>>> {
     let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
-    match is_useful(cx, matrix, &PatStack::from_pattern(wild_pattern), ConstructWitness, hir_id) {
+    let v = PatStack::from_pattern(wild_pattern);
+    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
         NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
         UsefulWithWitness(pats) => Err(if pats.is_empty() {
             bug!("Exhaustiveness check returned no witnesses")
@@ -495,25 +435,60 @@ fn check_exhaustive<'p, 'tcx>(
     sp: Span,
     matrix: &Matrix<'p, 'tcx>,
     hir_id: HirId,
+    is_empty_match: bool,
 ) {
+    // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by
+    // `is_useful` to exhaustively match uninhabited types, so we manually check here.
+    if is_empty_match && !cx.tcx.features().exhaustive_patterns {
+        let scrutinee_is_visibly_uninhabited = match scrut_ty.kind {
+            ty::Never => true,
+            ty::Adt(def, _) => {
+                def.is_enum()
+                    && def.variants.is_empty()
+                    && !cx.is_foreign_non_exhaustive_enum(scrut_ty)
+            }
+            _ => false,
+        };
+        if scrutinee_is_visibly_uninhabited {
+            // If the type *is* uninhabited, an empty match is vacuously exhaustive.
+            return;
+        }
+    }
+
     let witnesses = match check_not_useful(cx, scrut_ty, matrix, hir_id) {
         Ok(_) => return,
         Err(err) => err,
     };
 
-    let joined_patterns = joined_uncovered_patterns(&witnesses);
-    let mut err = create_e0004(
-        cx.tcx.sess,
-        sp,
-        format!("non-exhaustive patterns: {} not covered", joined_patterns),
-    );
-    err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+    let non_empty_enum = match scrut_ty.kind {
+        ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
+        _ => false,
+    };
+    // In the case of an empty match, replace the '`_` not covered' diagnostic with something more
+    // informative.
+    let mut err;
+    if is_empty_match && !non_empty_enum {
+        err = create_e0004(
+            cx.tcx.sess,
+            sp,
+            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
+        );
+    } else {
+        let joined_patterns = joined_uncovered_patterns(&witnesses);
+        err = create_e0004(
+            cx.tcx.sess,
+            sp,
+            format!("non-exhaustive patterns: {} not covered", joined_patterns),
+        );
+        err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+    };
+
     adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
     err.help(
         "ensure that all possible cases are being handled, \
          possibly by adding wildcards or more match arms",
-    )
-    .emit();
+    );
+    err.emit();
 }
 
 fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String {
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 33ed69af6ba..33cdf1b27f8 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -248,7 +248,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 )?;
             }
 
-            Ref(_, _, ref place) => {
+            AddressOf(_, ref place) | Ref(_, _, ref place) => {
                 let src = self.eval_place(place)?;
                 let place = self.force_allocation(src)?;
                 if place.layout.size.bytes() > 0 {
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index efa0d266cbc..916ea3dc393 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -140,7 +140,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx);
         let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
         // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
-        let ty = fn_sig.inputs()[0].builtin_deref(true).unwrap().ty;
+        let args = fn_sig.inputs();
+        if args.len() != 1 {
+            throw_ub_format!(
+                "drop fn should have 1 argument, but signature is {:?}", fn_sig
+            );
+        }
+        let ty = args[0].builtin_deref(true)
+            .ok_or_else(|| err_ub_format!(
+                "drop fn argument type {} is not a pointer type",
+                args[0]
+            ))?
+            .ty;
         Ok((drop_instance, ty))
     }
 
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index e358df2f213..1dbcfe5588e 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -22,28 +22,23 @@ use super::{
 
 macro_rules! throw_validation_failure {
     ($what:expr, $where:expr, $details:expr) => {{
-        let where_ = path_format(&$where);
-        let where_ = if where_.is_empty() {
-            String::new()
-        } else {
-            format!(" at {}", where_)
-        };
-        throw_unsup!(ValidationFailure(format!(
-            "encountered {}{}, but expected {}",
-            $what, where_, $details,
-        )))
+        let mut msg = format!("encountered {}", $what);
+        let where_ = &$where;
+        if !where_.is_empty() {
+            msg.push_str(" at ");
+            write_path(&mut msg, where_);
+        }
+        write!(&mut msg, ", but expected {}", $details).unwrap();
+        throw_unsup!(ValidationFailure(msg))
     }};
     ($what:expr, $where:expr) => {{
-        let where_ = path_format(&$where);
-        let where_ = if where_.is_empty() {
-            String::new()
-        } else {
-            format!(" at {}", where_)
-        };
-        throw_unsup!(ValidationFailure(format!(
-            "encountered {}{}",
-            $what, where_,
-        )))
+        let mut msg = format!("encountered {}", $what);
+        let where_ = &$where;
+        if !where_.is_empty() {
+            msg.push_str(" at ");
+            write_path(&mut msg, where_);
+        }
+        throw_unsup!(ValidationFailure(msg))
     }};
 }
 
@@ -60,7 +55,7 @@ macro_rules! try_validation {
             Ok(x) => x,
             Err(_) => throw_validation_failure!($what, $where),
         }
-    }}
+    }};
 }
 
 /// We want to show a nice path to the invalid field for diagnostics,
@@ -113,10 +108,9 @@ impl<T: Copy + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH>
 }
 
 /// Format a path
-fn path_format(path: &Vec<PathElem>) -> String {
+fn write_path(out: &mut String, path: &Vec<PathElem>) {
     use self::PathElem::*;
 
-    let mut out = String::new();
     for elem in path.iter() {
         match elem {
             Field(name) => write!(out, ".{}", name),
@@ -135,7 +129,6 @@ fn path_format(path: &Vec<PathElem>) -> String {
             DynDowncast => write!(out, ".<dyn-downcast>"),
         }.unwrap()
     }
-    out
 }
 
 // Test if a range that wraps at overflow contains `test`
@@ -428,7 +421,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                             err_unsup!(InvalidNullPointerUsage) =>
                                 throw_validation_failure!("NULL reference", self.path),
                             err_unsup!(AlignmentCheckFailed { required, has }) =>
-                                throw_validation_failure!(format!("unaligned reference \
+                                throw_validation_failure!(format_args!("unaligned reference \
                                     (required {} byte alignment but found {})",
                                     required.bytes(), has.bytes()), self.path),
                             err_unsup!(ReadBytesAsPointer) =>
@@ -519,7 +512,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         let value = try_validation!(value.not_undef(),
             value,
             self.path,
-            format!(
+            format_args!(
                 "something {}",
                 wrapping_range_format(&layout.valid_range, max_hi),
             )
@@ -532,7 +525,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                         throw_validation_failure!(
                             "a potentially NULL pointer",
                             self.path,
-                            format!(
+                            format_args!(
                                 "something that cannot possibly fail to be {}",
                                 wrapping_range_format(&layout.valid_range, max_hi)
                             )
@@ -545,7 +538,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                     throw_validation_failure!(
                         "a pointer",
                         self.path,
-                        format!(
+                        format_args!(
                             "something that cannot possibly fail to be {}",
                             wrapping_range_format(&layout.valid_range, max_hi)
                         )
@@ -562,7 +555,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
             throw_validation_failure!(
                 bits,
                 self.path,
-                format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
+                format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
             )
         }
     }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 42b72b64f8a..f6b3c5b8e5e 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -18,7 +18,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(drain_filter)]
 #![feature(exhaustive_patterns)]
 #![feature(iter_order_by)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(specialization)]
 #![feature(try_trait)]
 #![feature(unicode_internals)]
diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs
index dc21c674eea..0e4fe3f7f40 100644
--- a/src/librustc_mir/transform/add_retag.rs
+++ b/src/librustc_mir/transform/add_retag.rs
@@ -136,21 +136,9 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
             // iterate backwards using indices.
             for i in (0..block_data.statements.len()).rev() {
                 let (retag_kind, place) = match block_data.statements[i].kind {
-                    // If we are casting *from* a reference, we may have to retag-as-raw.
-                    StatementKind::Assign(box(ref place, Rvalue::Cast(
-                        CastKind::Misc,
-                        ref src,
-                        dest_ty,
-                    ))) => {
-                        let src_ty = src.ty(&*local_decls, tcx);
-                        if src_ty.is_region_ptr() {
-                            // The only `Misc` casts on references are those creating raw pointers.
-                            assert!(dest_ty.is_unsafe_ptr());
-                            (RetagKind::Raw, place.clone())
-                        } else {
-                            // Some other cast, no retag
-                            continue
-                        }
+                    // Retag-as-raw after escaping to a raw pointer.
+                    StatementKind::Assign(box (ref place, Rvalue::AddressOf(..))) => {
+                        (RetagKind::Raw, place.clone())
                     }
                     // Assignments of reference or ptr type are the ones where we may have
                     // to update tags.  This includes `x = &[mut] ...` and hence
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 393ae9442a1..e5f3003cd71 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -170,6 +170,10 @@ impl NonConstOp for LiveDrop {
 #[derive(Debug)]
 pub struct Loop;
 impl NonConstOp for Loop {
+    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+        Some(tcx.features().const_loop)
+    }
+
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
         // This should be caught by the HIR const-checker.
         item.tcx.sess.delay_span_bug(
@@ -221,6 +225,23 @@ impl NonConstOp for MutBorrow {
 }
 
 #[derive(Debug)]
+pub struct MutAddressOf;
+impl NonConstOp for MutAddressOf {
+    fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
+        Some(tcx.features().const_mut_refs)
+    }
+
+    fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
+        feature_err(
+            &item.tcx.sess.parse_sess,
+            sym::const_mut_refs,
+            span,
+            &format!("`&raw mut` is not allowed in {}s", item.const_kind())
+        ).emit();
+    }
+}
+
+#[derive(Debug)]
 pub struct MutDeref;
 impl NonConstOp for MutDeref {
     fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 223a5f8d605..28243bd71a2 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -151,17 +151,15 @@ pub trait Qualif {
                 Self::in_operand(cx, per_local, lhs) || Self::in_operand(cx, per_local, rhs)
             }
 
-            Rvalue::Ref(_, _, ref place) => {
+            Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
                 // Special-case reborrows to be more like a copy of the reference.
-                if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
-                    if ProjectionElem::Deref == elem {
-                        let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
-                        if let ty::Ref(..) = base_ty.kind {
-                            return Self::in_place(cx, per_local, PlaceRef {
-                                base: &place.base,
-                                projection: proj_base,
-                            });
-                        }
+                if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
+                    let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
+                    if let ty::Ref(..) = base_ty.kind {
+                        return Self::in_place(cx, per_local, PlaceRef {
+                            base: &place.base,
+                            projection: proj_base,
+                        });
                     }
                 }
 
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index 6261315c711..0904264586c 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -276,6 +276,27 @@ impl Validator<'a, 'mir, 'tcx> {
             self.check_op_spanned(ops::StaticAccess, span)
         }
     }
+
+    fn check_immutable_borrow_like(
+        &mut self,
+        location: Location,
+        place: &Place<'tcx>,
+    ) {
+        // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
+        // seek the cursors beforehand.
+        self.qualifs.has_mut_interior.cursor.seek_before(location);
+        self.qualifs.indirectly_mutable.seek(location);
+
+        let borrowed_place_has_mut_interior = HasMutInterior::in_place(
+            &self.item,
+            &|local| self.qualifs.has_mut_interior_eager_seek(local),
+            place.as_ref(),
+        );
+
+        if borrowed_place_has_mut_interior {
+            self.check_op(ops::CellBorrow);
+        }
+    }
 }
 
 impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
@@ -302,26 +323,44 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
         trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
 
         // Special-case reborrows to be more like a copy of a reference.
-        if let Rvalue::Ref(_, kind, ref place) = *rvalue {
-            if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
-                let ctx = match kind {
-                    BorrowKind::Shared => PlaceContext::NonMutatingUse(
-                        NonMutatingUseContext::SharedBorrow,
-                    ),
-                    BorrowKind::Shallow => PlaceContext::NonMutatingUse(
-                        NonMutatingUseContext::ShallowBorrow,
-                    ),
-                    BorrowKind::Unique => PlaceContext::NonMutatingUse(
-                        NonMutatingUseContext::UniqueBorrow,
-                    ),
-                    BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
-                        MutatingUseContext::Borrow,
-                    ),
-                };
-                self.visit_place_base(&place.base, ctx, location);
-                self.visit_projection(&place.base, reborrowed_proj, ctx, location);
-                return;
+        match *rvalue {
+            Rvalue::Ref(_, kind, ref place) => {
+                if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
+                    let ctx = match kind {
+                        BorrowKind::Shared => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::SharedBorrow,
+                        ),
+                        BorrowKind::Shallow => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::ShallowBorrow,
+                        ),
+                        BorrowKind::Unique => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::UniqueBorrow,
+                        ),
+                        BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
+                            MutatingUseContext::Borrow,
+                        ),
+                    };
+                    self.visit_place_base(&place.base, ctx, location);
+                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    return;
+                }
             }
+            Rvalue::AddressOf(mutbl, ref place) => {
+                if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
+                    let ctx = match mutbl {
+                        Mutability::Not => PlaceContext::NonMutatingUse(
+                            NonMutatingUseContext::AddressOf,
+                        ),
+                        Mutability::Mut => PlaceContext::MutatingUse(
+                            MutatingUseContext::AddressOf,
+                        ),
+                    };
+                    self.visit_place_base(&place.base, ctx, location);
+                    self.visit_projection(&place.base, reborrowed_proj, ctx, location);
+                    return;
+                }
+            }
+            _ => {}
         }
 
         self.super_rvalue(rvalue, location);
@@ -367,34 +406,25 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
                 }
             }
 
+            Rvalue::AddressOf(Mutability::Mut, _) => {
+                self.check_op(ops::MutAddressOf)
+            }
+
             // At the moment, `PlaceBase::Static` is only used for promoted MIR.
             | Rvalue::Ref(_, BorrowKind::Shared, ref place)
             | Rvalue::Ref(_, BorrowKind::Shallow, ref place)
+            | Rvalue::AddressOf(Mutability::Not, ref place)
             if matches!(place.base, PlaceBase::Static(_))
             => bug!("Saw a promoted during const-checking, which must run before promotion"),
 
-            | Rvalue::Ref(_, kind @ BorrowKind::Shared, ref place)
-            | Rvalue::Ref(_, kind @ BorrowKind::Shallow, ref place)
-            => {
-                // FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
-                // seek the cursors beforehand.
-                self.qualifs.has_mut_interior.cursor.seek_before(location);
-                self.qualifs.indirectly_mutable.seek(location);
-
-                let borrowed_place_has_mut_interior = HasMutInterior::in_place(
-                    &self.item,
-                    &|local| self.qualifs.has_mut_interior_eager_seek(local),
-                    place.as_ref(),
-                );
-
-                if borrowed_place_has_mut_interior {
-                    if let BorrowKind::Mut{ .. } = kind {
-                        self.check_op(ops::MutBorrow);
-                    } else {
-                        self.check_op(ops::CellBorrow);
-                    }
-                }
-            }
+            | Rvalue::Ref(_, BorrowKind::Shared, ref place)
+            | Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
+                self.check_immutable_borrow_like(location, place)
+            },
+
+            Rvalue::AddressOf(Mutability::Not, ref place) => {
+                self.check_immutable_borrow_like(location, place)
+            },
 
             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
                 let operand_ty = operand.ty(*self.body, self.tcx);
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index aff91ac5af9..c4d89b1494d 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -517,7 +517,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     let left_bits = place_layout.size.bits();
                     let right_size = r.layout.size;
                     let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
-                    if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
+                    if r_bits.map_or(false, |b| b >= left_bits as u128) {
                         let lint_root = match &self.source_scopes[source_info.scope].local_data {
                             ClearCrossCrate::Set(data) => data.lint_root,
                             ClearCrossCrate::Clear => return None,
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 4c723199102..4e5d8ae08fe 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -196,7 +196,12 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
         } else if let TempState::Defined { ref mut uses, .. } = *temp {
             // We always allow borrows, even mutable ones, as we need
             // to promote mutable borrows of some ZSTs e.g., `&mut []`.
-            let allowed_use = context.is_borrow() || context.is_nonmutating_use();
+            let allowed_use = match context {
+                PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+                | PlaceContext::NonMutatingUse(_) => true,
+                PlaceContext::MutatingUse(_)
+                | PlaceContext::NonUse(_) => false,
+            };
             debug!("visit_local: allowed_use={:?}", allowed_use);
             if allowed_use {
                 *uses += 1;
@@ -618,6 +623,21 @@ impl<'tcx> Validator<'_, 'tcx> {
                 self.validate_operand(rhs)
             }
 
+            Rvalue::AddressOf(_, place) => {
+                // Raw reborrows can come from reference to pointer coercions,
+                // so are allowed.
+                if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
+                    let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
+                    if let ty::Ref(..) = base_ty.kind {
+                        return self.validate_place(PlaceRef {
+                            base: &place.base,
+                            projection: proj_base,
+                        });
+                    }
+                }
+                Err(Unpromotable)
+            }
+
             Rvalue::Ref(_, kind, place) => {
                 if let BorrowKind::Mut { .. } = kind {
                     let ty = place.ty(*self.body, self.tcx).ty;
@@ -950,7 +970,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                 Candidate::Ref(loc) => {
                     let ref mut statement = blocks[loc.block].statements[loc.statement_index];
                     match statement.kind {
-                        StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
+                        StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
                             // Use the underlying local for this (necessarily interior) borrow.
                             let ty = place.base.ty(local_decls).ty;
                             let span = statement.source_info.span;
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index cf2e1306dc4..a61bff37fc8 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -80,7 +80,7 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> Mc
     for ty in ty.walk() {
         match ty.kind {
             ty::Ref(_, _, hir::Mutability::Mutable) => {
-                if !tcx.features().const_mut_refs {
+                if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
                     return Err((
                         span,
                         "mutable references in const fn are unstable".into(),
@@ -135,7 +135,10 @@ fn check_rvalue(
         Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
             check_operand(tcx, operand, span, def_id, body)
         }
-        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
+        Rvalue::Len(place)
+        | Rvalue::Discriminant(place)
+        | Rvalue::Ref(_, _, place)
+        | Rvalue::AddressOf(_, place) => {
             check_place(tcx, place, span, def_id, body)
         }
         Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
@@ -147,9 +150,6 @@ fn check_rvalue(
                     span,
                     "casting pointers to ints is unstable in const fn".into(),
                 )),
-                (CastTy::RPtr(_), CastTy::Float) => bug!(),
-                (CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
-                (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
                 _ => check_operand(tcx, operand, span, def_id, body),
             }
         }
@@ -220,7 +220,7 @@ fn check_statement(
         }
 
         | StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
-        if !tcx.features().const_if_match
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
         => {
             Err((span, "loops and conditional expressions are not stable in const fn".into()))
         }
@@ -272,7 +272,7 @@ fn check_place(
     while let &[ref proj_base @ .., elem] = cursor {
         cursor = proj_base;
         match elem {
-            ProjectionElem::Downcast(..) if !tcx.features().const_if_match
+            ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match)
                 => return Err((span, "`match` or `if let` in `const fn` is unstable".into())),
             ProjectionElem::Downcast(_symbol, _variant_index) => {}
 
@@ -329,7 +329,7 @@ fn check_terminator(
 
         | TerminatorKind::FalseEdges { .. }
         | TerminatorKind::SwitchInt { .. }
-        if !tcx.features().const_if_match
+        if !feature_allowed(tcx, def_id, sym::const_if_match)
         => Err((
             span,
             "loops and conditional expressions are not stable in const fn".into(),
@@ -341,7 +341,7 @@ fn check_terminator(
         }
 
         // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
-        TerminatorKind::Unreachable if tcx.features().const_if_match => Ok(()),
+        TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),
 
         | TerminatorKind::Abort | TerminatorKind::Unreachable => {
             Err((span, "const fn with unreachable code is not stable".into()))
@@ -390,8 +390,12 @@ fn check_terminator(
             cleanup: _,
         } => check_operand(tcx, cond, span, def_id, body),
 
+        | TerminatorKind::FalseUnwind { .. }
+        if feature_allowed(tcx, def_id, sym::const_loop)
+        => Ok(()),
+
         TerminatorKind::FalseUnwind { .. } => {
             Err((span, "loops are not allowed in const fn".into()))
-        },
+        }
     }
 }
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 67e5bfafafd..4f482431d33 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -557,10 +557,10 @@ where
     ///    if can_go then succ else drop-block
     /// drop-block:
     ///    if ptr_based {
-    ///        ptr = &mut *cur
+    ///        ptr = cur
     ///        cur = cur.offset(1)
     ///    } else {
-    ///        ptr = &mut P[cur]
+    ///        ptr = &raw mut P[cur]
     ///        cur = cur + 1
     ///    }
     ///    drop(ptr)
@@ -574,34 +574,28 @@ where
         unwind: Unwind,
         ptr_based: bool,
     ) -> BasicBlock {
-        let copy = |place: &Place<'tcx>| Operand::Copy(place.clone());
-        let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
+        let copy = |place: Place<'tcx>| Operand::Copy(place);
+        let move_ = |place: Place<'tcx>| Operand::Move(place);
         let tcx = self.tcx();
 
-        let ref_ty = tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut {
+        let ptr_ty = tcx.mk_ptr(ty::TypeAndMut {
             ty: ety,
             mutbl: hir::Mutability::Mutable
         });
-        let ptr = &Place::from(self.new_temp(ref_ty));
-        let can_go = &Place::from(self.new_temp(tcx.types.bool));
+        let ptr = &Place::from(self.new_temp(ptr_ty));
+        let can_go = Place::from(self.new_temp(tcx.types.bool));
 
         let one = self.constant_usize(1);
         let (ptr_next, cur_next) = if ptr_based {
-            (Rvalue::Ref(
-                tcx.lifetimes.re_erased,
-                BorrowKind::Mut { allow_two_phase_borrow: false },
-                Place {
-                    base: PlaceBase::Local(cur),
-                    projection: tcx.intern_place_elems(&vec![ProjectionElem::Deref]),
-                }
-             ),
-             Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
+            (
+                Rvalue::Use(copy(cur.into())),
+                Rvalue::BinaryOp(BinOp::Offset, move_(cur.into()), one),
+            )
         } else {
-            (Rvalue::Ref(
-                 tcx.lifetimes.re_erased,
-                 BorrowKind::Mut { allow_two_phase_borrow: false },
-                 tcx.mk_place_index(self.place.clone(), cur)),
-             Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one))
+            (
+                Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place.clone(), cur)),
+                Rvalue::BinaryOp(BinOp::Add, move_(cur.into()), one),
+            )
         };
 
         let drop_block = BasicBlockData {
@@ -620,9 +614,9 @@ where
 
         let loop_block = BasicBlockData {
             statements: vec![
-                self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
-                                                     copy(&Place::from(cur)),
-                                                     copy(length_or_end)))
+                self.assign(&can_go, Rvalue::BinaryOp(BinOp::Eq,
+                                                     copy(Place::from(cur)),
+                                                     copy(length_or_end.clone())))
             ],
             is_cleanup: unwind.is_cleanup(),
             terminator: Some(Terminator {
@@ -725,8 +719,6 @@ where
 
         let cur = self.new_temp(iter_ty);
         let length_or_end = if ptr_based {
-            // FIXME check if we want to make it return a `Place` directly
-            // if all use sites want a `Place::Base` anyway.
             Place::from(self.new_temp(iter_ty))
         } else {
             length.clone()
@@ -753,23 +745,16 @@ where
         let drop_block_stmts = if ptr_based {
             let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place));
             let tmp = Place::from(self.new_temp(tmp_ty));
-            // tmp = &mut P;
+            // tmp = &raw mut P;
             // cur = tmp as *mut T;
             // end = Offset(cur, len);
             vec![
-                self.assign(&tmp, Rvalue::Ref(
-                    tcx.lifetimes.re_erased,
-                    BorrowKind::Mut { allow_two_phase_borrow: false },
-                    self.place.clone()
-                )),
-                self.assign(
-                    &cur,
-                    Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty),
-                ),
+                self.assign(&tmp, Rvalue::AddressOf(Mutability::Mut, self.place.clone())),
+                self.assign(&cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)),
                 self.assign(
                     &length_or_end,
-                    Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length)
-                )),
+                    Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length)),
+                ),
             ]
         } else {
             // cur = 0 (length already pushed)
diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs
index 68c2e16399a..01eebeb8c55 100644
--- a/src/librustc_mir/util/liveness.rs
+++ b/src/librustc_mir/util/liveness.rs
@@ -167,6 +167,8 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
         PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
 
+        PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
+        PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
         PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 1e9203f377f..38ae7050abe 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -344,12 +344,12 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
         noop_flat_map_item(configure!(self, item), self)
     }
 
-    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
-        noop_flat_map_impl_item(configure!(self, item), self)
+    fn flat_map_impl_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
+        noop_flat_map_assoc_item(configure!(self, item), self)
     }
 
-    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
-        noop_flat_map_trait_item(configure!(self, item), self)
+    fn flat_map_trait_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
+        noop_flat_map_assoc_item(configure!(self, item), self)
     }
 
     fn visit_mac(&mut self, _mac: &mut ast::Mac) {
diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs
index faff386e923..58c36524380 100644
--- a/src/librustc_parse/lib.rs
+++ b/src/librustc_parse/lib.rs
@@ -305,10 +305,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
         Nonterminal::NtItem(ref item) => {
             prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
         }
-        Nonterminal::NtTraitItem(ref item) => {
-            prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
-        }
-        Nonterminal::NtImplItem(ref item) => {
+        Nonterminal::NtTraitItem(ref item) | Nonterminal::NtImplItem(ref item) => {
             prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span)
         }
         Nonterminal::NtIdent(ident, is_raw) => {
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 3cd4988ce0b..e4dff07e92c 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -1381,7 +1381,7 @@ impl<'a> Parser<'a> {
                 args
             }
         };
-        let output = self.parse_ret_ty(true)?;
+        let output = self.parse_ret_ty(true, true)?;
 
         Ok(P(FnDecl {
             inputs: inputs_captures,
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 34ef12e818c..0840a1551db 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -6,7 +6,7 @@ use crate::maybe_whole;
 use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey};
 use rustc_error_codes::*;
 use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item};
-use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind};
+use syntax::ast::{AssocItem, AssocItemKind, ItemKind, UseTree, UseTreeKind};
 use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit};
 use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind};
 use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, Variant, VariantData, StructField};
@@ -648,7 +648,7 @@ impl<'a> Parser<'a> {
         Ok((Ident::invalid(), item_kind, Some(attrs)))
     }
 
-    fn parse_impl_body(&mut self) -> PResult<'a, (Vec<ImplItem>, Vec<Attribute>)> {
+    fn parse_impl_body(&mut self) -> PResult<'a, (Vec<AssocItem>, Vec<Attribute>)> {
         self.expect(&token::OpenDelim(token::Brace))?;
         let attrs = self.parse_inner_attributes()?;
 
@@ -669,60 +669,6 @@ impl<'a> Parser<'a> {
         Ok((impl_items, attrs))
     }
 
-    /// Parses an impl item.
-    pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> {
-        maybe_whole!(self, NtImplItem, |x| x);
-        let attrs = self.parse_outer_attributes()?;
-        let mut unclosed_delims = vec![];
-        let (mut item, tokens) = self.collect_tokens(|this| {
-            let item = this.parse_impl_item_(at_end, attrs);
-            unclosed_delims.append(&mut this.unclosed_delims);
-            item
-        })?;
-        self.unclosed_delims.append(&mut unclosed_delims);
-
-        // See `parse_item` for why this clause is here.
-        if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
-            item.tokens = Some(tokens);
-        }
-        Ok(item)
-    }
-
-    fn parse_impl_item_(
-        &mut self,
-        at_end: &mut bool,
-        mut attrs: Vec<Attribute>,
-    ) -> PResult<'a, ImplItem> {
-        let lo = self.token.span;
-        let vis = self.parse_visibility(FollowedByType::No)?;
-        let defaultness = self.parse_defaultness();
-        let (name, kind, generics) = if self.eat_keyword(kw::Type) {
-            let (name, ty, generics) = self.parse_type_alias()?;
-            (name, ast::ImplItemKind::TyAlias(ty), generics)
-        } else if self.is_const_item() {
-            self.parse_impl_const()?
-        } else if let Some(mac) = self.parse_assoc_macro_invoc("impl", Some(&vis), at_end)? {
-            // FIXME: code copied from `parse_macro_use_or_failure` -- use abstraction!
-            (Ident::invalid(), ast::ImplItemKind::Macro(mac), Generics::default())
-        } else {
-            let (name, inner_attrs, generics, kind) = self.parse_impl_method(at_end)?;
-            attrs.extend(inner_attrs);
-            (name, kind, generics)
-        };
-
-        Ok(ImplItem {
-            id: DUMMY_NODE_ID,
-            span: lo.to(self.prev_span),
-            ident: name,
-            vis,
-            defaultness,
-            attrs,
-            generics,
-            kind,
-            tokens: None,
-        })
-    }
-
     /// Parses defaultness (i.e., `default` or nothing).
     fn parse_defaultness(&mut self) -> Defaultness {
         // `pub` is included for better error messages
@@ -745,26 +691,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Returns `true` if we are looking at `const ID`
-    /// (returns `false` for things like `const fn`, etc.).
-    fn is_const_item(&self) -> bool {
-        self.token.is_keyword(kw::Const) &&
-            !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
-    }
-
-    /// This parses the grammar:
-    ///     ImplItemConst = "const" Ident ":" Ty "=" Expr ";"
-    fn parse_impl_const(&mut self) -> PResult<'a, (Ident, ImplItemKind, Generics)> {
-        self.expect_keyword(kw::Const)?;
-        let name = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let typ = self.parse_ty()?;
-        self.expect(&token::Eq)?;
-        let expr = self.parse_expr()?;
-        self.expect_semi()?;
-        Ok((name, ImplItemKind::Const(typ, expr), Generics::default()))
-    }
-
     /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
         // Parse optional `auto` prefix.
@@ -857,13 +783,30 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parses the items in a trait declaration.
-    pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> {
+    pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, AssocItem> {
+        maybe_whole!(self, NtImplItem, |x| x);
+        self.parse_assoc_item(at_end, |_| true)
+    }
+
+    pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, AssocItem> {
         maybe_whole!(self, NtTraitItem, |x| x);
+        // This is somewhat dubious; We don't want to allow
+        // param names to be left off if there is a definition...
+        //
+        // We don't allow param names to be left off in edition 2018.
+        self.parse_assoc_item(at_end, |t| t.span.rust_2018())
+    }
+
+    /// Parses associated items.
+    fn parse_assoc_item(
+        &mut self,
+        at_end: &mut bool,
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, AssocItem> {
         let attrs = self.parse_outer_attributes()?;
         let mut unclosed_delims = vec![];
         let (mut item, tokens) = self.collect_tokens(|this| {
-            let item = this.parse_trait_item_(at_end, attrs);
+            let item = this.parse_assoc_item_(at_end, attrs, is_name_required);
             unclosed_delims.append(&mut this.unclosed_delims);
             item
         })?;
@@ -875,54 +818,66 @@ impl<'a> Parser<'a> {
         Ok(item)
     }
 
-    fn parse_trait_item_(
+    fn parse_assoc_item_(
         &mut self,
         at_end: &mut bool,
         mut attrs: Vec<Attribute>,
-    ) -> PResult<'a, TraitItem> {
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, AssocItem> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
+        let defaultness = self.parse_defaultness();
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
-            self.parse_trait_item_assoc_ty()?
+            self.parse_assoc_ty()?
         } else if self.is_const_item() {
-            self.parse_trait_item_const()?
-        } else if let Some(mac) = self.parse_assoc_macro_invoc("trait", None, &mut false)? {
-            // trait item macro.
-            (Ident::invalid(), TraitItemKind::Macro(mac), Generics::default())
+            self.parse_assoc_const()?
+        } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
+            (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
         } else {
-            self.parse_trait_item_method(at_end, &mut attrs)?
+            self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
         };
 
-        Ok(TraitItem {
+        Ok(AssocItem {
             id: DUMMY_NODE_ID,
+            span: lo.to(self.prev_span),
             ident: name,
             attrs,
             vis,
+            defaultness,
             generics,
             kind,
-            span: lo.to(self.prev_span),
             tokens: None,
         })
     }
 
-    fn parse_trait_item_const(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+    /// Returns `true` if we are looking at `const ID`
+    /// (returns `false` for things like `const fn`, etc.).
+    fn is_const_item(&self) -> bool {
+        self.token.is_keyword(kw::Const) &&
+            !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
+    }
+
+    /// This parses the grammar:
+    ///
+    ///     AssocConst = "const" Ident ":" Ty "=" Expr ";"
+    fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         self.expect_keyword(kw::Const)?;
         let ident = self.parse_ident()?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
-        let default = if self.eat(&token::Eq) {
+        let expr = if self.eat(&token::Eq) {
             Some(self.parse_expr()?)
         } else {
             None
         };
         self.expect_semi()?;
-        Ok((ident, TraitItemKind::Const(ty, default), Generics::default()))
+        Ok((ident, AssocItemKind::Const(ty, expr), Generics::default()))
     }
 
     /// Parses the following grammar:
     ///
-    ///     TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
-    fn parse_trait_item_assoc_ty(&mut self) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
+    ///     AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
+    fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
 
@@ -941,7 +896,7 @@ impl<'a> Parser<'a> {
         };
         self.expect_semi()?;
 
-        Ok((ident, TraitItemKind::Type(bounds, default), generics))
+        Ok((ident, AssocItemKind::TyAlias(bounds, default), generics))
     }
 
     /// Parses a `UseTree`.
@@ -1772,8 +1727,6 @@ impl<'a> Parser<'a> {
 pub(super) struct ParamCfg {
     /// Is `self` is allowed as the first parameter?
     pub is_self_allowed: bool,
-    /// Is `...` allowed as the tail of the parameter list?
-    pub allow_c_variadic: bool,
     /// `is_name_required` decides if, per-parameter,
     /// the parameter must have a pattern or just a type.
     pub is_name_required: fn(&token::Token) -> bool,
@@ -1789,16 +1742,8 @@ impl<'a> Parser<'a> {
         attrs: Vec<Attribute>,
         header: FnHeader,
     ) -> PResult<'a, Option<P<Item>>> {
-        let is_c_abi = match header.ext {
-            ast::Extern::None => false,
-            ast::Extern::Implicit => true,
-            ast::Extern::Explicit(abi) => abi.symbol_unescaped == sym::C,
-        };
         let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
             is_self_allowed: false,
-            // FIXME: Parsing should not depend on ABI or unsafety and
-            // the variadic parameter should always be parsed.
-            allow_c_variadic: is_c_abi && header.unsafety == Unsafety::Unsafe,
             is_name_required: |_| true,
         })?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1817,7 +1762,6 @@ impl<'a> Parser<'a> {
         self.expect_keyword(kw::Fn)?;
         let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
             is_self_allowed: false,
-            allow_c_variadic: true,
             is_name_required: |_| true,
         })?;
         let span = lo.to(self.token.span);
@@ -1833,48 +1777,39 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Parses a method or a macro invocation in a trait impl.
-    fn parse_impl_method(
-        &mut self,
-        at_end: &mut bool,
-    ) -> PResult<'a, (Ident, Vec<Attribute>, Generics, ImplItemKind)> {
-        let (ident, sig, generics) = self.parse_method_sig(|_| true)?;
-        *at_end = true;
-        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-        Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(sig, body)))
-    }
-
-    fn parse_trait_item_method(
+    fn parse_assoc_fn(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
-    ) -> PResult<'a, (Ident, TraitItemKind, Generics)> {
-        // This is somewhat dubious; We don't want to allow
-        // argument names to be left off if there is a definition...
-        //
-        // We don't allow argument names to be left off in edition 2018.
-        let (ident, sig, generics) = self.parse_method_sig(|t| t.span.rust_2018())?;
-        let body = self.parse_trait_method_body(at_end, attrs)?;
-        Ok((ident, TraitItemKind::Method(sig, body), generics))
+        is_name_required: fn(&token::Token) -> bool,
+    ) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
+        let header = self.parse_fn_front_matter()?;
+        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
+            is_self_allowed: true,
+            is_name_required,
+        })?;
+        let sig = FnSig { header, decl };
+        let body = self.parse_assoc_fn_body(at_end, attrs)?;
+        Ok((ident, AssocItemKind::Fn(sig, body), generics))
     }
 
-    /// Parse the "body" of a method in a trait item definition.
+    /// Parse the "body" of a method in an associated item definition.
     /// This can either be `;` when there's no body,
     /// or e.g. a block when the method is a provided one.
-    fn parse_trait_method_body(
+    fn parse_assoc_fn_body(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
     ) -> PResult<'a, Option<P<Block>>> {
         Ok(match self.token.kind {
             token::Semi => {
-                debug!("parse_trait_method_body(): parsing required method");
+                debug!("parse_assoc_fn_body(): parsing required method");
                 self.bump();
                 *at_end = true;
                 None
             }
             token::OpenDelim(token::Brace) => {
-                debug!("parse_trait_method_body(): parsing provided method");
+                debug!("parse_assoc_fn_body(): parsing provided method");
                 *at_end = true;
                 let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
                 attrs.extend(inner_attrs.iter().cloned());
@@ -1895,21 +1830,6 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Parse the "signature", including the identifier, parameters, and generics
-    /// of a method. The body is not parsed as that differs between `trait`s and `impl`s.
-    fn parse_method_sig(
-        &mut self,
-        is_name_required: fn(&token::Token) -> bool,
-    ) -> PResult<'a, (Ident, FnSig, Generics)> {
-        let header = self.parse_fn_front_matter()?;
-        let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
-            is_self_allowed: true,
-            allow_c_variadic: false,
-            is_name_required,
-        })?;
-        Ok((ident, FnSig { header, decl }, generics))
-    }
-
     /// Parses all the "front matter" for a `fn` declaration, up to
     /// and including the `fn` keyword:
     ///
@@ -1959,64 +1879,29 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
             inputs: self.parse_fn_params(cfg)?,
-            output: self.parse_ret_ty(ret_allow_plus)?,
+            output: self.parse_ret_ty(ret_allow_plus, true)?,
         }))
     }
 
     /// Parses the parameter list of a function, including the `(` and `)` delimiters.
     fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
-        let sp = self.token.span;
         let is_trait_item = cfg.is_self_allowed;
-        let mut c_variadic = false;
         // Parse the arguments, starting out with `self` being possibly allowed...
-        let (params, _) = self.parse_paren_comma_seq(|p| {
-            let param = p.parse_param_general(&cfg, is_trait_item);
+        let (mut params, _) = self.parse_paren_comma_seq(|p| {
+            let param = p.parse_param_general(&cfg, is_trait_item).or_else(|mut e| {
+                e.emit();
+                let lo = p.prev_span;
+                // Skip every token until next possible arg or end.
+                p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+                // Create a placeholder argument for proper arg count (issue #34264).
+                Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_span))))
+            });
             // ...now that we've parsed the first argument, `self` is no longer allowed.
             cfg.is_self_allowed = false;
-
-            match param {
-                Ok(param) => Ok(
-                    if let TyKind::CVarArgs = param.ty.kind {
-                        c_variadic = true;
-                        if p.token != token::CloseDelim(token::Paren) {
-                            p.span_err(
-                                p.token.span,
-                                "`...` must be the last argument of a C-variadic function",
-                            );
-                            // FIXME(eddyb) this should probably still push `CVarArgs`.
-                            // Maybe AST validation/HIR lowering should emit the above error?
-                            None
-                        } else {
-                            Some(param)
-                        }
-                    } else {
-                        Some(param)
-                    }
-                ),
-                Err(mut e) => {
-                    e.emit();
-                    let lo = p.prev_span;
-                    // Skip every token until next possible arg or end.
-                    p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
-                    // Create a placeholder argument for proper arg count (issue #34264).
-                    let span = lo.to(p.prev_span);
-                    Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
-                }
-            }
+            param
         })?;
-
-        let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
-
         // Replace duplicated recovered params with `_` pattern to avoid unnecessary errors.
         self.deduplicate_recovered_params_names(&mut params);
-
-        if c_variadic && params.len() <= 1 {
-            self.span_err(
-                sp,
-                "C-variadic function must be declared with at least one named argument",
-            );
-        }
-
         Ok(params)
     }
 
@@ -2061,12 +1946,12 @@ impl<'a> Parser<'a> {
             }
 
             self.eat_incorrect_doc_comment_for_param_type();
-            (pat, self.parse_ty_common(true, true, cfg.allow_c_variadic)?)
+            (pat, self.parse_ty_for_param()?)
         } else {
             debug!("parse_param_general ident_to_pat");
             let parser_snapshot_before_ty = self.clone();
             self.eat_incorrect_doc_comment_for_param_type();
-            let mut ty = self.parse_ty_common(true, true, cfg.allow_c_variadic);
+            let mut ty = self.parse_ty_for_param();
             if ty.is_ok() && self.token != token::Comma &&
                self.token != token::CloseDelim(token::Paren) {
                 // This wasn't actually a type, but a pattern looking like a type,
diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index 42ece96adb9..117b92dc9a5 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -459,16 +459,26 @@ impl<'a> Parser<'a> {
     /// Parse `&pat` / `&mut pat`.
     fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> {
         self.expect_and()?;
+        self.recover_lifetime_in_deref_pat();
         let mutbl = self.parse_mutability();
+        let subpat = self.parse_pat_with_range_pat(false, expected)?;
+        Ok(PatKind::Ref(subpat, mutbl))
+    }
 
+    fn recover_lifetime_in_deref_pat(&mut self) {
         if let token::Lifetime(name) = self.token.kind {
-            let mut err = self.fatal(&format!("unexpected lifetime `{}` in pattern", name));
-            err.span_label(self.token.span, "unexpected lifetime");
-            return Err(err);
-        }
+            self.bump(); // `'a`
 
-        let subpat = self.parse_pat_with_range_pat(false, expected)?;
-        Ok(PatKind::Ref(subpat, mutbl))
+            let span = self.prev_span;
+            self.struct_span_err(span, &format!("unexpected lifetime `{}` in pattern", name))
+                .span_suggestion(
+                    span,
+                    "remove the lifetime",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
     }
 
     /// Parse a tuple or parenthesis pattern.
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 5334fc485e7..aeba6dd2f67 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -182,11 +182,7 @@ impl<'a> Parser<'a> {
                 // `(T, U) -> R`
                 let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
                 let span = ident.span.to(self.prev_span);
-                let output = if self.eat(&token::RArrow) {
-                    Some(self.parse_ty_common(false, false, false)?)
-                } else {
-                    None
-                };
+                let output = self.parse_ret_ty(false, false)?;
                 ParenthesizedArgs { inputs, output, span }.into()
             };
 
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index 84ffef68e9a..6f7ab0542d5 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -10,7 +10,7 @@ use syntax::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam
 use syntax::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef};
 use syntax::ast::{Mutability, AnonConst, Mac};
 use syntax::token::{self, Token};
-use syntax::struct_span_fatal;
+use syntax::struct_span_err;
 use syntax_pos::source_map::Span;
 use syntax_pos::symbol::kw;
 
@@ -30,6 +30,13 @@ impl<'a> Parser<'a> {
         self.parse_ty_common(true, true, false)
     }
 
+    /// Parse a type suitable for a function or function pointer parameter.
+    /// The difference from `parse_ty` is that this version allows `...`
+    /// (`CVarArgs`) at the top level of the the type.
+    pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
+        self.parse_ty_common(true, true, true)
+    }
+
     /// Parses a type in restricted contexts where `+` is not permitted.
     ///
     /// Example 1: `&'a TYPE`
@@ -41,16 +48,26 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an optional return type `[ -> TY ]` in a function declaration.
-    pub(super) fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> {
-        if self.eat(&token::RArrow) {
-            Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?))
+    pub(super) fn parse_ret_ty(
+        &mut self,
+        allow_plus: bool,
+        allow_qpath_recovery: bool,
+    ) -> PResult<'a, FunctionRetTy> {
+        Ok(if self.eat(&token::RArrow) {
+            // FIXME(Centril): Can we unconditionally `allow_plus`?
+            FunctionRetTy::Ty(self.parse_ty_common(allow_plus, allow_qpath_recovery, false)?)
         } else {
-            Ok(FunctionRetTy::Default(self.token.span.shrink_to_lo()))
-        }
+            FunctionRetTy::Default(self.token.span.shrink_to_lo())
+        })
     }
 
-    pub(super) fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool,
-                       allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
+    fn parse_ty_common(
+        &mut self,
+        allow_plus: bool,
+        allow_qpath_recovery: bool,
+        // Is `...` (`CVarArgs`) legal in the immediate top level call?
+        allow_c_variadic: bool,
+    ) -> PResult<'a, P<Ty>> {
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
         maybe_whole!(self, NtTy, |x| x);
 
@@ -192,17 +209,21 @@ impl<'a> Parser<'a> {
                     TyKind::Path(None, path)
                 }
             }
-        } else if self.check(&token::DotDotDot) {
+        } else if self.eat(&token::DotDotDot) {
             if allow_c_variadic {
-                self.eat(&token::DotDotDot);
                 TyKind::CVarArgs
             } else {
-                return Err(struct_span_fatal!(
+                // FIXME(Centril): Should we just allow `...` syntactically
+                // anywhere in a type and use semantic restrictions instead?
+                struct_span_err!(
                     self.sess.span_diagnostic,
-                    self.token.span,
+                    lo.to(self.prev_span),
                     E0743,
-                    "only foreign functions are allowed to be C-variadic",
-                ));
+                    "C-variadic type `...` may not be nested inside another type",
+                )
+                .emit();
+
+                TyKind::Err
             }
         } else {
             let msg = format!("expected type, found {}", self.this_token_descr());
@@ -287,7 +308,6 @@ impl<'a> Parser<'a> {
         self.expect_keyword(kw::Fn)?;
         let cfg = ParamCfg {
             is_self_allowed: false,
-            allow_c_variadic: true,
             is_name_required: |_| false,
         };
         let decl = self.parse_fn_decl(cfg, false)?;
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 202b6ae2f94..e90231f984b 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -250,6 +250,26 @@ impl<'a> AstValidator<'a> {
     }
 
     fn check_fn_decl(&self, fn_decl: &FnDecl) {
+        match &*fn_decl.inputs {
+            [Param { ty, span, .. }] => if let TyKind::CVarArgs = ty.kind {
+                self.err_handler()
+                    .span_err(
+                        *span,
+                        "C-variadic function must be declared with at least one named argument",
+                    );
+            },
+            [ps @ .., _] => for Param { ty, span, .. } in ps {
+                if let TyKind::CVarArgs = ty.kind {
+                    self.err_handler()
+                        .span_err(
+                            *span,
+                            "`...` must be the last argument of a C-variadic function",
+                        );
+                }
+            }
+            _ => {}
+        }
+
         fn_decl
             .inputs
             .iter()
@@ -259,18 +279,65 @@ impl<'a> AstValidator<'a> {
                 !arr.contains(&attr.name_or_empty()) && attr::is_builtin_attr(attr)
             })
             .for_each(|attr| if attr.is_doc_comment() {
-                let mut err = self.err_handler().struct_span_err(
+                self.err_handler().struct_span_err(
                     attr.span,
                     "documentation comments cannot be applied to function parameters"
-                );
-                err.span_label(attr.span, "doc comments are not allowed here");
-                err.emit();
-            }
-            else {
+                )
+                .span_label(attr.span, "doc comments are not allowed here")
+                .emit();
+            } else {
                 self.err_handler().span_err(attr.span, "allow, cfg, cfg_attr, deny, \
                 forbid, and warn are the only allowed built-in attributes in function parameters")
             });
     }
+
+    fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
+        if let Defaultness::Default = defaultness {
+            self.err_handler()
+                .struct_span_err(span, "`default` is only allowed on items in `impl` definitions")
+                .emit();
+        }
+    }
+
+    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
+        if body.is_some() {
+            return;
+        }
+
+        self.err_handler()
+            .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx))
+            .span_suggestion(
+                self.session.source_map().end_point(sp),
+                &format!("provide a definition for the {}", ctx),
+                sugg.to_string(),
+                Applicability::HasPlaceholders,
+            )
+            .emit();
+    }
+
+    fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
+        let span = match bounds {
+            [] => return,
+            [b0] => b0.span(),
+            [b0, .., bl] => b0.span().to(bl.span()),
+        };
+        self.err_handler()
+            .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
+            .emit();
+    }
+
+    fn check_c_varadic_type(&self, decl: &FnDecl) {
+        for Param { ty, span, .. } in &decl.inputs {
+            if let TyKind::CVarArgs = ty.kind {
+                self.err_handler()
+                    .struct_span_err(
+                        *span,
+                        "only foreign or `unsafe extern \"C\" functions may be C-variadic",
+                    )
+                    .emit();
+            }
+        }
+    }
 }
 
 enum GenericPosition {
@@ -477,7 +544,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, None);
-                    if let ImplItemKind::Method(ref sig, _) = impl_item.kind {
+                    if let AssocItemKind::Fn(ref sig, _) = impl_item.kind {
                         self.check_trait_fn_not_const(sig.header.constness);
                         self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
                     }
@@ -519,6 +586,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         }
                     }
                 }
+                // Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
+                match sig.header.ext {
+                    Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) |
+                    Extern::Implicit if sig.header.unsafety == Unsafety::Unsafe => {}
+                    _ => self.check_c_varadic_type(&sig.decl),
+                }
             }
             ItemKind::ForeignMod(..) => {
                 self.invalid_visibility(
@@ -554,26 +627,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     }
                 }
                 self.no_questions_in_bounds(bounds, "supertraits", true);
-                for trait_item in trait_items {
-                    if let TraitItemKind::Method(ref sig, ref block) = trait_item.kind {
-                        self.check_fn_decl(&sig.decl);
-                        self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node);
-                        self.check_trait_fn_not_const(sig.header.constness);
-                        if block.is_none() {
-                            Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
-                                if mut_ident {
-                                    self.lint_buffer.buffer_lint(
-                                        lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
-                                        trait_item.id, span,
-                                        "patterns aren't allowed in methods without bodies");
-                                } else {
-                                    struct_span_err!(self.session, span, E0642,
-                                        "patterns aren't allowed in methods without bodies").emit();
-                                }
-                            });
-                        }
-                    }
-                }
             }
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
@@ -639,10 +692,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             GenericArgs::Parenthesized(ref data) => {
                 walk_list!(self, visit_ty, &data.inputs);
-                if let Some(ref type_) = data.output {
+                if let FunctionRetTy::Ty(ty) = &data.output {
                     // `-> Foo` syntax is essentially an associated type binding,
                     // so it is also allowed to contain nested `impl Trait`.
-                    self.with_impl_trait(None, |this| this.visit_ty(type_));
+                    self.with_impl_trait(None, |this| this.visit_ty(ty));
                 }
             }
         }
@@ -737,17 +790,59 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             |this| visit::walk_enum_def(this, enum_definition, generics, item_id))
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ImplItem) {
-        if let ImplItemKind::Method(ref sig, _) = ii.kind {
-            self.check_fn_decl(&sig.decl);
+    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
+        match &ii.kind {
+            AssocItemKind::Const(_, body) => {
+                self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
+            }
+            AssocItemKind::Fn(sig, body) => {
+                self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
+                self.check_fn_decl(&sig.decl);
+            }
+            AssocItemKind::TyAlias(bounds, body) => {
+                self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
+                self.check_impl_assoc_type_no_bounds(bounds);
+            }
+            _ => {}
         }
         visit::walk_impl_item(self, ii);
     }
 
-    fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
         self.invalid_visibility(&ti.vis, None);
+        self.check_defaultness(ti.span, ti.defaultness);
+
+        if let AssocItemKind::Fn(sig, block) = &ti.kind {
+            self.check_fn_decl(&sig.decl);
+            self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
+            self.check_trait_fn_not_const(sig.header.constness);
+            if block.is_none() {
+                Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
+                    if mut_ident {
+                        self.lint_buffer.buffer_lint(
+                            lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
+                            ti.id, span,
+                            "patterns aren't allowed in methods without bodies"
+                        );
+                    } else {
+                        struct_span_err!(
+                            self.session, span, E0642,
+                            "patterns aren't allowed in methods without bodies"
+                        ).emit();
+                    }
+                });
+            }
+        }
+
         visit::walk_trait_item(self, ti);
     }
+
+    fn visit_assoc_item(&mut self, item: &'a AssocItem) {
+        if let AssocItemKind::Fn(sig, _) = &item.kind {
+            self.check_c_varadic_type(&sig.decl);
+        }
+        visit::walk_assoc_item(self, item);
+    }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {
diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs
index 63c6e60de79..725a742382e 100644
--- a/src/librustc_passes/check_const.rs
+++ b/src/librustc_passes/check_const.rs
@@ -13,11 +13,11 @@ use rustc::hir::map::Map;
 use rustc::hir;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
-use rustc_feature::Features;
+use rustc::session::config::nightly_options;
 use syntax::ast::Mutability;
 use syntax::feature_gate::feature_err;
 use syntax::span_err;
-use syntax_pos::{sym, Span};
+use syntax_pos::{sym, Span, Symbol};
 use rustc_error_codes::*;
 
 use std::fmt;
@@ -37,18 +37,31 @@ impl NonConstExpr {
         }
     }
 
-    /// Returns `true` if all feature gates required to enable this expression are turned on, or
-    /// `None` if there is no feature gate corresponding to this expression.
-    fn is_feature_gate_enabled(self, features: &Features) -> Option<bool> {
+    fn required_feature_gates(self) -> Option<&'static [Symbol]> {
         use hir::MatchSource::*;
-        match self {
+        use hir::LoopSource::*;
+
+        let gates: &[_] = match self {
             | Self::Match(Normal)
             | Self::Match(IfDesugar { .. })
             | Self::Match(IfLetDesugar { .. })
-            => Some(features.const_if_match),
+            => &[sym::const_if_match],
 
-            _ => None,
-        }
+            | Self::Loop(Loop)
+            => &[sym::const_loop],
+
+            | Self::Loop(While)
+            | Self::Loop(WhileLet)
+            | Self::Match(WhileDesugar)
+            | Self::Match(WhileLetDesugar)
+            => &[sym::const_loop, sym::const_if_match],
+
+            // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
+            // so they are not yet allowed with `#![feature(const_loop)]`.
+            _ => return None,
+        };
+
+        Some(gates)
     }
 }
 
@@ -120,11 +133,15 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
     /// Emits an error when an unsupported expression is found in a const context.
     fn const_check_violated(&self, expr: NonConstExpr, span: Span) {
-        match expr.is_feature_gate_enabled(self.tcx.features()) {
+        let features = self.tcx.features();
+        let required_gates = expr.required_feature_gates();
+        match required_gates {
             // Don't emit an error if the user has enabled the requisite feature gates.
-            Some(true) => return,
+            Some(gates) if gates.iter().all(|&g| features.enabled(g)) => return,
 
-            // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible.
+            // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
+            // corresponding feature gate. This encourages nightly users to use feature gates when
+            // possible.
             None if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you => {
                 self.tcx.sess.span_warn(span, "skipping const checks");
                 return;
@@ -135,15 +152,47 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
         let const_kind = self.const_kind
             .expect("`const_check_violated` may only be called inside a const context");
-
         let msg = format!("`{}` is not allowed in a `{}`", expr.name(), const_kind);
-        match expr {
-            | NonConstExpr::Match(hir::MatchSource::Normal)
-            | NonConstExpr::Match(hir::MatchSource::IfDesugar { .. })
-            | NonConstExpr::Match(hir::MatchSource::IfLetDesugar { .. })
-            => feature_err(&self.tcx.sess.parse_sess, sym::const_if_match, span, &msg).emit(),
 
-            _ => span_err!(self.tcx.sess, span, E0744, "{}", msg),
+        let required_gates = required_gates.unwrap_or(&[]);
+        let missing_gates: Vec<_> = required_gates
+            .iter()
+            .copied()
+            .filter(|&g| !features.enabled(g))
+            .collect();
+
+        match missing_gates.as_slice() {
+            &[] => span_err!(self.tcx.sess, span, E0744, "{}", msg),
+
+            // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`,
+            // explain why their `while` loop is being rejected.
+            &[gate @ sym::const_if_match] if required_gates.contains(&sym::const_loop) => {
+                feature_err(&self.tcx.sess.parse_sess, gate, span, &msg)
+                    .note("`#![feature(const_loop)]` alone is not sufficient, \
+                           since this loop expression contains an implicit conditional")
+                    .emit();
+            }
+
+            &[missing_primary, ref missing_secondary @ ..] => {
+                let mut err = feature_err(&self.tcx.sess.parse_sess, missing_primary, span, &msg);
+
+                // If multiple feature gates would be required to enable this expression, include
+                // them as help messages. Don't emit a separate error for each missing feature gate.
+                //
+                // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
+                // is a pretty narrow case, however.
+                if nightly_options::is_nightly_build() {
+                    for gate in missing_secondary {
+                        let note = format!(
+                            "add `#![feature({})]` to the crate attributes to enable",
+                            gate,
+                        );
+                        err.help(&note);
+                    }
+                }
+
+                err.emit();
+            }
         }
     }
 
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index a5924efefc2..66ceb4212c8 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -314,12 +314,12 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_fn(self, fk, fd, s)
     }
 
-    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'v ast::AssocItem) {
         self.record("TraitItem", Id::None, ti);
         ast_visit::walk_trait_item(self, ti)
     }
 
-    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'v ast::AssocItem) {
         self.record("ImplItem", Id::None, ii);
         ast_visit::walk_impl_item(self, ii)
     }
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 81f06a14d95..f01867f32c6 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -8,6 +8,7 @@
 
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
+#![feature(slice_patterns)]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index e2578d67e73..e94e0dc695c 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -30,7 +30,7 @@ use errors::Applicability;
 use syntax::ast::{Name, Ident};
 use syntax::attr;
 use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
-use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind};
+use syntax::ast::{MetaItemKind, StmtKind, AssocItem, AssocItemKind};
 use syntax::token::{self, Token};
 use syntax::span_err;
 use syntax::source_map::{respan, Spanned};
@@ -1164,10 +1164,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         self.parent_scope.legacy = orig_current_legacy_scope;
     }
 
-    fn visit_trait_item(&mut self, item: &'b TraitItem) {
+    fn visit_trait_item(&mut self, item: &'b AssocItem) {
         let parent = self.parent_scope.module;
 
-        if let TraitItemKind::Macro(_) = item.kind {
+        if let AssocItemKind::Macro(_) = item.kind {
             self.visit_invoc(item.id);
             return
         }
@@ -1175,15 +1175,15 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         // Add the item to the trait info.
         let item_def_id = self.r.definitions.local_def_id(item.id);
         let (res, ns) = match item.kind {
-            TraitItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
-            TraitItemKind::Method(ref sig, _) => {
+            AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
+            AssocItemKind::Fn(ref sig, _) => {
                 if sig.decl.has_self() {
                     self.r.has_self.insert(item_def_id);
                 }
                 (Res::Def(DefKind::Method, item_def_id), ValueNS)
             }
-            TraitItemKind::Type(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS),
-            TraitItemKind::Macro(_) => bug!(),  // handled above
+            AssocItemKind::TyAlias(..) => (Res::Def(DefKind::AssocTy, item_def_id), TypeNS),
+            AssocItemKind::Macro(_) => bug!(),  // handled above
         };
 
         let vis = ty::Visibility::Public;
@@ -1193,8 +1193,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         visit::walk_trait_item(self, item);
     }
 
-    fn visit_impl_item(&mut self, item: &'b ast::ImplItem) {
-        if let ast::ImplItemKind::Macro(..) = item.kind {
+    fn visit_impl_item(&mut self, item: &'b ast::AssocItem) {
+        if let ast::AssocItemKind::Macro(..) = item.kind {
             self.visit_invoc(item.id);
         } else {
             self.resolve_visibility(&item.vis);
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index dd6b1d2119e..9bae339f80e 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -50,7 +50,7 @@ impl<'a> DefCollector<'a> {
         header: &FnHeader,
         generics: &'a Generics,
         decl: &'a FnDecl,
-        body: &'a Block,
+        body: Option<&'a Block>,
     ) {
         let (closure_id, return_impl_trait_id) = match header.asyncness.node {
             IsAsync::Async {
@@ -74,7 +74,9 @@ impl<'a> DefCollector<'a> {
                 closure_id, DefPathData::ClosureExpr, span,
             );
             this.with_parent(closure_def, |this| {
-                visit::walk_block(this, body);
+                if let Some(body) = body {
+                    visit::walk_block(this, body);
+                }
             })
         })
     }
@@ -123,7 +125,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                     &sig.header,
                     generics,
                     &sig.decl,
-                    body,
+                    Some(body),
                 )
             }
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
@@ -210,23 +212,20 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         visit::walk_generic_param(self, param);
     }
 
-    fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
         let def_data = match ti.kind {
-            TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
-                DefPathData::ValueNs(ti.ident.name),
-            TraitItemKind::Type(..) => {
-                DefPathData::TypeNs(ti.ident.name)
-            },
-            TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
+            AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name),
+            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ti.ident.name),
+            AssocItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
         };
 
         let def = self.create_def(ti.id, def_data, ti.span);
         self.with_parent(def, |this| visit::walk_trait_item(this, ti));
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
         let def_data = match ii.kind {
-            ImplItemKind::Method(FnSig {
+            AssocItemKind::Fn(FnSig {
                 ref header,
                 ref decl,
             }, ref body) if header.asyncness.node.is_async() => {
@@ -237,13 +236,13 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                     header,
                     &ii.generics,
                     decl,
-                    body,
+                    body.as_deref(),
                 )
             }
-            ImplItemKind::Method(..) |
-            ImplItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name),
-            ImplItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name),
-            ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
+            AssocItemKind::Fn(..) |
+            AssocItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name),
+            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name),
+            AssocItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
         };
 
         let def = self.create_def(ii.id, def_data, ii.span);
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 4f95d6fe70f..4321f62e03b 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -806,7 +806,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                 this.with_generic_param_rib(&trait_item.generics, AssocItemRibKind,
                                     |this| {
                                         match trait_item.kind {
-                                            TraitItemKind::Const(ref ty, ref default) => {
+                                            AssocItemKind::Const(ref ty, ref default) => {
                                                 this.visit_ty(ty);
 
                                                 // Only impose the restrictions of
@@ -818,13 +818,13 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                                     });
                                                 }
                                             }
-                                            TraitItemKind::Method(_, _) => {
+                                            AssocItemKind::Fn(_, _) => {
                                                 visit::walk_trait_item(this, trait_item)
                                             }
-                                            TraitItemKind::Type(..) => {
+                                            AssocItemKind::TyAlias(..) => {
                                                 visit::walk_trait_item(this, trait_item)
                                             }
-                                            TraitItemKind::Macro(_) => {
+                                            AssocItemKind::Macro(_) => {
                                                 panic!("unexpanded macro in resolve!")
                                             }
                                         };
@@ -989,13 +989,13 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
     /// When evaluating a `trait` use its associated types' idents for suggestionsa in E0412.
     fn with_trait_items<T>(
         &mut self,
-        trait_items: &Vec<TraitItem>,
+        trait_items: &Vec<AssocItem>,
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         let trait_assoc_types = replace(
             &mut self.diagnostic_metadata.current_trait_assoc_types,
             trait_items.iter().filter_map(|item| match &item.kind {
-                TraitItemKind::Type(bounds, _) if bounds.len() == 0 => Some(item.ident),
+                AssocItemKind::TyAlias(bounds, _) if bounds.len() == 0 => Some(item.ident),
                 _ => None,
             }).collect(),
         );
@@ -1063,7 +1063,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                               opt_trait_reference: &Option<TraitRef>,
                               self_type: &Ty,
                               item_id: NodeId,
-                              impl_items: &[ImplItem]) {
+                              impl_items: &[AssocItem]) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
         self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
@@ -1092,9 +1092,9 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                                                 |this| {
                                         use crate::ResolutionError::*;
                                         match impl_item.kind {
-                                            ImplItemKind::Const(..) => {
+                                            AssocItemKind::Const(..) => {
                                                 debug!(
-                                                    "resolve_implementation ImplItemKind::Const",
+                                                    "resolve_implementation AssocItemKind::Const",
                                                 );
                                                 // If this is a trait impl, ensure the const
                                                 // exists in trait
@@ -1109,7 +1109,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
                                                     visit::walk_impl_item(this, impl_item)
                                                 });
                                             }
-                                            ImplItemKind::Method(..) => {
+                                            AssocItemKind::Fn(..) => {
                                                 // If this is a trait impl, ensure the method
                                                 // exists in trait
                                                 this.check_trait_item(impl_item.ident,
@@ -1119,7 +1119,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
 
                                                 visit::walk_impl_item(this, impl_item);
                                             }
-                                            ImplItemKind::TyAlias(ref ty) => {
+                                            AssocItemKind::TyAlias(_, Some(ref ty)) => {
                                                 // If this is a trait impl, ensure the type
                                                 // exists in trait
                                                 this.check_trait_item(impl_item.ident,
@@ -1129,7 +1129,8 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
 
                                                 this.visit_ty(ty);
                                             }
-                                            ImplItemKind::Macro(_) =>
+                                            AssocItemKind::TyAlias(_, None) => {}
+                                            AssocItemKind::Macro(_) =>
                                                 panic!("unexpanded macro in resolve!"),
                                         }
                                     });
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 396d9484339..df6ad51d104 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -676,7 +676,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         generics: &'l ast::Generics,
         trait_ref: &'l Option<ast::TraitRef>,
         typ: &'l ast::Ty,
-        impl_items: &'l [ast::ImplItem],
+        impl_items: &'l [ast::AssocItem],
     ) {
         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
             if !self.span.filter_generated(item.span) {
@@ -707,7 +707,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         item: &'l ast::Item,
         generics: &'l ast::Generics,
         trait_refs: &'l ast::GenericBounds,
-        methods: &'l [ast::TraitItem],
+        methods: &'l [ast::AssocItem],
     ) {
         let name = item.ident.to_string();
         let qualname = format!("::{}",
@@ -811,9 +811,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 match **generic_args {
                     ast::GenericArgs::AngleBracketed(ref data) => {
                         for arg in &data.args {
-                            match arg {
-                                ast::GenericArg::Type(ty) => self.visit_ty(ty),
-                                _ => {}
+                            if let ast::GenericArg::Type(ty) = arg {
+                                self.visit_ty(ty);
                             }
                         }
                     }
@@ -821,8 +820,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                         for t in &data.inputs {
                             self.visit_ty(t);
                         }
-                        if let Some(ref t) = data.output {
-                            self.visit_ty(t);
+                        if let ast::FunctionRetTy::Ty(ty) = &data.output {
+                            self.visit_ty(ty);
                         }
                     }
                 }
@@ -1030,11 +1029,11 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         // }
     }
 
-    fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
+    fn process_trait_item(&mut self, trait_item: &'l ast::AssocItem, trait_id: DefId) {
         self.process_macro_use(trait_item.span);
         let vis_span = trait_item.span.shrink_to_lo();
         match trait_item.kind {
-            ast::TraitItemKind::Const(ref ty, ref expr) => {
+            ast::AssocItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     trait_item.id,
                     trait_item.ident,
@@ -1045,7 +1044,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     &trait_item.attrs,
                 );
             }
-            ast::TraitItemKind::Method(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(ref sig, ref body) => {
                 self.process_method(
                     sig,
                     body.as_ref().map(|x| &**x),
@@ -1056,7 +1055,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     trait_item.span,
                 );
             }
-            ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
+            ast::AssocItemKind::TyAlias(ref bounds, ref default_ty) => {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname = format!("::{}",
@@ -1098,28 +1097,28 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     self.visit_ty(default_ty)
                 }
             }
-            ast::TraitItemKind::Macro(_) => {}
+            ast::AssocItemKind::Macro(_) => {}
         }
     }
 
-    fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
+    fn process_impl_item(&mut self, impl_item: &'l ast::AssocItem, impl_id: DefId) {
         self.process_macro_use(impl_item.span);
         match impl_item.kind {
-            ast::ImplItemKind::Const(ref ty, ref expr) => {
+            ast::AssocItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     impl_item.id,
                     impl_item.ident,
                     &ty,
-                    Some(expr),
+                    expr.as_deref(),
                     impl_id,
                     impl_item.vis.clone(),
                     &impl_item.attrs,
                 );
             }
-            ast::ImplItemKind::Method(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(ref sig, ref body) => {
                 self.process_method(
                     sig,
-                    Some(body),
+                    body.as_deref(),
                     impl_item.id,
                     impl_item.ident,
                     &impl_item.generics,
@@ -1127,13 +1126,14 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     impl_item.span,
                 );
             }
-            ast::ImplItemKind::TyAlias(ref ty) => {
+            ast::AssocItemKind::TyAlias(_, None) => {}
+            ast::AssocItemKind::TyAlias(_, Some(ref ty)) => {
                 // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
                 self.visit_ty(ty)
             }
-            ast::ImplItemKind::Macro(_) => {}
+            ast::AssocItemKind::Macro(_) => {}
         }
     }
 
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 7f3bab8f232..55e647729e9 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -1,8 +1,8 @@
-// ignore-tidy-filelength
-
 //! Contains infrastructure for configuring the compiler, including parsing
 //! command-line options.
 
+pub use crate::options::*;
+
 use crate::lint;
 use crate::utils::NativeLibraryKind;
 use crate::{early_error, early_warn, Session};
@@ -11,7 +11,6 @@ use crate::search_paths::SearchPath;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::impl_stable_hash_via_hash;
 
-use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
 use rustc_target::spec::{Target, TargetTriple};
 
 use syntax_pos::source_map::{FileName, FilePathMapping};
@@ -31,8 +30,6 @@ use std::collections::btree_map::{
 };
 use std::fmt;
 use std::str::{self, FromStr};
-use std::hash::Hasher;
-use std::collections::hash_map::DefaultHasher;
 use std::iter::{self, FromIterator};
 use std::path::{Path, PathBuf};
 
@@ -382,131 +379,6 @@ impl ExternEntry {
     }
 }
 
-macro_rules! hash_option {
-    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
-    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
-        if $sub_hashes.insert(stringify!($opt_name),
-                              $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
-            panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
-        }
-    });
-}
-
-macro_rules! top_level_options {
-    (pub struct Options { $(
-        $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
-    )* } ) => (
-        #[derive(Clone)]
-        pub struct Options {
-            $(pub $opt: $t),*
-        }
-
-        impl Options {
-            pub fn dep_tracking_hash(&self) -> u64 {
-                let mut sub_hashes = BTreeMap::new();
-                $({
-                    hash_option!($opt,
-                                 &self.$opt,
-                                 &mut sub_hashes,
-                                 [$dep_tracking_marker $($warn_val,
-                                                         $warn_text,
-                                                         self.error_format)*]);
-                })*
-                let mut hasher = DefaultHasher::new();
-                dep_tracking::stable_hash(sub_hashes,
-                                          &mut hasher,
-                                          self.error_format);
-                hasher.finish()
-            }
-        }
-    );
-}
-
-// The top-level command-line options struct.
-//
-// For each option, one has to specify how it behaves with regard to the
-// dependency tracking system of incremental compilation. This is done via the
-// square-bracketed directive after the field type. The options are:
-//
-// [TRACKED]
-// A change in the given field will cause the compiler to completely clear the
-// incremental compilation cache before proceeding.
-//
-// [UNTRACKED]
-// Incremental compilation is not influenced by this option.
-//
-// If you add a new option to this struct or one of the sub-structs like
-// `CodegenOptions`, think about how it influences incremental compilation. If in
-// doubt, specify [TRACKED], which is always "correct" but might lead to
-// unnecessary re-compilation.
-top_level_options!(
-    pub struct Options {
-        // The crate config requested for the session, which may be combined
-        // with additional crate configurations during the compile process.
-        crate_types: Vec<CrateType> [TRACKED],
-        optimize: OptLevel [TRACKED],
-        // Include the `debug_assertions` flag in dependency tracking, since it
-        // can influence whether overflow checks are done or not.
-        debug_assertions: bool [TRACKED],
-        debuginfo: DebugInfo [TRACKED],
-        lint_opts: Vec<(String, lint::Level)> [TRACKED],
-        lint_cap: Option<lint::Level> [TRACKED],
-        describe_lints: bool [UNTRACKED],
-        output_types: OutputTypes [TRACKED],
-        search_paths: Vec<SearchPath> [UNTRACKED],
-        libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
-        maybe_sysroot: Option<PathBuf> [UNTRACKED],
-
-        target_triple: TargetTriple [TRACKED],
-
-        test: bool [TRACKED],
-        error_format: ErrorOutputType [UNTRACKED],
-
-        // If `Some`, enable incremental compilation, using the given
-        // directory to store intermediate results.
-        incremental: Option<PathBuf> [UNTRACKED],
-
-        debugging_opts: DebuggingOptions [TRACKED],
-        prints: Vec<PrintRequest> [UNTRACKED],
-        // Determines which borrow checker(s) to run. This is the parsed, sanitized
-        // version of `debugging_opts.borrowck`, which is just a plain string.
-        borrowck_mode: BorrowckMode [UNTRACKED],
-        cg: CodegenOptions [TRACKED],
-        externs: Externs [UNTRACKED],
-        crate_name: Option<String> [TRACKED],
-        // An optional name to use as the crate for std during std injection,
-        // written `extern crate name as std`. Defaults to `std`. Used by
-        // out-of-tree drivers.
-        alt_std_name: Option<String> [TRACKED],
-        // Indicates how the compiler should treat unstable features.
-        unstable_features: UnstableFeatures [TRACKED],
-
-        // Indicates whether this run of the compiler is actually rustdoc. This
-        // is currently just a hack and will be removed eventually, so please
-        // try to not rely on this too much.
-        actually_rustdoc: bool [TRACKED],
-
-        // Specifications of codegen units / ThinLTO which are forced as a
-        // result of parsing command line options. These are not necessarily
-        // what rustc was invoked with, but massaged a bit to agree with
-        // commands like `--emit llvm-ir` which they're often incompatible with
-        // if we otherwise use the defaults of rustc.
-        cli_forced_codegen_units: Option<usize> [UNTRACKED],
-        cli_forced_thinlto_off: bool [UNTRACKED],
-
-        // Remap source path prefixes in all output (messages, object files, debug, etc.).
-        remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
-
-        edition: Edition [TRACKED],
-
-        // `true` if we're emitting JSON blobs about each artifact produced
-        // by the compiler.
-        json_artifact_notifications: bool [TRACKED],
-
-        pretty: Option<PpMode> [UNTRACKED],
-    }
-);
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PrintRequest {
     FileNames,
@@ -767,811 +639,6 @@ impl Passes {
     }
 }
 
-/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
-/// macro is to define an interface that can be programmatically used by the option parser
-/// to initialize the struct without hardcoding field names all over the place.
-///
-/// The goal is to invoke this macro once with the correct fields, and then this macro generates all
-/// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
-/// generated code to parse an option into its respective field in the struct. There are a few
-/// hand-written parsers for parsing specific types of values in this module.
-macro_rules! options {
-    ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
-     $buildfn:ident, $prefix:expr, $outputname:expr,
-     $stat:ident, $mod_desc:ident, $mod_set:ident,
-     $($opt:ident : $t:ty = (
-        $init:expr,
-        $parse:ident,
-        [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
-        $desc:expr)
-     ),* ,) =>
-(
-    #[derive(Clone)]
-    pub struct $struct_name { $(pub $opt: $t),* }
-
-    pub fn $defaultfn() -> $struct_name {
-        $struct_name { $($opt: $init),* }
-    }
-
-    pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
-    {
-        let mut op = $defaultfn();
-        for option in matches.opt_strs($prefix) {
-            let mut iter = option.splitn(2, '=');
-            let key = iter.next().unwrap();
-            let value = iter.next();
-            let option_to_lookup = key.replace("-", "_");
-            let mut found = false;
-            for &(candidate, setter, opt_type_desc, _) in $stat {
-                if option_to_lookup != candidate { continue }
-                if !setter(&mut op, value) {
-                    match (value, opt_type_desc) {
-                        (Some(..), None) => {
-                            early_error(error_format, &format!("{} option `{}` takes no \
-                                                                value", $outputname, key))
-                        }
-                        (None, Some(type_desc)) => {
-                            early_error(error_format, &format!("{0} option `{1}` requires \
-                                                                {2} ({3} {1}=<value>)",
-                                                               $outputname, key,
-                                                               type_desc, $prefix))
-                        }
-                        (Some(value), Some(type_desc)) => {
-                            early_error(error_format, &format!("incorrect value `{}` for {} \
-                                                                option `{}` - {} was expected",
-                                                               value, $outputname,
-                                                               key, type_desc))
-                        }
-                        (None, None) => panic!()
-                    }
-                }
-                found = true;
-                break;
-            }
-            if !found {
-                early_error(error_format, &format!("unknown {} option: `{}`",
-                                                   $outputname, key));
-            }
-        }
-        return op;
-    }
-
-    impl dep_tracking::DepTrackingHash for $struct_name {
-        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
-            let mut sub_hashes = BTreeMap::new();
-            $({
-                hash_option!($opt,
-                             &self.$opt,
-                             &mut sub_hashes,
-                             [$dep_tracking_marker $($dep_warn_val,
-                                                     $dep_warn_text,
-                                                     error_format)*]);
-            })*
-            dep_tracking::stable_hash(sub_hashes, hasher, error_format);
-        }
-    }
-
-    pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
-    pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
-        &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
-
-    #[allow(non_upper_case_globals, dead_code)]
-    mod $mod_desc {
-        pub const parse_bool: Option<&str> = None;
-        pub const parse_opt_bool: Option<&str> =
-            Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
-        pub const parse_string: Option<&str> = Some("a string");
-        pub const parse_string_push: Option<&str> = Some("a string");
-        pub const parse_pathbuf_push: Option<&str> = Some("a path");
-        pub const parse_opt_string: Option<&str> = Some("a string");
-        pub const parse_opt_pathbuf: Option<&str> = Some("a path");
-        pub const parse_list: Option<&str> = Some("a space-separated list of strings");
-        pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
-        pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
-        pub const parse_threads: Option<&str> = Some("a number");
-        pub const parse_uint: Option<&str> = Some("a number");
-        pub const parse_passes: Option<&str> =
-            Some("a space-separated list of passes, or `all`");
-        pub const parse_opt_uint: Option<&str> =
-            Some("a number");
-        pub const parse_panic_strategy: Option<&str> =
-            Some("either `unwind` or `abort`");
-        pub const parse_relro_level: Option<&str> =
-            Some("one of: `full`, `partial`, or `off`");
-        pub const parse_sanitizer: Option<&str> =
-            Some("one of: `address`, `leak`, `memory` or `thread`");
-        pub const parse_sanitizer_list: Option<&str> =
-            Some("comma separated list of sanitizers");
-        pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
-        pub const parse_linker_flavor: Option<&str> =
-            Some(::rustc_target::spec::LinkerFlavor::one_of());
-        pub const parse_optimization_fuel: Option<&str> =
-            Some("crate=integer");
-        pub const parse_unpretty: Option<&str> =
-            Some("`string` or `string=string`");
-        pub const parse_treat_err_as_bug: Option<&str> =
-            Some("either no value or a number bigger than 0");
-        pub const parse_lto: Option<&str> =
-            Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
-                  `fat`, or omitted");
-        pub const parse_linker_plugin_lto: Option<&str> =
-            Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
-                  or the path to the linker plugin");
-        pub const parse_switch_with_opt_path: Option<&str> =
-            Some("an optional path to the profiling data output directory");
-        pub const parse_merge_functions: Option<&str> =
-            Some("one of: `disabled`, `trampolines`, or `aliases`");
-        pub const parse_symbol_mangling_version: Option<&str> =
-            Some("either `legacy` or `v0` (RFC 2603)");
-    }
-
-    #[allow(dead_code)]
-    mod $mod_set {
-        use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
-            SymbolManglingVersion};
-        use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
-        use std::path::PathBuf;
-        use std::str::FromStr;
-
-        $(
-            pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
-                $parse(&mut cg.$opt, v)
-            }
-        )*
-
-        fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
-            match v {
-                Some(..) => false,
-                None => { *slot = true; true }
-            }
-        }
-
-        fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => {
-                    match s {
-                        "n" | "no" | "off" => {
-                            *slot = Some(false);
-                        }
-                        "y" | "yes" | "on" => {
-                            *slot = Some(true);
-                        }
-                        _ => { return false; }
-                    }
-
-                    true
-                },
-                None => { *slot = Some(true); true }
-            }
-        }
-
-        fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = Some(s.to_string()); true },
-                None => false,
-            }
-        }
-
-        fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = Some(PathBuf::from(s)); true },
-                None => false,
-            }
-        }
-
-        fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.to_string(); true },
-                None => false,
-            }
-        }
-
-        fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { slot.push(s.to_string()); true },
-                None => false,
-            }
-        }
-
-        fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { slot.push(PathBuf::from(s)); true },
-                None => false,
-            }
-        }
-
-        fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    slot.extend(s.split_whitespace().map(|s| s.to_string()));
-                    true
-                },
-                None => false,
-            }
-        }
-
-        fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    let v = s.split_whitespace().map(|s| s.to_string()).collect();
-                    *slot = Some(v);
-                    true
-                },
-                None => false,
-            }
-        }
-
-        fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    let v = s.split(',').map(|s| s.to_string()).collect();
-                    *slot = Some(v);
-                    true
-                },
-                None => false,
-            }
-        }
-
-        fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
-            match v.and_then(|s| s.parse().ok()) {
-                Some(0) => { *slot = ::num_cpus::get(); true },
-                Some(i) => { *slot = i; true },
-                None => false
-            }
-        }
-
-        fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
-            match v.and_then(|s| s.parse().ok()) {
-                Some(i) => { *slot = i; true },
-                None => false
-            }
-        }
-
-        fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
-                None => { *slot = None; false }
-            }
-        }
-
-        fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
-            match v {
-                Some("all") => {
-                    *slot = Passes::All;
-                    true
-                }
-                v => {
-                    let mut passes = vec![];
-                    if parse_list(&mut passes, v) {
-                        *slot = Passes::Some(passes);
-                        true
-                    } else {
-                        false
-                    }
-                }
-            }
-        }
-
-        fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
-            match v {
-                Some("unwind") => *slot = Some(PanicStrategy::Unwind),
-                Some("abort") => *slot = Some(PanicStrategy::Abort),
-                _ => return false
-            }
-            true
-        }
-
-        fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => {
-                    match s.parse::<RelroLevel>() {
-                        Ok(level) => *slot = Some(level),
-                        _ => return false
-                    }
-                },
-                _ => return false
-            }
-            true
-        }
-
-        fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
-            if let Some(Ok(s)) =  v.map(str::parse) {
-                *slot = Some(s);
-                true
-            } else {
-                false
-            }
-        }
-
-        fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
-            if let Some(v) = v {
-                for s in v.split(',').map(str::parse) {
-                    if let Ok(s) = s {
-                        if !slot.contains(&s) {
-                            slot.push(s);
-                        }
-                    } else {
-                        return false;
-                    }
-                }
-                true
-            } else {
-                false
-            }
-        }
-
-        fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
-            match v.map(|s| s.parse()) {
-                None => {
-                    *slot = 2;
-                    true
-                }
-                Some(Ok(i)) if i <= 2 => {
-                    *slot = i;
-                    true
-                }
-                _ => {
-                    false
-                }
-            }
-        }
-
-        fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
-            match v.and_then(LinkerFlavor::from_str) {
-                Some(lf) => *slote = Some(lf),
-                _ => return false,
-            }
-            true
-        }
-
-        fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
-            match v {
-                None => false,
-                Some(s) => {
-                    let parts = s.split('=').collect::<Vec<_>>();
-                    if parts.len() != 2 { return false; }
-                    let crate_name = parts[0].to_string();
-                    let fuel = parts[1].parse::<u64>();
-                    if fuel.is_err() { return false; }
-                    *slot = Some((crate_name, fuel.unwrap()));
-                    true
-                }
-            }
-        }
-
-        fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
-            match v {
-                None => false,
-                Some(s) if s.split('=').count() <= 2 => {
-                    *slot = Some(s.to_string());
-                    true
-                }
-                _ => false,
-            }
-        }
-
-        fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
-                None => { *slot = Some(1); true }
-            }
-        }
-
-        fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        LtoCli::Yes
-                    } else {
-                        LtoCli::No
-                    };
-                    return true
-                }
-            }
-
-            *slot = match v {
-                None => LtoCli::NoParam,
-                Some("thin") => LtoCli::Thin,
-                Some("fat") => LtoCli::Fat,
-                Some(_) => return false,
-            };
-            true
-        }
-
-        fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        LinkerPluginLto::LinkerPluginAuto
-                    } else {
-                        LinkerPluginLto::Disabled
-                    };
-                    return true
-                }
-            }
-
-            *slot = match v {
-                None => LinkerPluginLto::LinkerPluginAuto,
-                Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
-            };
-            true
-        }
-
-        fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
-            *slot = match v {
-                None => SwitchWithOptPath::Enabled(None),
-                Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
-            };
-            true
-        }
-
-        fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
-            match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
-                Some(mergefunc) => *slot = Some(mergefunc),
-                _ => return false,
-            }
-            true
-        }
-
-        fn parse_symbol_mangling_version(
-            slot: &mut SymbolManglingVersion,
-            v: Option<&str>,
-        ) -> bool {
-            *slot = match v {
-                Some("legacy") => SymbolManglingVersion::Legacy,
-                Some("v0") => SymbolManglingVersion::V0,
-                _ => return false,
-            };
-            true
-        }
-    }
-) }
-
-options! {CodegenOptions, CodegenSetter, basic_codegen_options,
-          build_codegen_options, "C", "codegen",
-          CG_OPTIONS, cg_type_desc, cgsetters,
-    ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "this option is deprecated and does nothing"),
-    linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
-        "system linker to link outputs with"),
-    link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
-        "a single extra argument to append to the linker invocation (can be used several times)"),
-    link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
-        "extra arguments to append to the linker invocation (space separated)"),
-    link_dead_code: bool = (false, parse_bool, [UNTRACKED],
-        "don't let linker strip dead code (turning it on can be used for code coverage)"),
-    lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
-        "perform LLVM link-time optimizations"),
-    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). \
-        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],
-        "a list of arguments to pass to LLVM (space separated)"),
-    save_temps: bool = (false, parse_bool, [UNTRACKED],
-        "save all temporary output files during compilation"),
-    rpath: bool = (false, parse_bool, [UNTRACKED],
-        "set rpath values in libs/exes"),
-    overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "use overflow checks for integer arithmetic"),
-    no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
-        "don't pre-populate the pass manager with a list of passes"),
-    no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
-        "don't run the loop vectorization optimization passes"),
-    no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
-        "don't run LLVM's SLP vectorization pass"),
-    soft_float: bool = (false, parse_bool, [TRACKED],
-        "use soft float ABI (*eabihf targets only)"),
-    prefer_dynamic: bool = (false, parse_bool, [TRACKED],
-        "prefer dynamic linking to static linking"),
-    no_integrated_as: bool = (false, parse_bool, [TRACKED],
-        "use an external assembler rather than LLVM's integrated one"),
-    no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "disable the use of the redzone"),
-    relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
-        "choose the relocation model to use (`rustc --print relocation-models` for details)"),
-    code_model: Option<String> = (None, parse_opt_string, [TRACKED],
-        "choose the code model to use (`rustc --print code-models` for details)"),
-    metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
-        "metadata to mangle symbol names with"),
-    extra_filename: String = (String::new(), parse_string, [UNTRACKED],
-        "extra data to put in each output filename"),
-    codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
-        "divide crate into N units to optimize in parallel"),
-    remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
-        "print remarks for these optimization passes (space separated, or \"all\")"),
-    no_stack_check: bool = (false, parse_bool, [UNTRACKED],
-        "the `--no-stack-check` flag is deprecated and does nothing"),
-    debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
-        "debug info emission level, 0 = no debug info, 1 = line tables only, \
-         2 = full debug info with variable and type information"),
-    opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
-        "optimize with possible levels 0-3, s, or z"),
-    force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "force use of the frame pointers"),
-    debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "explicitly enable the `cfg(debug_assertions)` directive"),
-    inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
-        "set the threshold for inlining a function (default: 225)"),
-    panic: Option<PanicStrategy> = (None, parse_panic_strategy,
-        [TRACKED], "panic strategy to compile crate with"),
-    incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "enable incremental compilation"),
-    default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
-        "allow the linker to link its default libraries"),
-    linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
-                                           "linker flavor"),
-    linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
-        parse_linker_plugin_lto, [TRACKED],
-        "generate build artifacts that are compatible with linker-based LTO."),
-    profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
-        parse_switch_with_opt_path, [TRACKED],
-        "compile the program with profiling instrumentation"),
-    profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
-        "use the given `.profdata` file for profile-guided optimization"),
-}
-
-options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
-          build_debugging_options, "Z", "debugging",
-          DB_OPTIONS, db_type_desc, dbsetters,
-    codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
-        "the backend to use"),
-    verbose: bool = (false, parse_bool, [UNTRACKED],
-        "in general, enable more debug printouts"),
-    span_free_formats: bool = (false, parse_bool, [UNTRACKED],
-        "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
-    identify_regions: bool = (false, parse_bool, [UNTRACKED],
-        "make unnamed regions display as '# (where # is some non-ident unique id)"),
-    borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "select which borrowck is used (`mir` or `migrate`)"),
-    time_passes: bool = (false, parse_bool, [UNTRACKED],
-        "measure time of each rustc pass"),
-    time: bool = (false, parse_bool, [UNTRACKED],
-        "measure time of rustc processes"),
-    time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
-        "measure time of each LLVM pass"),
-    input_stats: bool = (false, parse_bool, [UNTRACKED],
-        "gather statistics about the input"),
-    asm_comments: bool = (false, parse_bool, [TRACKED],
-        "generate comments into the assembly (may change behavior)"),
-    verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
-        "verify LLVM IR"),
-    borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
-        "gather borrowck statistics"),
-    no_landing_pads: bool = (false, parse_bool, [TRACKED],
-        "omit landing pads for unwinding"),
-    fewer_names: bool = (false, parse_bool, [TRACKED],
-        "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
-    meta_stats: bool = (false, parse_bool, [UNTRACKED],
-        "gather metadata statistics"),
-    print_link_args: bool = (false, parse_bool, [UNTRACKED],
-        "print the arguments passed to the linker"),
-    print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
-        "prints the LLVM optimization passes being run"),
-    ast_json: bool = (false, parse_bool, [UNTRACKED],
-        "print the AST as JSON and halt"),
-    // We default to 1 here since we want to behave like
-    // a sequential compiler for now. This'll likely be adjusted
-    // in the future. Note that -Zthreads=0 is the way to get
-    // the num_cpus behavior.
-    threads: usize = (1, parse_threads, [UNTRACKED],
-        "use a thread pool with N threads"),
-    ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
-        "print the pre-expansion AST as JSON and halt"),
-    ls: bool = (false, parse_bool, [UNTRACKED],
-        "list the symbols defined by a library crate"),
-    save_analysis: bool = (false, parse_bool, [UNTRACKED],
-        "write syntax and type analysis (in JSON format) information, in \
-         addition to normal output"),
-    print_region_graph: bool = (false, parse_bool, [UNTRACKED],
-        "prints region inference graph. \
-         Use with RUST_REGION_GRAPH=help for more info"),
-    parse_only: bool = (false, parse_bool, [UNTRACKED],
-        "parse only; do not compile, assemble, or link"),
-    dual_proc_macros: bool = (false, parse_bool, [TRACKED],
-        "load proc macros for both target and host, but only link to the target"),
-    no_codegen: bool = (false, parse_bool, [TRACKED],
-        "run all passes except codegen; no output"),
-    treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
-        "treat error number `val` that occurs as bug"),
-    report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
-        "immediately print bugs registered with `delay_span_bug`"),
-    external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
-        "show macro backtraces even for non-local macros"),
-    teach: bool = (false, parse_bool, [TRACKED],
-        "show extended diagnostic help"),
-    terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
-        "set the current terminal width"),
-    panic_abort_tests: bool = (false, parse_bool, [TRACKED],
-        "support compiling tests with panic=abort"),
-    continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
-        "attempt to recover from parse errors (experimental)"),
-    dep_tasks: bool = (false, parse_bool, [UNTRACKED],
-        "print tasks that execute and the color their dep node gets (requires debug build)"),
-    incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "enable incremental compilation (experimental)"),
-    incremental_queries: bool = (true, parse_bool, [UNTRACKED],
-        "enable incremental compilation support for queries (experimental)"),
-    incremental_info: bool = (false, parse_bool, [UNTRACKED],
-        "print high-level information about incremental reuse (or the lack thereof)"),
-    incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
-        "dump hash information in textual format to stdout"),
-    incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
-        "verify incr. comp. hashes of green query instances"),
-    incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
-        "ignore spans during ICH computation -- used for testing"),
-    instrument_mcount: bool = (false, parse_bool, [TRACKED],
-        "insert function instrument code for mcount-based tracing"),
-    dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
-        "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
-    query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
-        "enable queries of the dependency graph for regression testing"),
-    no_analysis: bool = (false, parse_bool, [UNTRACKED],
-        "parse and expand the source, but run no analysis"),
-    unstable_options: bool = (false, parse_bool, [UNTRACKED],
-        "adds unstable command line options to rustc interface"),
-    force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "force overflow checks on or off"),
-    trace_macros: bool = (false, parse_bool, [UNTRACKED],
-        "for every macro invocation, print its name and arguments"),
-    debug_macros: bool = (false, parse_bool, [TRACKED],
-        "emit line numbers debug info inside macros"),
-    generate_arange_section: bool = (true, parse_bool, [TRACKED],
-        "generate DWARF address ranges for faster lookups"),
-    keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
-        "don't clear the hygiene data after analysis"),
-    keep_ast: bool = (false, parse_bool, [UNTRACKED],
-        "keep the AST after lowering it to HIR"),
-    show_span: Option<String> = (None, parse_opt_string, [TRACKED],
-        "show spans for compiler debugging (expr|pat|ty)"),
-    print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
-        "print layout information for each type encountered"),
-    print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "print the result of the monomorphization collection pass"),
-    mir_opt_level: usize = (1, parse_uint, [TRACKED],
-        "set the MIR optimization level (0-3, default: 1)"),
-    mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "emit noalias metadata for mutable references (default: no)"),
-    dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "dump MIR state to file.
-        `val` is used to select which passes and functions to dump. For example:
-        `all` matches all passes and functions,
-        `foo` matches all passes for functions whose name contains 'foo',
-        `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
-        `foo | bar` all passes for function names containing 'foo' or 'bar'."),
-
-    dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
-        "the directory the MIR is dumped into"),
-    dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
-        "in addition to `.mir` files, create graphviz `.dot` files"),
-    dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
-        "if set, exclude the pass number when dumping MIR (used in tests)"),
-    mir_emit_retag: bool = (false, parse_bool, [TRACKED],
-        "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
-    perf_stats: bool = (false, parse_bool, [UNTRACKED],
-        "print some performance-related statistics"),
-    query_stats: bool = (false, parse_bool, [UNTRACKED],
-        "print some statistics about the query system"),
-    hir_stats: bool = (false, parse_bool, [UNTRACKED],
-        "print some statistics about AST and HIR"),
-    always_encode_mir: bool = (false, parse_bool, [TRACKED],
-        "encode MIR of all functions into the crate metadata"),
-    json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
-        "describes how to render the `rendered` field of json diagnostics"),
-    unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
-        "take the breaks off const evaluation. NOTE: this is unsound"),
-    osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
-        "pass `-install_name @rpath/...` to the macOS linker"),
-    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
-                                    "use a sanitizer"),
-    sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
-        "Enable recovery for selected sanitizers"),
-    sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
-        "Enable origins tracking in MemorySanitizer"),
-    fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
-        "set the optimization fuel quota for a crate"),
-    print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
-        "make rustc print the total optimization fuel used by a crate"),
-    force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
-        "force all crates to be `rustc_private` unstable"),
-    pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
-        "a single extra argument to prepend the linker invocation (can be used several times)"),
-    pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
-        "extra arguments to prepend to the linker invocation (space separated)"),
-    profile: bool = (false, parse_bool, [TRACKED],
-                     "insert profiling code"),
-    disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
-        "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
-    relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
-        "choose which RELRO level to use"),
-    nll_facts: bool = (false, parse_bool, [UNTRACKED],
-                       "dump facts from NLL analysis into side files"),
-    nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
-        "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
-    dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
-        "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
-    polonius: bool = (false, parse_bool, [UNTRACKED],
-        "enable polonius-based borrow-checker"),
-    codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
-        "generate a graphical HTML report of time spent in codegen and LLVM"),
-    thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "enable ThinLTO when possible"),
-    inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "control whether `#[inline]` functions are in all CGUs"),
-    tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
-        "choose the TLS model to use (`rustc --print tls-models` for details)"),
-    saturating_float_casts: bool = (false, parse_bool, [TRACKED],
-        "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
-         the max/min integer respectively, and NaN is mapped to 0"),
-    human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
-        "generate human-readable, predictable names for codegen units"),
-    dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
-        "in dep-info output, omit targets for tracking dependencies of the dep-info files \
-         themselves"),
-    unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
-        "present the input source, unstable (and less-pretty) variants;
-        valid types are any of the types for `--pretty`, as well as:
-        `expanded`, `expanded,identified`,
-        `expanded,hygiene` (with internal representations),
-        `everybody_loops` (all function bodies replaced with `loop {}`),
-        `hir` (the HIR), `hir,identified`,
-        `hir,typed` (HIR with types for each node),
-        `hir-tree` (dump the raw HIR),
-        `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
-    run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "run `dsymutil` and delete intermediate object files"),
-    ui_testing: bool = (false, parse_bool, [UNTRACKED],
-        "format compiler diagnostics in a way that's better suitable for UI testing"),
-    embed_bitcode: bool = (false, parse_bool, [TRACKED],
-        "embed LLVM bitcode in object files"),
-    strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "tell the linker to strip debuginfo when building without debuginfo enabled."),
-    share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
-        "make the current crate share its generic instantiations"),
-    chalk: bool = (false, parse_bool, [TRACKED],
-        "enable the experimental Chalk-based trait solving engine"),
-    no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
-        "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
-    no_leak_check: bool = (false, parse_bool, [UNTRACKED],
-        "disables the 'leak check' for subtyping; unsound, but useful for tests"),
-    no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
-        "don't interleave execution of lints; allows benchmarking individual lints"),
-    crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
-        "inject the given attribute in the crate"),
-    self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
-        parse_switch_with_opt_path, [UNTRACKED],
-        "run the self profiler and output the raw event data"),
-    self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
-        "specifies which kinds of events get recorded by the self profiler"),
-    emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
-        "emits a section containing stack size metadata"),
-    plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
-          "whether to use the PLT when calling into shared libraries;
-          only has effect for PIC code on systems with ELF binaries
-          (default: PLT is disabled if full relro is enabled)"),
-    merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
-        "control the operation of the MergeFunctions LLVM pass, taking
-         the same values as the target option of the same name"),
-    allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
-        "only allow the listed language features to be enabled in code (space separated)"),
-    symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
-        parse_symbol_mangling_version, [TRACKED],
-        "which mangling version to use for symbol names"),
-    binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
-        "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
-    insert_sideeffect: bool = (false, parse_bool, [TRACKED],
-        "fix undefined behavior when a thread doesn't eventually make progress \
-         (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
-}
-
 pub const fn default_lib_output() -> CrateType {
     CrateType::Rlib
 }
@@ -2953,7 +2020,7 @@ impl PpMode {
 /// `Hash` implementation for `DepTrackingHash`. It's important though that
 /// we have an opt-in scheme here, so one is hopefully forced to think about
 /// how the hash should be calculated when adding a new command-line argument.
-mod dep_tracking {
+crate mod dep_tracking {
     use crate::lint;
     use crate::utils::NativeLibraryKind;
     use std::collections::BTreeMap;
diff --git a/src/librustc_session/lib.rs b/src/librustc_session/lib.rs
index 9d7c23100a0..39e997a3b91 100644
--- a/src/librustc_session/lib.rs
+++ b/src/librustc_session/lib.rs
@@ -1,3 +1,4 @@
+#![feature(crate_visibility_modifier)]
 #![feature(test)]
 
 // Use the test crate here so we depend on getopts through it. This allow tools to link to both
@@ -13,7 +14,9 @@ pub mod node_id;
 pub mod parse;
 
 mod code_stats;
+#[macro_use]
 pub mod config;
+mod options;
 pub mod filesearch;
 pub mod search_paths;
 
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
new file mode 100644
index 00000000000..9ddc9c0d602
--- /dev/null
+++ b/src/librustc_session/options.rs
@@ -0,0 +1,951 @@
+use crate::config::*;
+
+use crate::lint;
+use crate::utils::NativeLibraryKind;
+use crate::early_error;
+use crate::search_paths::SearchPath;
+
+use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
+use rustc_target::spec::TargetTriple;
+
+use syntax_pos::edition::Edition;
+use rustc_feature::UnstableFeatures;
+
+use getopts;
+
+use std::collections::BTreeMap;
+
+use std::str;
+use std::hash::Hasher;
+use std::collections::hash_map::DefaultHasher;
+use std::path::PathBuf;
+
+macro_rules! hash_option {
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
+        if $sub_hashes.insert(stringify!($opt_name),
+                              $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
+            panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
+        }
+    });
+}
+
+macro_rules! top_level_options {
+    (pub struct Options { $(
+        $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
+    )* } ) => (
+        #[derive(Clone)]
+        pub struct Options {
+            $(pub $opt: $t),*
+        }
+
+        impl Options {
+            pub fn dep_tracking_hash(&self) -> u64 {
+                let mut sub_hashes = BTreeMap::new();
+                $({
+                    hash_option!($opt,
+                                 &self.$opt,
+                                 &mut sub_hashes,
+                                 [$dep_tracking_marker $($warn_val,
+                                                         $warn_text,
+                                                         self.error_format)*]);
+                })*
+                let mut hasher = DefaultHasher::new();
+                dep_tracking::stable_hash(sub_hashes,
+                                          &mut hasher,
+                                          self.error_format);
+                hasher.finish()
+            }
+        }
+    );
+}
+
+// The top-level command-line options struct.
+//
+// For each option, one has to specify how it behaves with regard to the
+// dependency tracking system of incremental compilation. This is done via the
+// square-bracketed directive after the field type. The options are:
+//
+// [TRACKED]
+// A change in the given field will cause the compiler to completely clear the
+// incremental compilation cache before proceeding.
+//
+// [UNTRACKED]
+// Incremental compilation is not influenced by this option.
+//
+// If you add a new option to this struct or one of the sub-structs like
+// `CodegenOptions`, think about how it influences incremental compilation. If in
+// doubt, specify [TRACKED], which is always "correct" but might lead to
+// unnecessary re-compilation.
+top_level_options!(
+    pub struct Options {
+        // The crate config requested for the session, which may be combined
+        // with additional crate configurations during the compile process.
+        crate_types: Vec<CrateType> [TRACKED],
+        optimize: OptLevel [TRACKED],
+        // Include the `debug_assertions` flag in dependency tracking, since it
+        // can influence whether overflow checks are done or not.
+        debug_assertions: bool [TRACKED],
+        debuginfo: DebugInfo [TRACKED],
+        lint_opts: Vec<(String, lint::Level)> [TRACKED],
+        lint_cap: Option<lint::Level> [TRACKED],
+        describe_lints: bool [UNTRACKED],
+        output_types: OutputTypes [TRACKED],
+        search_paths: Vec<SearchPath> [UNTRACKED],
+        libs: Vec<(String, Option<String>, Option<NativeLibraryKind>)> [TRACKED],
+        maybe_sysroot: Option<PathBuf> [UNTRACKED],
+
+        target_triple: TargetTriple [TRACKED],
+
+        test: bool [TRACKED],
+        error_format: ErrorOutputType [UNTRACKED],
+
+        // If `Some`, enable incremental compilation, using the given
+        // directory to store intermediate results.
+        incremental: Option<PathBuf> [UNTRACKED],
+
+        debugging_opts: DebuggingOptions [TRACKED],
+        prints: Vec<PrintRequest> [UNTRACKED],
+        // Determines which borrow checker(s) to run. This is the parsed, sanitized
+        // version of `debugging_opts.borrowck`, which is just a plain string.
+        borrowck_mode: BorrowckMode [UNTRACKED],
+        cg: CodegenOptions [TRACKED],
+        externs: Externs [UNTRACKED],
+        crate_name: Option<String> [TRACKED],
+        // An optional name to use as the crate for std during std injection,
+        // written `extern crate name as std`. Defaults to `std`. Used by
+        // out-of-tree drivers.
+        alt_std_name: Option<String> [TRACKED],
+        // Indicates how the compiler should treat unstable features.
+        unstable_features: UnstableFeatures [TRACKED],
+
+        // Indicates whether this run of the compiler is actually rustdoc. This
+        // is currently just a hack and will be removed eventually, so please
+        // try to not rely on this too much.
+        actually_rustdoc: bool [TRACKED],
+
+        // Specifications of codegen units / ThinLTO which are forced as a
+        // result of parsing command line options. These are not necessarily
+        // what rustc was invoked with, but massaged a bit to agree with
+        // commands like `--emit llvm-ir` which they're often incompatible with
+        // if we otherwise use the defaults of rustc.
+        cli_forced_codegen_units: Option<usize> [UNTRACKED],
+        cli_forced_thinlto_off: bool [UNTRACKED],
+
+        // Remap source path prefixes in all output (messages, object files, debug, etc.).
+        remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+
+        edition: Edition [TRACKED],
+
+        // `true` if we're emitting JSON blobs about each artifact produced
+        // by the compiler.
+        json_artifact_notifications: bool [TRACKED],
+
+        pretty: Option<PpMode> [UNTRACKED],
+    }
+);
+
+/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
+/// macro is to define an interface that can be programmatically used by the option parser
+/// to initialize the struct without hardcoding field names all over the place.
+///
+/// The goal is to invoke this macro once with the correct fields, and then this macro generates all
+/// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
+/// generated code to parse an option into its respective field in the struct. There are a few
+/// hand-written parsers for parsing specific types of values in this module.
+macro_rules! options {
+    ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
+     $buildfn:ident, $prefix:expr, $outputname:expr,
+     $stat:ident, $mod_desc:ident, $mod_set:ident,
+     $($opt:ident : $t:ty = (
+        $init:expr,
+        $parse:ident,
+        [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
+        $desc:expr)
+     ),* ,) =>
+(
+    #[derive(Clone)]
+    pub struct $struct_name { $(pub $opt: $t),* }
+
+    pub fn $defaultfn() -> $struct_name {
+        $struct_name { $($opt: $init),* }
+    }
+
+    pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
+    {
+        let mut op = $defaultfn();
+        for option in matches.opt_strs($prefix) {
+            let mut iter = option.splitn(2, '=');
+            let key = iter.next().unwrap();
+            let value = iter.next();
+            let option_to_lookup = key.replace("-", "_");
+            let mut found = false;
+            for &(candidate, setter, opt_type_desc, _) in $stat {
+                if option_to_lookup != candidate { continue }
+                if !setter(&mut op, value) {
+                    match (value, opt_type_desc) {
+                        (Some(..), None) => {
+                            early_error(error_format, &format!("{} option `{}` takes no \
+                                                                value", $outputname, key))
+                        }
+                        (None, Some(type_desc)) => {
+                            early_error(error_format, &format!("{0} option `{1}` requires \
+                                                                {2} ({3} {1}=<value>)",
+                                                               $outputname, key,
+                                                               type_desc, $prefix))
+                        }
+                        (Some(value), Some(type_desc)) => {
+                            early_error(error_format, &format!("incorrect value `{}` for {} \
+                                                                option `{}` - {} was expected",
+                                                               value, $outputname,
+                                                               key, type_desc))
+                        }
+                        (None, None) => panic!()
+                    }
+                }
+                found = true;
+                break;
+            }
+            if !found {
+                early_error(error_format, &format!("unknown {} option: `{}`",
+                                                   $outputname, key));
+            }
+        }
+        return op;
+    }
+
+    impl dep_tracking::DepTrackingHash for $struct_name {
+        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+            let mut sub_hashes = BTreeMap::new();
+            $({
+                hash_option!($opt,
+                             &self.$opt,
+                             &mut sub_hashes,
+                             [$dep_tracking_marker $($dep_warn_val,
+                                                     $dep_warn_text,
+                                                     error_format)*]);
+            })*
+            dep_tracking::stable_hash(sub_hashes, hasher, error_format);
+        }
+    }
+
+    pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
+    pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
+        &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
+
+    #[allow(non_upper_case_globals, dead_code)]
+    mod $mod_desc {
+        pub const parse_bool: Option<&str> = None;
+        pub const parse_opt_bool: Option<&str> =
+            Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
+        pub const parse_string: Option<&str> = Some("a string");
+        pub const parse_string_push: Option<&str> = Some("a string");
+        pub const parse_pathbuf_push: Option<&str> = Some("a path");
+        pub const parse_opt_string: Option<&str> = Some("a string");
+        pub const parse_opt_pathbuf: Option<&str> = Some("a path");
+        pub const parse_list: Option<&str> = Some("a space-separated list of strings");
+        pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
+        pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
+        pub const parse_threads: Option<&str> = Some("a number");
+        pub const parse_uint: Option<&str> = Some("a number");
+        pub const parse_passes: Option<&str> =
+            Some("a space-separated list of passes, or `all`");
+        pub const parse_opt_uint: Option<&str> =
+            Some("a number");
+        pub const parse_panic_strategy: Option<&str> =
+            Some("either `unwind` or `abort`");
+        pub const parse_relro_level: Option<&str> =
+            Some("one of: `full`, `partial`, or `off`");
+        pub const parse_sanitizer: Option<&str> =
+            Some("one of: `address`, `leak`, `memory` or `thread`");
+        pub const parse_sanitizer_list: Option<&str> =
+            Some("comma separated list of sanitizers");
+        pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
+        pub const parse_linker_flavor: Option<&str> =
+            Some(::rustc_target::spec::LinkerFlavor::one_of());
+        pub const parse_optimization_fuel: Option<&str> =
+            Some("crate=integer");
+        pub const parse_unpretty: Option<&str> =
+            Some("`string` or `string=string`");
+        pub const parse_treat_err_as_bug: Option<&str> =
+            Some("either no value or a number bigger than 0");
+        pub const parse_lto: Option<&str> =
+            Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
+                  `fat`, or omitted");
+        pub const parse_linker_plugin_lto: Option<&str> =
+            Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
+                  or the path to the linker plugin");
+        pub const parse_switch_with_opt_path: Option<&str> =
+            Some("an optional path to the profiling data output directory");
+        pub const parse_merge_functions: Option<&str> =
+            Some("one of: `disabled`, `trampolines`, or `aliases`");
+        pub const parse_symbol_mangling_version: Option<&str> =
+            Some("either `legacy` or `v0` (RFC 2603)");
+    }
+
+    #[allow(dead_code)]
+    mod $mod_set {
+        use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
+            SymbolManglingVersion};
+        use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
+        use std::path::PathBuf;
+        use std::str::FromStr;
+
+        $(
+            pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
+                $parse(&mut cg.$opt, v)
+            }
+        )*
+
+        fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
+            match v {
+                Some(..) => false,
+                None => { *slot = true; true }
+            }
+        }
+
+        fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => {
+                    match s {
+                        "n" | "no" | "off" => {
+                            *slot = Some(false);
+                        }
+                        "y" | "yes" | "on" => {
+                            *slot = Some(true);
+                        }
+                        _ => { return false; }
+                    }
+
+                    true
+                },
+                None => { *slot = Some(true); true }
+            }
+        }
+
+        fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { *slot = Some(s.to_string()); true },
+                None => false,
+            }
+        }
+
+        fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { *slot = Some(PathBuf::from(s)); true },
+                None => false,
+            }
+        }
+
+        fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { *slot = s.to_string(); true },
+                None => false,
+            }
+        }
+
+        fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { slot.push(s.to_string()); true },
+                None => false,
+            }
+        }
+
+        fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { slot.push(PathBuf::from(s)); true },
+                None => false,
+            }
+        }
+
+        fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
+                      -> bool {
+            match v {
+                Some(s) => {
+                    slot.extend(s.split_whitespace().map(|s| s.to_string()));
+                    true
+                },
+                None => false,
+            }
+        }
+
+        fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
+                      -> bool {
+            match v {
+                Some(s) => {
+                    let v = s.split_whitespace().map(|s| s.to_string()).collect();
+                    *slot = Some(v);
+                    true
+                },
+                None => false,
+            }
+        }
+
+        fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
+                      -> bool {
+            match v {
+                Some(s) => {
+                    let v = s.split(',').map(|s| s.to_string()).collect();
+                    *slot = Some(v);
+                    true
+                },
+                None => false,
+            }
+        }
+
+        fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
+            match v.and_then(|s| s.parse().ok()) {
+                Some(0) => { *slot = ::num_cpus::get(); true },
+                Some(i) => { *slot = i; true },
+                None => false
+            }
+        }
+
+        fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
+            match v.and_then(|s| s.parse().ok()) {
+                Some(i) => { *slot = i; true },
+                None => false
+            }
+        }
+
+        fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
+                None => { *slot = None; false }
+            }
+        }
+
+        fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
+            match v {
+                Some("all") => {
+                    *slot = Passes::All;
+                    true
+                }
+                v => {
+                    let mut passes = vec![];
+                    if parse_list(&mut passes, v) {
+                        *slot = Passes::Some(passes);
+                        true
+                    } else {
+                        false
+                    }
+                }
+            }
+        }
+
+        fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
+            match v {
+                Some("unwind") => *slot = Some(PanicStrategy::Unwind),
+                Some("abort") => *slot = Some(PanicStrategy::Abort),
+                _ => return false
+            }
+            true
+        }
+
+        fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => {
+                    match s.parse::<RelroLevel>() {
+                        Ok(level) => *slot = Some(level),
+                        _ => return false
+                    }
+                },
+                _ => return false
+            }
+            true
+        }
+
+        fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
+            if let Some(Ok(s)) =  v.map(str::parse) {
+                *slot = Some(s);
+                true
+            } else {
+                false
+            }
+        }
+
+        fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
+            if let Some(v) = v {
+                for s in v.split(',').map(str::parse) {
+                    if let Ok(s) = s {
+                        if !slot.contains(&s) {
+                            slot.push(s);
+                        }
+                    } else {
+                        return false;
+                    }
+                }
+                true
+            } else {
+                false
+            }
+        }
+
+        fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
+            match v.map(|s| s.parse()) {
+                None => {
+                    *slot = 2;
+                    true
+                }
+                Some(Ok(i)) if i <= 2 => {
+                    *slot = i;
+                    true
+                }
+                _ => {
+                    false
+                }
+            }
+        }
+
+        fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+            match v.and_then(LinkerFlavor::from_str) {
+                Some(lf) => *slote = Some(lf),
+                _ => return false,
+            }
+            true
+        }
+
+        fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+            match v {
+                None => false,
+                Some(s) => {
+                    let parts = s.split('=').collect::<Vec<_>>();
+                    if parts.len() != 2 { return false; }
+                    let crate_name = parts[0].to_string();
+                    let fuel = parts[1].parse::<u64>();
+                    if fuel.is_err() { return false; }
+                    *slot = Some((crate_name, fuel.unwrap()));
+                    true
+                }
+            }
+        }
+
+        fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
+            match v {
+                None => false,
+                Some(s) if s.split('=').count() <= 2 => {
+                    *slot = Some(s.to_string());
+                    true
+                }
+                _ => false,
+            }
+        }
+
+        fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
+            match v {
+                Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
+                None => { *slot = Some(1); true }
+            }
+        }
+
+        fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
+            if v.is_some() {
+                let mut bool_arg = None;
+                if parse_opt_bool(&mut bool_arg, v) {
+                    *slot = if bool_arg.unwrap() {
+                        LtoCli::Yes
+                    } else {
+                        LtoCli::No
+                    };
+                    return true
+                }
+            }
+
+            *slot = match v {
+                None => LtoCli::NoParam,
+                Some("thin") => LtoCli::Thin,
+                Some("fat") => LtoCli::Fat,
+                Some(_) => return false,
+            };
+            true
+        }
+
+        fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
+            if v.is_some() {
+                let mut bool_arg = None;
+                if parse_opt_bool(&mut bool_arg, v) {
+                    *slot = if bool_arg.unwrap() {
+                        LinkerPluginLto::LinkerPluginAuto
+                    } else {
+                        LinkerPluginLto::Disabled
+                    };
+                    return true
+                }
+            }
+
+            *slot = match v {
+                None => LinkerPluginLto::LinkerPluginAuto,
+                Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
+            };
+            true
+        }
+
+        fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
+            *slot = match v {
+                None => SwitchWithOptPath::Enabled(None),
+                Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
+            };
+            true
+        }
+
+        fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
+            match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
+                Some(mergefunc) => *slot = Some(mergefunc),
+                _ => return false,
+            }
+            true
+        }
+
+        fn parse_symbol_mangling_version(
+            slot: &mut SymbolManglingVersion,
+            v: Option<&str>,
+        ) -> bool {
+            *slot = match v {
+                Some("legacy") => SymbolManglingVersion::Legacy,
+                Some("v0") => SymbolManglingVersion::V0,
+                _ => return false,
+            };
+            true
+        }
+    }
+) }
+
+options! {CodegenOptions, CodegenSetter, basic_codegen_options,
+          build_codegen_options, "C", "codegen",
+          CG_OPTIONS, cg_type_desc, cgsetters,
+    ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "this option is deprecated and does nothing"),
+    linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "system linker to link outputs with"),
+    link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
+        "a single extra argument to append to the linker invocation (can be used several times)"),
+    link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
+        "extra arguments to append to the linker invocation (space separated)"),
+    link_dead_code: bool = (false, parse_bool, [UNTRACKED],
+        "don't let linker strip dead code (turning it on can be used for code coverage)"),
+    lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
+        "perform LLVM link-time optimizations"),
+    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). \
+        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],
+        "a list of arguments to pass to LLVM (space separated)"),
+    save_temps: bool = (false, parse_bool, [UNTRACKED],
+        "save all temporary output files during compilation"),
+    rpath: bool = (false, parse_bool, [UNTRACKED],
+        "set rpath values in libs/exes"),
+    overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "use overflow checks for integer arithmetic"),
+    no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
+        "don't pre-populate the pass manager with a list of passes"),
+    no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
+        "don't run the loop vectorization optimization passes"),
+    no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
+        "don't run LLVM's SLP vectorization pass"),
+    soft_float: bool = (false, parse_bool, [TRACKED],
+        "use soft float ABI (*eabihf targets only)"),
+    prefer_dynamic: bool = (false, parse_bool, [TRACKED],
+        "prefer dynamic linking to static linking"),
+    no_integrated_as: bool = (false, parse_bool, [TRACKED],
+        "use an external assembler rather than LLVM's integrated one"),
+    no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "disable the use of the redzone"),
+    relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
+        "choose the relocation model to use (`rustc --print relocation-models` for details)"),
+    code_model: Option<String> = (None, parse_opt_string, [TRACKED],
+        "choose the code model to use (`rustc --print code-models` for details)"),
+    metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
+        "metadata to mangle symbol names with"),
+    extra_filename: String = (String::new(), parse_string, [UNTRACKED],
+        "extra data to put in each output filename"),
+    codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
+        "divide crate into N units to optimize in parallel"),
+    remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
+        "print remarks for these optimization passes (space separated, or \"all\")"),
+    no_stack_check: bool = (false, parse_bool, [UNTRACKED],
+        "the `--no-stack-check` flag is deprecated and does nothing"),
+    debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
+        "debug info emission level, 0 = no debug info, 1 = line tables only, \
+         2 = full debug info with variable and type information"),
+    opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
+        "optimize with possible levels 0-3, s, or z"),
+    force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "force use of the frame pointers"),
+    debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "explicitly enable the `cfg(debug_assertions)` directive"),
+    inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
+        "set the threshold for inlining a function (default: 225)"),
+    panic: Option<PanicStrategy> = (None, parse_panic_strategy,
+        [TRACKED], "panic strategy to compile crate with"),
+    incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "enable incremental compilation"),
+    default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
+        "allow the linker to link its default libraries"),
+    linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
+                                           "linker flavor"),
+    linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
+        parse_linker_plugin_lto, [TRACKED],
+        "generate build artifacts that are compatible with linker-based LTO."),
+    profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+        parse_switch_with_opt_path, [TRACKED],
+        "compile the program with profiling instrumentation"),
+    profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
+        "use the given `.profdata` file for profile-guided optimization"),
+}
+
+options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
+          build_debugging_options, "Z", "debugging",
+          DB_OPTIONS, db_type_desc, dbsetters,
+    codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
+        "the backend to use"),
+    verbose: bool = (false, parse_bool, [UNTRACKED],
+        "in general, enable more debug printouts"),
+    span_free_formats: bool = (false, parse_bool, [UNTRACKED],
+        "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
+    identify_regions: bool = (false, parse_bool, [UNTRACKED],
+        "make unnamed regions display as '# (where # is some non-ident unique id)"),
+    borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "select which borrowck is used (`mir` or `migrate`)"),
+    time_passes: bool = (false, parse_bool, [UNTRACKED],
+        "measure time of each rustc pass"),
+    time: bool = (false, parse_bool, [UNTRACKED],
+        "measure time of rustc processes"),
+    time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
+        "measure time of each LLVM pass"),
+    input_stats: bool = (false, parse_bool, [UNTRACKED],
+        "gather statistics about the input"),
+    asm_comments: bool = (false, parse_bool, [TRACKED],
+        "generate comments into the assembly (may change behavior)"),
+    verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
+        "verify LLVM IR"),
+    borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
+        "gather borrowck statistics"),
+    no_landing_pads: bool = (false, parse_bool, [TRACKED],
+        "omit landing pads for unwinding"),
+    fewer_names: bool = (false, parse_bool, [TRACKED],
+        "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
+    meta_stats: bool = (false, parse_bool, [UNTRACKED],
+        "gather metadata statistics"),
+    print_link_args: bool = (false, parse_bool, [UNTRACKED],
+        "print the arguments passed to the linker"),
+    print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
+        "prints the LLVM optimization passes being run"),
+    ast_json: bool = (false, parse_bool, [UNTRACKED],
+        "print the AST as JSON and halt"),
+    // We default to 1 here since we want to behave like
+    // a sequential compiler for now. This'll likely be adjusted
+    // in the future. Note that -Zthreads=0 is the way to get
+    // the num_cpus behavior.
+    threads: usize = (1, parse_threads, [UNTRACKED],
+        "use a thread pool with N threads"),
+    ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
+        "print the pre-expansion AST as JSON and halt"),
+    ls: bool = (false, parse_bool, [UNTRACKED],
+        "list the symbols defined by a library crate"),
+    save_analysis: bool = (false, parse_bool, [UNTRACKED],
+        "write syntax and type analysis (in JSON format) information, in \
+         addition to normal output"),
+    print_region_graph: bool = (false, parse_bool, [UNTRACKED],
+        "prints region inference graph. \
+         Use with RUST_REGION_GRAPH=help for more info"),
+    parse_only: bool = (false, parse_bool, [UNTRACKED],
+        "parse only; do not compile, assemble, or link"),
+    dual_proc_macros: bool = (false, parse_bool, [TRACKED],
+        "load proc macros for both target and host, but only link to the target"),
+    no_codegen: bool = (false, parse_bool, [TRACKED],
+        "run all passes except codegen; no output"),
+    treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
+        "treat error number `val` that occurs as bug"),
+    report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
+        "immediately print bugs registered with `delay_span_bug`"),
+    external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
+        "show macro backtraces even for non-local macros"),
+    teach: bool = (false, parse_bool, [TRACKED],
+        "show extended diagnostic help"),
+    terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
+        "set the current terminal width"),
+    panic_abort_tests: bool = (false, parse_bool, [TRACKED],
+        "support compiling tests with panic=abort"),
+    continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
+        "attempt to recover from parse errors (experimental)"),
+    dep_tasks: bool = (false, parse_bool, [UNTRACKED],
+        "print tasks that execute and the color their dep node gets (requires debug build)"),
+    incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "enable incremental compilation (experimental)"),
+    incremental_queries: bool = (true, parse_bool, [UNTRACKED],
+        "enable incremental compilation support for queries (experimental)"),
+    incremental_info: bool = (false, parse_bool, [UNTRACKED],
+        "print high-level information about incremental reuse (or the lack thereof)"),
+    incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
+        "dump hash information in textual format to stdout"),
+    incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
+        "verify incr. comp. hashes of green query instances"),
+    incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
+        "ignore spans during ICH computation -- used for testing"),
+    instrument_mcount: bool = (false, parse_bool, [TRACKED],
+        "insert function instrument code for mcount-based tracing"),
+    dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
+        "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
+    query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
+        "enable queries of the dependency graph for regression testing"),
+    no_analysis: bool = (false, parse_bool, [UNTRACKED],
+        "parse and expand the source, but run no analysis"),
+    unstable_options: bool = (false, parse_bool, [UNTRACKED],
+        "adds unstable command line options to rustc interface"),
+    force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "force overflow checks on or off"),
+    trace_macros: bool = (false, parse_bool, [UNTRACKED],
+        "for every macro invocation, print its name and arguments"),
+    debug_macros: bool = (false, parse_bool, [TRACKED],
+        "emit line numbers debug info inside macros"),
+    generate_arange_section: bool = (true, parse_bool, [TRACKED],
+        "generate DWARF address ranges for faster lookups"),
+    keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
+        "don't clear the hygiene data after analysis"),
+    keep_ast: bool = (false, parse_bool, [UNTRACKED],
+        "keep the AST after lowering it to HIR"),
+    show_span: Option<String> = (None, parse_opt_string, [TRACKED],
+        "show spans for compiler debugging (expr|pat|ty)"),
+    print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
+        "print layout information for each type encountered"),
+    print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "print the result of the monomorphization collection pass"),
+    mir_opt_level: usize = (1, parse_uint, [TRACKED],
+        "set the MIR optimization level (0-3, default: 1)"),
+    mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "emit noalias metadata for mutable references (default: no)"),
+    dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "dump MIR state to file.
+        `val` is used to select which passes and functions to dump. For example:
+        `all` matches all passes and functions,
+        `foo` matches all passes for functions whose name contains 'foo',
+        `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
+        `foo | bar` all passes for function names containing 'foo' or 'bar'."),
+
+    dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
+        "the directory the MIR is dumped into"),
+    dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
+        "in addition to `.mir` files, create graphviz `.dot` files"),
+    dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
+        "if set, exclude the pass number when dumping MIR (used in tests)"),
+    mir_emit_retag: bool = (false, parse_bool, [TRACKED],
+        "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
+    perf_stats: bool = (false, parse_bool, [UNTRACKED],
+        "print some performance-related statistics"),
+    query_stats: bool = (false, parse_bool, [UNTRACKED],
+        "print some statistics about the query system"),
+    hir_stats: bool = (false, parse_bool, [UNTRACKED],
+        "print some statistics about AST and HIR"),
+    always_encode_mir: bool = (false, parse_bool, [TRACKED],
+        "encode MIR of all functions into the crate metadata"),
+    json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "describes how to render the `rendered` field of json diagnostics"),
+    unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
+        "take the breaks off const evaluation. NOTE: this is unsound"),
+    osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
+        "pass `-install_name @rpath/...` to the macOS linker"),
+    sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
+                                    "use a sanitizer"),
+    sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
+        "Enable recovery for selected sanitizers"),
+    sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
+        "Enable origins tracking in MemorySanitizer"),
+    fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
+        "set the optimization fuel quota for a crate"),
+    print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
+        "make rustc print the total optimization fuel used by a crate"),
+    force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
+        "force all crates to be `rustc_private` unstable"),
+    pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
+        "a single extra argument to prepend the linker invocation (can be used several times)"),
+    pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
+        "extra arguments to prepend to the linker invocation (space separated)"),
+    profile: bool = (false, parse_bool, [TRACKED],
+                     "insert profiling code"),
+    disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
+        "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
+    relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
+        "choose which RELRO level to use"),
+    nll_facts: bool = (false, parse_bool, [UNTRACKED],
+                       "dump facts from NLL analysis into side files"),
+    nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
+        "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
+    dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
+        "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
+    polonius: bool = (false, parse_bool, [UNTRACKED],
+        "enable polonius-based borrow-checker"),
+    codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
+        "generate a graphical HTML report of time spent in codegen and LLVM"),
+    thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "enable ThinLTO when possible"),
+    inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "control whether `#[inline]` functions are in all CGUs"),
+    tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
+        "choose the TLS model to use (`rustc --print tls-models` for details)"),
+    saturating_float_casts: bool = (false, parse_bool, [TRACKED],
+        "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
+         the max/min integer respectively, and NaN is mapped to 0"),
+    human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
+        "generate human-readable, predictable names for codegen units"),
+    dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
+        "in dep-info output, omit targets for tracking dependencies of the dep-info files \
+         themselves"),
+    unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
+        "present the input source, unstable (and less-pretty) variants;
+        valid types are any of the types for `--pretty`, as well as:
+        `expanded`, `expanded,identified`,
+        `expanded,hygiene` (with internal representations),
+        `everybody_loops` (all function bodies replaced with `loop {}`),
+        `hir` (the HIR), `hir,identified`,
+        `hir,typed` (HIR with types for each node),
+        `hir-tree` (dump the raw HIR),
+        `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
+    run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "run `dsymutil` and delete intermediate object files"),
+    ui_testing: bool = (false, parse_bool, [UNTRACKED],
+        "format compiler diagnostics in a way that's better suitable for UI testing"),
+    embed_bitcode: bool = (false, parse_bool, [TRACKED],
+        "embed LLVM bitcode in object files"),
+    strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "tell the linker to strip debuginfo when building without debuginfo enabled."),
+    share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "make the current crate share its generic instantiations"),
+    chalk: bool = (false, parse_bool, [TRACKED],
+        "enable the experimental Chalk-based trait solving engine"),
+    no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
+        "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
+    no_leak_check: bool = (false, parse_bool, [UNTRACKED],
+        "disables the 'leak check' for subtyping; unsound, but useful for tests"),
+    no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
+        "don't interleave execution of lints; allows benchmarking individual lints"),
+    crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
+        "inject the given attribute in the crate"),
+    self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
+        parse_switch_with_opt_path, [UNTRACKED],
+        "run the self profiler and output the raw event data"),
+    self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
+        "specifies which kinds of events get recorded by the self profiler"),
+    emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
+        "emits a section containing stack size metadata"),
+    plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
+          "whether to use the PLT when calling into shared libraries;
+          only has effect for PIC code on systems with ELF binaries
+          (default: PLT is disabled if full relro is enabled)"),
+    merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
+        "control the operation of the MergeFunctions LLVM pass, taking
+         the same values as the target option of the same name"),
+    allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
+        "only allow the listed language features to be enabled in code (space separated)"),
+    symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
+        parse_symbol_mangling_version, [TRACKED],
+        "which mangling version to use for symbol names"),
+    binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
+        "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
+    insert_sideeffect: bool = (false, parse_bool, [TRACKED],
+        "fix undefined behavior when a thread doesn't eventually make progress \
+         (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
+}
diff --git a/src/librustc_target/spec/i686_unknown_dragonfly.rs b/src/librustc_target/spec/i686_unknown_dragonfly.rs
deleted file mode 100644
index 20315e7145c..00000000000
--- a/src/librustc_target/spec/i686_unknown_dragonfly.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
-
-pub fn target() -> TargetResult {
-    let mut base = super::dragonfly_base::opts();
-    base.cpu = "pentium4".to_string();
-    base.max_atomic_width = Some(64);
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
-    base.stack_probes = true;
-
-    Ok(Target {
-        llvm_target: "i686-unknown-dragonfly".to_string(),
-        target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
-        target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
-        arch: "x86".to_string(),
-        target_os: "dragonfly".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: base,
-    })
-}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 693cf75e8fd..34b321d38f0 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -398,7 +398,6 @@ supported_targets! {
     ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
     ("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
 
-    ("i686-unknown-dragonfly", i686_unknown_dragonfly),
     ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
 
     ("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
index dbcd77bc753..2c9ba9f2ca9 100644
--- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs
@@ -7,7 +7,7 @@ pub fn target() -> Result<Target, String> {
         "--as-needed",
         "--eh-frame-hdr",
         "-z" , "noexecstack",
-        "-e","sgx_entry",
+        "-e","elf_entry",
         "-Bstatic",
         "--gc-sections",
         "-z","text",
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index af978d5095e..290f86d626e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1145,11 +1145,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         } else {
             // Otherwise, we have to walk through the supertraits to find
             // those that do.
-            let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
-                self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
-            });
             self.one_bound_for_assoc_type(
-                candidates,
+                || traits::supertraits(tcx, trait_ref),
                 &trait_ref.print_only_trait_path().to_string(),
                 binding.item_name,
                 binding.span
@@ -1531,50 +1528,48 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
 
-        let bounds = predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref());
-
-        // Check that there is exactly one way to find an associated type with the
-        // correct name.
-        let suitable_bounds = traits::transitive_bounds(tcx, bounds)
-            .filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name));
-
         let param_hir_id = tcx.hir().as_local_hir_id(ty_param_def_id).unwrap();
         let param_name = tcx.hir().ty_param_name(param_hir_id);
-        self.one_bound_for_assoc_type(suitable_bounds,
-                                      &param_name.as_str(),
-                                      assoc_name,
-                                      span)
+        self.one_bound_for_assoc_type(
+            || traits::transitive_bounds(tcx, predicates
+                .iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref())),
+            &param_name.as_str(),
+            assoc_name,
+            span,
+        )
     }
 
-    // Checks that `bounds` contains exactly one element and reports appropriate
-    // errors otherwise.
     fn one_bound_for_assoc_type<I>(&self,
-                                   mut bounds: I,
+                                   all_candidates: impl Fn() -> I,
                                    ty_param_name: &str,
                                    assoc_name: ast::Ident,
                                    span: Span)
         -> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
         where I: Iterator<Item = ty::PolyTraitRef<'tcx>>
     {
-        let bound = match bounds.next() {
+        let mut matching_candidates = all_candidates().filter(|r| {
+            self.trait_defines_associated_type_named(r.def_id(), assoc_name)
+        });
+
+        let bound = match matching_candidates.next() {
             Some(bound) => bound,
             None => {
-                struct_span_err!(self.tcx().sess, span, E0220,
-                                 "associated type `{}` not found for `{}`",
-                                 assoc_name,
-                                 ty_param_name)
-                    .span_label(span, format!("associated type `{}` not found", assoc_name))
-                    .emit();
+                self.complain_about_assoc_type_not_found(
+                    all_candidates,
+                    ty_param_name,
+                    assoc_name,
+                    span
+                );
                 return Err(ErrorReported);
             }
         };
 
         debug!("one_bound_for_assoc_type: bound = {:?}", bound);
 
-        if let Some(bound2) = bounds.next() {
+        if let Some(bound2) = matching_candidates.next() {
             debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
 
-            let bounds = iter::once(bound).chain(iter::once(bound2)).chain(bounds);
+            let bounds = iter::once(bound).chain(iter::once(bound2)).chain(matching_candidates);
             let mut err = struct_span_err!(
                 self.tcx().sess, span, E0221,
                 "ambiguous associated type `{}` in bounds of `{}`",
@@ -1606,6 +1601,50 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         return Ok(bound);
     }
 
+    fn complain_about_assoc_type_not_found<I>(&self,
+                                              all_candidates: impl Fn() -> I,
+                                              ty_param_name: &str,
+                                              assoc_name: ast::Ident,
+                                              span: Span)
+    where I: Iterator<Item = ty::PolyTraitRef<'tcx>> {
+        let mut err = struct_span_err!(self.tcx().sess, span, E0220,
+                                 "associated type `{}` not found for `{}`",
+                                 assoc_name,
+                                 ty_param_name);
+
+        let all_candidate_names: Vec<_> = all_candidates()
+            .map(|r| self.tcx().associated_items(r.def_id()))
+            .flatten()
+            .filter_map(|item|
+                if item.kind == ty::AssocKind::Type {
+                    Some(item.ident.name)
+                } else {
+                    None
+                }
+            )
+            .collect();
+
+        if let Some(suggested_name) = find_best_match_for_name(
+            all_candidate_names.iter(),
+            &assoc_name.as_str(),
+            None,
+        ) {
+            err.span_suggestion(
+                span,
+                "there is an associated type with a similar name",
+                suggested_name.to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            err.span_label(
+                span,
+                format!("associated type `{}` not found", assoc_name)
+            );
+        }
+
+        err.emit();
+    }
+
     // Create a type from a path to an associated type.
     // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
     // and item_segment is the path segment for `D`. We return a type and a def for
@@ -1660,10 +1699,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                 };
 
-                let candidates = traits::supertraits(tcx, ty::Binder::bind(trait_ref))
-                    .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_ident));
-
-                self.one_bound_for_assoc_type(candidates, "Self", assoc_ident, span)?
+                self.one_bound_for_assoc_type(
+                    || traits::supertraits(tcx, ty::Binder::bind(trait_ref)),
+                    "Self",
+                    assoc_ident,
+                    span
+                )?
             }
             (&ty::Param(_), Res::SelfTy(Some(param_did), None)) |
             (&ty::Param(_), Res::Def(DefKind::TyParam, param_did)) => {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 035ece23810..21ba02746c7 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -469,22 +469,48 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (Some(t_from), Some(t_cast)) => (t_from, t_cast),
             // Function item types may need to be reified before casts.
             (None, Some(t_cast)) => {
-                if let ty::FnDef(..) = self.expr_ty.kind {
-                    // Attempt a coercion to a fn pointer type.
-                    let f = self.expr_ty.fn_sig(fcx.tcx);
-                    let res = fcx.try_coerce(self.expr,
-                                             self.expr_ty,
-                                             fcx.tcx.mk_fn_ptr(f),
-                                             AllowTwoPhase::No);
-                    if let Err(TypeError::IntrinsicCast) = res {
-                        return Err(CastError::IllegalCast);
+                match self.expr_ty.kind {
+                    ty::FnDef(..) => {
+                        // Attempt a coercion to a fn pointer type.
+                        let f = self.expr_ty.fn_sig(fcx.tcx);
+                        let res = fcx.try_coerce(self.expr,
+                                                 self.expr_ty,
+                                                 fcx.tcx.mk_fn_ptr(f),
+                                                 AllowTwoPhase::No);
+                        if let Err(TypeError::IntrinsicCast) = res {
+                            return Err(CastError::IllegalCast);
+                        }
+                        if res.is_err() {
+                            return Err(CastError::NonScalar);
+                        }
+                        (FnPtr, t_cast)
                     }
-                    if res.is_err() {
-                        return Err(CastError::NonScalar);
+                    // Special case some errors for references, and check for
+                    // array-ptr-casts. `Ref` is not a CastTy because the cast
+                    // is split into a coercion to a pointer type, followed by
+                    // a cast.
+                    ty::Ref(_, inner_ty, mutbl) => {
+                        return match t_cast {
+                            Int(_) | Float => match inner_ty.kind {
+                                ty::Int(_) |
+                                ty::Uint(_) |
+                                ty::Float(_) |
+                                ty::Infer(ty::InferTy::IntVar(_)) |
+                                ty::Infer(ty::InferTy::FloatVar(_)) => {
+                                    Err(CastError::NeedDeref)
+                                }
+                                _ => Err(CastError::NeedViaPtr),
+                            }
+                            // array-ptr-cast
+                            Ptr(mt) => self.check_ref_cast(
+                                fcx,
+                                TypeAndMut { mutbl, ty: inner_ty },
+                                mt,
+                            ),
+                            _ => Err(CastError::NonScalar),
+                        };
                     }
-                    (FnPtr, t_cast)
-                } else {
-                    return Err(CastError::NonScalar);
+                    _ => return Err(CastError::NonScalar),
                 }
             }
             _ => return Err(CastError::NonScalar),
@@ -492,7 +518,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
         match (t_from, t_cast) {
             // These types have invariants! can't cast into them.
-            (_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
+            (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
 
             // * -> Bool
             (_, Int(Bool)) => Err(CastError::CastToBool),
@@ -517,28 +543,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
             (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
             (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
-            (RPtr(p), Int(_)) |
-            (RPtr(p), Float) => {
-                match p.ty.kind {
-                    ty::Int(_) |
-                    ty::Uint(_) |
-                    ty::Float(_) => {
-                        Err(CastError::NeedDeref)
-                    }
-                    ty::Infer(t) => {
-                        match t {
-                            ty::InferTy::IntVar(_) |
-                            ty::InferTy::FloatVar(_) => Err(CastError::NeedDeref),
-                            _ => Err(CastError::NeedViaPtr),
-                        }
-                    }
-                    _ => Err(CastError::NeedViaPtr),
-                }
-            }
+
             // * -> ptr
             (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
             (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
-            (RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
 
             // prim -> prim
             (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 253fc5575c5..726b3ba9857 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1289,8 +1289,20 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 }
 
                 // Error possibly reported in `check_assign` so avoid emitting error again.
-                err.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected))
-                    .is_some());
+                let assign_to_bool = expression
+                    // #67273: Use initial expected type as opposed to `expected`.
+                    // Otherwise we end up using prior coercions in e.g. a `match` expression:
+                    // ```
+                    // match i {
+                    //     0 => true, // Because of this...
+                    //     1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`.
+                    //     _ => (),
+                    // };
+                    // ```
+                    .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
+                    .is_some();
+
+                err.emit_unless(assign_to_bool);
 
                 self.final_ty = Some(fcx.tcx.types.err);
             }
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 5bfc60c7540..19441be87b9 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -871,6 +871,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) {
             Ok(method) => {
+                // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
+                // trigger this codepath causing `structuraly_resolved_type` to emit an error.
+
                 self.write_method_call(expr.hir_id, method);
                 Ok(method)
             }
@@ -1422,8 +1425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         field: ast::Ident,
     ) -> Ty<'tcx> {
         let expr_t = self.check_expr_with_needs(base, needs);
-        let expr_t = self.structurally_resolved_type(base.span,
-                                                     expr_t);
+        let expr_t = self.structurally_resolved_type(base.span, expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
         while let Some((base_t, _)) = autoderef.next() {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 992308183b4..880ead0e301 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1456,7 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     pcx.method_name = Some(method_name);
                     pcx.assemble_inherent_candidates();
                     pcx.assemble_extension_candidates_for_traits_in_scope(hir::DUMMY_HIR_ID)
-                        .ok().map_or(None, |_| {
+                        .map_or(None, |_| {
                             pcx.pick_core()
                                 .and_then(|pick| pick.ok())
                                 .and_then(|pick| Some(pick.item))
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index f4b53b4d106..9cd8c9abfd7 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -15,7 +15,7 @@ use rustc::traits::Obligation;
 use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use rustc::ty::print::with_crate_prefix;
 use syntax_pos::{Span, FileName};
-use syntax::ast;
+use syntax::{ast, source_map};
 use syntax::util::lev_distance;
 
 use rustc_error_codes::*;
@@ -79,37 +79,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return None;
         }
 
-        let print_disambiguation_help = |
-            err: &mut DiagnosticBuilder<'_>,
-            trait_name: String,
-        | {
-            err.help(&format!(
-                "to disambiguate the method call, write `{}::{}({}{})` instead",
-                trait_name,
-                item_name,
-                if rcvr_ty.is_region_ptr() && args.is_some() {
-                    if rcvr_ty.is_mutable_ptr() {
-                        "&mut "
-                    } else {
-                        "&"
-                    }
-                } else {
-                    ""
-                },
-                args.map(|arg| arg
-                    .iter()
-                    .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span)
-                        .unwrap_or_else(|_| "...".to_owned()))
-                    .collect::<Vec<_>>()
-                    .join(", ")
-                ).unwrap_or_else(|| "...".to_owned())
-            ));
-        };
-
         let report_candidates = |
             span: Span,
             err: &mut DiagnosticBuilder<'_>,
             mut sources: Vec<CandidateSource>,
+            sugg_span: Span,
         | {
             sources.sort();
             sources.dedup();
@@ -150,15 +124,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                         };
 
-                        let note_str = if sources.len() > 1 {
-                            format!("candidate #{} is defined in an impl{} for the type `{}`",
-                                    idx + 1,
-                                    insertion,
-                                    impl_ty)
+                        let (note_str, idx) = if sources.len() > 1 {
+                            (format!(
+                                "candidate #{} is defined in an impl{} for the type `{}`",
+                                idx + 1,
+                                insertion,
+                                impl_ty,
+                            ), Some(idx + 1))
                         } else {
-                            format!("the candidate is defined in an impl{} for the type `{}`",
-                                    insertion,
-                                    impl_ty)
+                            (format!(
+                                "the candidate is defined in an impl{} for the type `{}`",
+                                insertion,
+                                impl_ty,
+                            ), None)
                         };
                         if let Some(note_span) = note_span {
                             // We have a span pointing to the method. Show note with snippet.
@@ -168,7 +146,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             err.note(&note_str);
                         }
                         if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
-                            print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id));
+                            let path = self.tcx.def_path_str(trait_ref.def_id);
+
+                            let ty = match item.kind {
+                                ty::AssocKind::Const |
+                                ty::AssocKind::Type |
+                                ty::AssocKind::OpaqueTy => rcvr_ty,
+                                ty::AssocKind::Method => self.tcx.fn_sig(item.def_id)
+                                    .inputs()
+                                    .skip_binder()
+                                    .get(0)
+                                    .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr())
+                                    .map(|ty| *ty)
+                                    .unwrap_or(rcvr_ty),
+                            };
+                            print_disambiguation_help(
+                                item_name,
+                                args,
+                                err,
+                                path,
+                                ty,
+                                item.kind,
+                                sugg_span,
+                                idx,
+                                self.tcx.sess.source_map(),
+                            );
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
@@ -182,19 +184,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         };
                         let item_span = self.tcx.sess.source_map()
                             .def_span(self.tcx.def_span(item.def_id));
-                        if sources.len() > 1 {
+                        let idx = if sources.len() > 1 {
                             span_note!(err,
                                        item_span,
                                        "candidate #{} is defined in the trait `{}`",
                                        idx + 1,
                                        self.tcx.def_path_str(trait_did));
+                            Some(idx + 1)
                         } else {
                             span_note!(err,
                                        item_span,
                                        "the candidate is defined in the trait `{}`",
                                        self.tcx.def_path_str(trait_did));
-                        }
-                        print_disambiguation_help(err, self.tcx.def_path_str(trait_did));
+                            None
+                        };
+                        let path = self.tcx.def_path_str(trait_did);
+                        print_disambiguation_help(
+                            item_name,
+                            args,
+                            err,
+                            path,
+                            rcvr_ty,
+                            item.kind,
+                            sugg_span,
+                            idx,
+                            self.tcx.sess.source_map(),
+                        );
                     }
                 }
             }
@@ -203,6 +218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
+        let sugg_span = if let SelfSource::MethodCall(expr) = source {
+            // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
+            self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span
+        } else {
+            span
+        };
+
         match error {
             MethodError::NoMatch(NoMatchData {
                 static_candidates: static_sources,
@@ -495,9 +517,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ));
                     }
 
-                    report_candidates(span, &mut err, static_sources);
+                    report_candidates(span, &mut err, static_sources, sugg_span);
                 } else if static_sources.len() > 1 {
-                    report_candidates(span, &mut err, static_sources);
+                    report_candidates(span, &mut err, static_sources, sugg_span);
                 }
 
                 if !unsatisfied_predicates.is_empty() {
@@ -584,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                                "multiple applicable items in scope");
                 err.span_label(span, format!("multiple `{}` found", item_name));
 
-                report_candidates(span, &mut err, sources);
+                report_candidates(span, &mut err, sources, sugg_span);
                 err.emit();
             }
 
@@ -1123,3 +1145,56 @@ impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
         hir::intravisit::NestedVisitorMap::None
     }
 }
+
+fn print_disambiguation_help(
+    item_name: ast::Ident,
+    args: Option<&'tcx [hir::Expr]>,
+    err: &mut DiagnosticBuilder<'_>,
+    trait_name: String,
+    rcvr_ty: Ty<'_>,
+    kind: ty::AssocKind,
+    span: Span,
+    candidate: Option<usize>,
+    source_map: &source_map::SourceMap,
+) {
+    let mut applicability = Applicability::MachineApplicable;
+    let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) {
+        format!(
+            "({}{})",
+            if rcvr_ty.is_region_ptr() {
+                if rcvr_ty.is_mutable_ptr() {
+                    "&mut "
+                } else {
+                    "&"
+                }
+            } else {
+                ""
+            },
+            args.iter()
+                .map(|arg| source_map.span_to_snippet(arg.span)
+                    .unwrap_or_else(|_| {
+                        applicability = Applicability::HasPlaceholders;
+                        "_".to_owned()
+                    }))
+                .collect::<Vec<_>>()
+                .join(", "),
+        )
+    } else {
+        String::new()
+    };
+    let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
+    err.span_suggestion(
+        span,
+        &format!(
+            "disambiguate the {} for {}",
+            kind.suggestion_descr(),
+            if let Some(candidate) = candidate {
+                format!("candidate #{}", candidate)
+            } else {
+                "the candidate".to_string()
+            },
+        ),
+        sugg,
+        applicability,
+    );
+}
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a956aba4f62..7f1c6c99cf8 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -103,6 +103,7 @@ use rustc_index::vec::Idx;
 use rustc_target::spec::abi::Abi;
 use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
@@ -2329,7 +2330,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, d
     );
     let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
     err.span_label(sp, &msg);
-    if let &[ref start @ .., ref end] = &variant_spans[..] {
+    if let [start @ .., end] = &*variant_spans {
         for variant_span in start {
             err.span_label(*variant_span, "");
         }
@@ -2371,23 +2372,14 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
     }
     let sp = tcx.sess.source_map().def_span(sp);
 
-    if adt.is_enum() {
-        if !tcx.features().transparent_enums {
-            feature_err(
-                &tcx.sess.parse_sess,
-                sym::transparent_enums,
-                sp,
-                "transparent enums are unstable",
-            )
-            .emit();
-        }
-        if adt.variants.len() != 1 {
-            bad_variant_count(tcx, adt, sp, def_id);
-            if adt.variants.is_empty() {
-                // Don't bother checking the fields. No variants (and thus no fields) exist.
-                return;
-            }
-        }
+    if adt.is_enum() && !tcx.features().transparent_enums {
+        feature_err(
+            &tcx.sess.parse_sess,
+            sym::transparent_enums,
+            sp,
+            "transparent enums are unstable",
+        )
+        .emit();
     }
 
     if adt.is_union() && !tcx.features().transparent_unions {
@@ -2400,6 +2392,14 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
         .emit();
     }
 
+    if adt.variants.len() != 1 {
+        bad_variant_count(tcx, adt, sp, def_id);
+        if adt.variants.is_empty() {
+            // Don't bother checking the fields. No variants (and thus no fields) exist.
+            return;
+        }
+    }
+
     // For each field, figure out if it's known to be a ZST and align(1)
     let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
@@ -3880,36 +3880,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         call_sp: Span,
         args: &'tcx [hir::Expr],
     ) {
-        if !call_sp.desugaring_kind().is_some() {
-            // We *do not* do this for desugared call spans to keep good diagnostics when involving
-            // the `?` operator.
-            for error in errors {
-                if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
-                    // Collect the argument position for all arguments that could have caused this
-                    // `FulfillmentError`.
-                    let mut referenced_in = final_arg_types.iter()
-                        .map(|(i, checked_ty, _)| (i, checked_ty))
-                        .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
-                        .flat_map(|(i, ty)| {
-                            let ty = self.resolve_vars_if_possible(ty);
-                            // We walk the argument type because the argument's type could have
-                            // been `Option<T>`, but the `FulfillmentError` references `T`.
-                            ty.walk()
-                                .filter(|&ty| ty == predicate.skip_binder().self_ty())
-                                .map(move |_| *i)
-                        })
-                        .collect::<Vec<_>>();
+        // We *do not* do this for desugared call spans to keep good diagnostics when involving
+        // the `?` operator.
+        if call_sp.desugaring_kind().is_some() {
+            return
+        }
 
-                    // Both checked and coerced types could have matched, thus we need to remove
-                    // duplicates.
-                    referenced_in.dedup();
+        for error in errors {
+            // Only if the cause is somewhere inside the expression we want try to point at arg.
+            // Otherwise, it means that the cause is somewhere else and we should not change
+            // anything because we can break the correct span.
+            if !call_sp.contains(error.obligation.cause.span) {
+                continue
+            }
 
-                    if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
-                        // We make sure that only *one* argument matches the obligation failure
-                        // and we assign the obligation's span to its expression's.
-                        error.obligation.cause.span = args[ref_in].span;
-                        error.points_at_arg_span = true;
-                    }
+            if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
+                // Collect the argument position for all arguments that could have caused this
+                // `FulfillmentError`.
+                let mut referenced_in = final_arg_types.iter()
+                    .map(|(i, checked_ty, _)| (i, checked_ty))
+                    .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
+                    .flat_map(|(i, ty)| {
+                        let ty = self.resolve_vars_if_possible(ty);
+                        // We walk the argument type because the argument's type could have
+                        // been `Option<T>`, but the `FulfillmentError` references `T`.
+                        ty.walk()
+                            .filter(|&ty| ty == predicate.skip_binder().self_ty())
+                            .map(move |_| *i)
+                    })
+                    .collect::<Vec<_>>();
+
+                // Both checked and coerced types could have matched, thus we need to remove
+                // duplicates.
+                referenced_in.dedup();
+
+                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+                    // We make sure that only *one* argument matches the obligation failure
+                    // and we assign the obligation's span to its expression's.
+                    error.obligation.cause.span = args[ref_in].span;
+                    error.points_at_arg_span = true;
                 }
             }
         }
@@ -5350,16 +5359,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                       directly, not through a function pointer");
     }
 
-    // Resolves `typ` by a single level if `typ` is a type variable.
-    // If no resolution is possible, then an error is reported.
-    // Numeric inference variables may be left unresolved.
+    /// Resolves `typ` by a single level if `typ` is a type variable.
+    /// 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_vars_with_obligations(ty);
         if !ty.is_ty_var() {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.need_type_info_err((**self).body_id, sp, ty)
+                self.need_type_info_err((**self).body_id, sp, ty, E0282)
                     .note("type must be known at this point")
                     .emit();
             }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 321faa4a322..4f20a91e4b0 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -334,10 +334,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             err.emit();
                         }
                         IsAssign::No => {
+                            let (message, missing_trait) = match op.node {
+                                hir::BinOpKind::Add    => {
+                                    (format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty),
+                                    Some("std::ops::Add"))
+                                },
+                                hir::BinOpKind::Sub    => {
+                                    (format!("cannot substract `{}` from `{}`", rhs_ty, lhs_ty),
+                                    Some("std::ops::Sub"))
+                                },
+                                hir::BinOpKind::Mul    => {
+                                    (format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty),
+                                    Some("std::ops::Mul"))
+                                },
+                                hir::BinOpKind::Div    => {
+                                    (format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::Div"))
+                                },
+                                hir::BinOpKind::Rem    => {
+                                    (format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::Rem"))
+                                },
+                                hir::BinOpKind::BitAnd => {
+                                    (format!("no implementation for `{} & {}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::BitAnd"))
+                                },
+                                hir::BinOpKind::BitXor => {
+                                    (format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::BitXor"))
+                                },
+                                hir::BinOpKind::BitOr  => {
+                                    (format!("no implementation for `{} | {}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::BitOr"))
+                                },
+                                hir::BinOpKind::Shl    => {
+                                    (format!("no implementation for `{} << {}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::Shl"))
+                                },
+                                hir::BinOpKind::Shr    => {
+                                    (format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty),
+                                    Some("std::ops::Shr"))
+                                },
+                                hir::BinOpKind::Eq |
+                                hir::BinOpKind::Ne     => {
+                                    (format!(
+                                            "binary operation `{}` cannot be applied to type `{}`",
+                                            op.node.as_str(), lhs_ty),
+                                    Some("std::cmp::PartialEq"))
+                                },
+                                hir::BinOpKind::Lt |
+                                hir::BinOpKind::Le |
+                                hir::BinOpKind::Gt |
+                                hir::BinOpKind::Ge     => {
+                                    (format!(
+                                            "binary operation `{}` cannot be applied to type `{}`",
+                                            op.node.as_str(), lhs_ty),
+                                    Some("std::cmp::PartialOrd"))
+                                }
+                                _ => (format!(
+                                        "binary operation `{}` cannot be applied to type `{}`",
+                                        op.node.as_str(), lhs_ty),
+                                    None)
+                            };
                             let mut err = struct_span_err!(self.tcx.sess, op.span, E0369,
-                                "binary operation `{}` cannot be applied to type `{}`",
-                                op.node.as_str(),
-                                lhs_ty);
+                                "{}", message.as_str());
 
                             let mut involves_fn = false;
                             if !lhs_expr.span.eq(&rhs_expr.span) {
@@ -382,25 +442,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     }
                                 }
                             }
-                            let missing_trait = match op.node {
-                                hir::BinOpKind::Add    => Some("std::ops::Add"),
-                                hir::BinOpKind::Sub    => Some("std::ops::Sub"),
-                                hir::BinOpKind::Mul    => Some("std::ops::Mul"),
-                                hir::BinOpKind::Div    => Some("std::ops::Div"),
-                                hir::BinOpKind::Rem    => Some("std::ops::Rem"),
-                                hir::BinOpKind::BitAnd => Some("std::ops::BitAnd"),
-                                hir::BinOpKind::BitXor => Some("std::ops::BitXor"),
-                                hir::BinOpKind::BitOr  => Some("std::ops::BitOr"),
-                                hir::BinOpKind::Shl    => Some("std::ops::Shl"),
-                                hir::BinOpKind::Shr    => Some("std::ops::Shr"),
-                                hir::BinOpKind::Eq |
-                                hir::BinOpKind::Ne => Some("std::cmp::PartialEq"),
-                                hir::BinOpKind::Lt |
-                                hir::BinOpKind::Le |
-                                hir::BinOpKind::Gt |
-                                hir::BinOpKind::Ge => Some("std::cmp::PartialOrd"),
-                                _ => None
-                            };
                             if let Some(missing_trait) = missing_trait {
                                 if op.node == hir::BinOpKind::Add &&
                                     self.check_str_addition(
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 71d1cd869a6..4fb57a65625 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -1154,6 +1154,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx.mk_ref(region, mt)
     }
 
+    /// Type check a slice pattern.
+    ///
+    /// Syntactically, these look like `[pat_0, ..., pat_n]`.
+    /// Semantically, we are type checking a pattern with structure:
+    /// ```
+    /// [before_0, ..., before_n, (slice, after_0, ... after_n)?]
+    /// ```
+    /// The type of `slice`, if it is present, depends on the `expected` type.
+    /// If `slice` is missing, then so is `after_i`.
+    /// If `slice` is present, it can still represent 0 elements.
     fn check_pat_slice(
         &self,
         span: Span,
@@ -1167,27 +1177,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         let expected_ty = self.structurally_resolved_type(span, expected);
         let (inner_ty, slice_ty) = match expected_ty.kind {
+            // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
             ty::Array(inner_ty, size) => {
                 let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) {
+                    // Now we know the length...
                     let min_len = before.len() as u64 + after.len() as u64;
                     if slice.is_none() {
+                        // ...and since there is no variable-length pattern,
+                        // we require an exact match between the number of elements
+                        // in the array pattern and as provided by the matched type.
                         if min_len != size {
                             self.error_scrutinee_inconsistent_length(span, min_len, size)
                         }
                         tcx.types.err
                     } else if let Some(rest) = size.checked_sub(min_len) {
+                        // The variable-length pattern was there,
+                        // so it has an array type with the remaining elements left as its size...
                         tcx.mk_array(inner_ty, rest)
                     } else {
+                        // ...however, in this case, there were no remaining elements.
+                        // That is, the slice pattern requires more than the array type offers.
                         self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size);
                         tcx.types.err
                     }
                 } else {
+                    // No idea what the length is, which happens if we have e.g.,
+                    // `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
                     self.error_scrutinee_unfixed_length(span);
                     tcx.types.err
                 };
                 (inner_ty, slice_ty)
             }
             ty::Slice(inner_ty) => (inner_ty, expected_ty),
+            // The expected type must be an array or slice, but was neither, so error.
             _ => {
                 if !expected_ty.references_error() {
                     self.error_expected_array_or_slice(span, expected_ty);
@@ -1196,12 +1218,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
+        // Type check all the patterns before `slice`.
         for elt in before {
             self.check_pat(&elt, inner_ty, def_bm, discrim_span);
         }
+        // Type check the `slice`, if present, against its expected type.
         if let Some(slice) = slice {
             self.check_pat(&slice, slice_ty, def_bm, discrim_span);
         }
+        // Type check the elements after `slice`, if present.
         for elt in after {
             self.check_pat(&elt, inner_ty, def_bm, discrim_span);
         }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3113e9b241d..35f25b322e0 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -8,6 +8,7 @@ use rustc::hir;
 use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::infer::InferCtxt;
+use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc::ty::fold::{TypeFoldable, TypeFolder};
 use rustc::ty::{self, Ty, TyCtxt};
@@ -717,7 +718,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
     fn report_error(&self, t: Ty<'tcx>) {
         if !self.tcx.sess.has_errors() {
             self.infcx
-                .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t)
+                .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282)
                 .emit();
         }
     }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 6a6294b6f87..c6c9703e92c 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -67,7 +67,7 @@ This API is completely unstable and subject to change.
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(slice_patterns)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 
 #![recursion_limit="256"]
 
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index e3de7fe2049..f2822916d3c 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -12,4 +12,6 @@ path = "lib.rs"
 pulldown-cmark = { version = "0.5.3", default-features = false }
 minifier = "0.0.33"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
 tempfile = "3"
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index f5e45924893..85f132378b1 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -1,7 +1,11 @@
 //! Item types.
 
 use std::fmt;
+
+use serde::{Serialize, Serializer};
+
 use syntax_pos::hygiene::MacroKind;
+
 use crate::clean;
 
 /// Item type. Corresponds to `clean::ItemEnum` variants.
@@ -45,6 +49,14 @@ pub enum ItemType {
     TraitAlias      = 25,
 }
 
+impl Serialize for ItemType {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        (*self as u8).serialize(serializer)
+    }
+}
 
 impl<'a> From<&'a clean::Item> for ItemType {
     fn from(item: &'a clean::Item) -> ItemType {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 86e5efbd7b3..e764b7ee527 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -31,7 +31,8 @@ use std::cmp::Ordering;
 use std::collections::{BTreeMap, VecDeque};
 use std::default::Default;
 use std::error;
-use std::fmt::{self, Formatter, Write as FmtWrite};
+
+use std::fmt::{self, Formatter, Write};
 use std::ffi::OsStr;
 use std::fs::{self, File};
 use std::io::prelude::*;
@@ -42,7 +43,8 @@ use std::sync::Arc;
 use std::rc::Rc;
 
 use errors;
-use serialize::json::{ToJson, Json, as_json};
+use serde::{Serialize, Serializer};
+use serde::ser::SerializeSeq;
 use syntax::ast;
 use syntax::edition::Edition;
 use syntax::print::pprust;
@@ -303,19 +305,22 @@ struct IndexItem {
     search_type: Option<IndexItemFunctionType>,
 }
 
-impl ToJson for IndexItem {
-    fn to_json(&self) -> Json {
+impl Serialize for IndexItem {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
         assert_eq!(self.parent.is_some(), self.parent_idx.is_some());
 
-        let mut data = Vec::with_capacity(6);
-        data.push((self.ty as usize).to_json());
-        data.push(self.name.to_json());
-        data.push(self.path.to_json());
-        data.push(self.desc.to_json());
-        data.push(self.parent_idx.to_json());
-        data.push(self.search_type.to_json());
-
-        Json::Array(data)
+        (
+            self.ty,
+            &self.name,
+            &self.path,
+            &self.desc,
+            self.parent_idx,
+            &self.search_type,
+        )
+            .serialize(serializer)
     }
 }
 
@@ -326,18 +331,20 @@ struct Type {
     generics: Option<Vec<String>>,
 }
 
-impl ToJson for Type {
-    fn to_json(&self) -> Json {
-        match self.name {
-            Some(ref name) => {
-                let mut data = Vec::with_capacity(2);
-                data.push(name.to_json());
-                if let Some(ref generics) = self.generics {
-                    data.push(generics.to_json());
-                }
-                Json::Array(data)
+impl Serialize for Type {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        if let Some(name) = &self.name {
+            let mut seq = serializer.serialize_seq(None)?;
+            seq.serialize_element(&name)?;
+            if let Some(generics) = &self.generics {
+                seq.serialize_element(&generics)?;
             }
-            None => Json::Null,
+            seq.end()
+        } else {
+            serializer.serialize_none()
         }
     }
 }
@@ -349,26 +356,29 @@ struct IndexItemFunctionType {
     output: Option<Vec<Type>>,
 }
 
-impl ToJson for IndexItemFunctionType {
-    fn to_json(&self) -> Json {
+impl Serialize for IndexItemFunctionType {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
         // If we couldn't figure out a type, just write `null`.
         let mut iter = self.inputs.iter();
         if match self.output {
             Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()),
             None => iter.any(|ref i| i.name.is_none()),
         } {
-            Json::Null
+            serializer.serialize_none()
         } else {
-            let mut data = Vec::with_capacity(2);
-            data.push(self.inputs.to_json());
-            if let Some(ref output) = self.output {
+            let mut seq = serializer.serialize_seq(None)?;
+            seq.serialize_element(&self.inputs)?;
+            if let Some(output) = &self.output {
                 if output.len() > 1 {
-                    data.push(output.to_json());
+                    seq.serialize_element(&output)?;
                 } else {
-                    data.push(output[0].to_json());
+                    seq.serialize_element(&output[0])?;
                 }
             }
-            Json::Array(data)
+            seq.end()
         }
     }
 }
@@ -596,7 +606,7 @@ fn write_shared(
     // To avoid theme switch latencies as much as possible, we put everything theme related
     // at the beginning of the html files into another js file.
     let theme_js = format!(
-r#"var themes = document.getElementById("theme-choices");
+        r#"var themes = document.getElementById("theme-choices");
 var themePicker = document.getElementById("theme-picker");
 
 function showThemeButtonState() {{
@@ -642,8 +652,8 @@ themePicker.onblur = handleThemeButtonsBlur;
     }};
     but.onblur = handleThemeButtonsBlur;
     themes.appendChild(but);
-}});"#,
-                 as_json(&themes));
+}});"#, serde_json::to_string(&themes).unwrap());
+
     write_minify(&cx.shared.fs, cx.path("theme.js"),
                  &theme_js,
                  options.enable_minification)?;
@@ -932,32 +942,48 @@ themePicker.onblur = handleThemeButtonsBlur;
             }
         };
 
-        let mut have_impls = false;
-        let mut implementors = format!(r#"implementors["{}"] = ["#, krate.name);
-        for imp in imps {
-            // If the trait and implementation are in the same crate, then
-            // there's no need to emit information about it (there's inlining
-            // going on). If they're in different crates then the crate defining
-            // the trait will be interested in our implementation.
-            if imp.impl_item.def_id.krate == did.krate { continue }
-            // If the implementation is from another crate then that crate
-            // should add it.
-            if !imp.impl_item.def_id.is_local() { continue }
-            have_impls = true;
-            write!(implementors, "{{text:{},synthetic:{},types:{}}},",
-                   as_json(&imp.inner_impl().print().to_string()),
-                   imp.inner_impl().synthetic,
-                   as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap();
+        #[derive(Serialize)]
+        struct Implementor {
+            text: String,
+            synthetic: bool,
+            types: Vec<String>,
         }
-        implementors.push_str("];");
+
+        let implementors = imps
+            .iter()
+            .filter_map(|imp| {
+                // If the trait and implementation are in the same crate, then
+                // there's no need to emit information about it (there's inlining
+                // going on). If they're in different crates then the crate defining
+                // the trait will be interested in our implementation.
+                //
+                // If the implementation is from another crate then that crate
+                // should add it.
+                if imp.impl_item.def_id.krate == did.krate || !imp.impl_item.def_id.is_local() {
+                    None
+                } else {
+                    Some(Implementor {
+                        text: imp.inner_impl().print().to_string(),
+                        synthetic: imp.inner_impl().synthetic,
+                        types: collect_paths_for_type(imp.inner_impl().for_.clone()),
+                    })
+                }
+            })
+            .collect::<Vec<_>>();
 
         // Only create a js file if we have impls to add to it. If the trait is
         // documented locally though we always create the file to avoid dead
         // links.
-        if !have_impls && !cx.cache.paths.contains_key(&did) {
+        if implementors.is_empty() && !cx.cache.paths.contains_key(&did) {
             continue;
         }
 
+        let implementors = format!(
+            r#"implementors["{}"] = {};"#,
+            krate.name,
+            serde_json::to_string(&implementors).unwrap()
+        );
+
         let mut mydst = dst.clone();
         for part in &remote_path[..remote_path.len() - 1] {
             mydst.push(part);
@@ -1456,7 +1482,7 @@ impl Context {
             if !self.render_redirect_pages {
                 let items = self.build_sidebar_items(&m);
                 let js_dst = self.dst.join("sidebar-items.js");
-                let v = format!("initSidebarItems({});", as_json(&items));
+                let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap());
                 scx.fs.write(&js_dst, &v)?;
             }
 
@@ -2558,8 +2584,11 @@ fn item_trait(
             write_loading_content(w, "</div>");
         }
     }
-    write!(w, r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,
-           as_json(&synthetic_types));
+    write!(
+        w,
+        r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,
+        serde_json::to_string(&synthetic_types).unwrap(),
+    );
 
     write!(w, r#"<script type="text/javascript" async
                          src="{root_path}/implementors/{path}/{ty}.{name}.js">
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 65dd119c27c..d80facf4704 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -8,7 +8,8 @@ use std::path::{Path, PathBuf};
 use std::collections::BTreeMap;
 use syntax::source_map::FileName;
 use syntax::symbol::sym;
-use serialize::json::{ToJson, Json, as_json};
+
+use serde::Serialize;
 
 use super::{ItemType, IndexItem, IndexItemFunctionType, Impl, shorten, plain_summary_line};
 use super::{Type, RenderInfo};
@@ -544,7 +545,7 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat
 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     let mut nodeid_to_pathid = FxHashMap::default();
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
-    let mut crate_paths = Vec::<Json>::new();
+    let mut crate_paths = vec![];
 
     let Cache { ref mut search_index,
                 ref orphan_impl_items,
@@ -581,7 +582,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
                 lastpathid += 1;
 
                 let &(ref fqp, short) = paths.get(&nodeid).unwrap();
-                crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
+                crate_paths.push((short, fqp.last().unwrap().clone()));
                 pathid
             }
         });
@@ -592,22 +593,33 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
         } else {
             lastpath = item.path.clone();
         }
-        crate_items.push(item.to_json());
+        crate_items.push(&*item);
     }
 
     let crate_doc = krate.module.as_ref().map(|module| {
         shorten(plain_summary_line(module.doc_value()))
     }).unwrap_or(String::new());
 
-    let mut crate_data = BTreeMap::new();
-    crate_data.insert("doc".to_owned(), Json::String(crate_doc));
-    crate_data.insert("i".to_owned(), Json::Array(crate_items));
-    crate_data.insert("p".to_owned(), Json::Array(crate_paths));
+    #[derive(Serialize)]
+    struct CrateData<'a> {
+        doc: String,
+        #[serde(rename = "i")]
+        items: Vec<&'a IndexItem>,
+        #[serde(rename = "p")]
+        paths: Vec<(ItemType, String)>,
+    }
 
     // Collect the index into a string
-    format!("searchIndex[{}] = {};",
-            as_json(&krate.name),
-            Json::Object(crate_data))
+    format!(
+        r#"searchIndex["{}"] = {};"#,
+        krate.name,
+        serde_json::to_string(&CrateData {
+            doc: crate_doc,
+            items: crate_items,
+            paths: crate_paths,
+        })
+        .unwrap()
+    )
 }
 
 fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 49a9cb093da..1459e8f37cd 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2683,7 +2683,7 @@ function getSearchElement() {
         insertAfter(popup, getSearchElement());
     }
 
-    onHashChange();
+    onHashChange(null);
     window.onhashchange = onHashChange;
 
     buildHelperPopup();
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index a4be3dee938..11d50cb7ce6 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -14,7 +14,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(const_fn)]
 #![feature(drain_filter)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(unicode_internals)]
 
 #![recursion_limit="256"]
@@ -35,7 +35,6 @@ extern crate rustc_parse;
 extern crate rustc_target;
 extern crate rustc_typeck;
 extern crate rustc_lexer;
-extern crate serialize;
 extern crate syntax;
 extern crate syntax_expand;
 extern crate syntax_pos;
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 13d83337f5f..e45d56c320c 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -11,7 +11,7 @@ Core encoding and decoding interfaces.
 #![feature(box_syntax)]
 #![feature(core_intrinsics)]
 #![feature(specialization)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
 #![cfg_attr(test, feature(test))]
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index ec1c444bcf8..d4c4cb9c3b9 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -465,7 +465,7 @@ impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
     }
 }
 
-#[stable(feature = "never_type", since = "1.41.0")]
+#[unstable(feature = "never_type", issue = "35121")]
 impl Error for ! {
     fn description(&self) -> &str { *self }
 }
@@ -551,6 +551,13 @@ impl Error for string::FromUtf16Error {
     }
 }
 
+#[stable(feature = "str_parse_error2", since = "1.8.0")]
+impl Error for string::ParseError {
+    fn description(&self) -> &str {
+        match *self {}
+    }
+}
+
 #[stable(feature = "decode_utf16", since = "1.9.0")]
 impl Error for char::DecodeUtf16Error {
     fn description(&self) -> &str {
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 6dcda986310..05008958ed2 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -1065,7 +1065,7 @@ impl CStr {
     /// ```
     #[inline]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_cstr_unchecked")]
+    #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "0")]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
         &*(bytes as *const [u8] as *const CStr)
     }
@@ -1119,6 +1119,7 @@ impl CStr {
     /// [`CString`]: struct.CString.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")]
     pub const fn as_ptr(&self) -> *const c_char {
         self.inner.as_ptr()
     }
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index a109e38e1e3..01e57ec0ab9 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -936,7 +936,7 @@ impl OpenOptions {
     /// ```no_run
     /// use std::fs::OpenOptions;
     ///
-    /// let file = OpenOptions::new().open("foo.txt");
+    /// let file = OpenOptions::new().read(true).open("foo.txt");
     /// ```
     ///
     /// [`ErrorKind`]: ../io/enum.ErrorKind.html
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 8e81b292f6f..df259dc2f56 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -989,6 +989,68 @@ impl<W: Write> Write for LineWriter<W> {
         }
     }
 
+    // Vectored writes are very similar to the writes above, but adjusted for
+    // the list of buffers that we have to write.
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        if self.need_flush {
+            self.flush()?;
+        }
+
+        // Find the last newline, and failing that write the whole buffer
+        let last_newline = bufs
+            .iter()
+            .enumerate()
+            .rev()
+            .filter_map(|(i, buf)| {
+                let pos = memchr::memrchr(b'\n', buf)?;
+                Some((i, pos))
+            })
+            .next();
+        let (i, j) = match last_newline {
+            Some(pair) => pair,
+            None => return self.inner.write_vectored(bufs),
+        };
+        let (prefix, suffix) = bufs.split_at(i);
+        let (buf, suffix) = suffix.split_at(1);
+        let buf = &buf[0];
+
+        // Write everything up to the last newline, flushing afterwards. Note
+        // that only if we finished our entire `write_vectored` do we try the
+        // subsequent
+        // `write`
+        let mut n = 0;
+        let prefix_amt = prefix.iter().map(|i| i.len()).sum();
+        if prefix_amt > 0 {
+            n += self.inner.write_vectored(prefix)?;
+            self.need_flush = true;
+        }
+        if n == prefix_amt {
+            match self.inner.write(&buf[..=j]) {
+                Ok(m) => n += m,
+                Err(e) if n == 0 => return Err(e),
+                Err(_) => return Ok(n),
+            }
+            self.need_flush = true;
+        }
+        if self.flush().is_err() || n != j + 1 + prefix_amt {
+            return Ok(n);
+        }
+
+        // ... and now write out everything remaining
+        match self.inner.write(&buf[j + 1..]) {
+            Ok(i) => n += i,
+            Err(_) => return Ok(n),
+        }
+
+        if suffix.iter().map(|s| s.len()).sum::<usize>() == 0 {
+            return Ok(n)
+        }
+        match self.inner.write_vectored(suffix) {
+            Ok(i) => Ok(n + i),
+            Err(_) => Ok(n),
+        }
+    }
+
     fn flush(&mut self) -> io::Result<()> {
         self.inner.flush()?;
         self.need_flush = false;
@@ -1015,7 +1077,7 @@ where
 #[cfg(test)]
 mod tests {
     use crate::io::prelude::*;
-    use crate::io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
+    use crate::io::{self, BufReader, BufWriter, LineWriter, SeekFrom, IoSlice};
     use crate::sync::atomic::{AtomicUsize, Ordering};
     use crate::thread;
 
@@ -1483,4 +1545,112 @@ mod tests {
 
         assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
     }
+
+    #[test]
+    fn line_vectored() {
+        let mut a = LineWriter::new(Vec::new());
+        assert_eq!(
+            a.write_vectored(&[
+                IoSlice::new(&[]),
+                IoSlice::new(b"\n"),
+                IoSlice::new(&[]),
+                IoSlice::new(b"a"),
+            ])
+            .unwrap(),
+            2,
+        );
+        assert_eq!(a.get_ref(), b"\n");
+
+        assert_eq!(
+            a.write_vectored(&[
+                IoSlice::new(&[]),
+                IoSlice::new(b"b"),
+                IoSlice::new(&[]),
+                IoSlice::new(b"a"),
+                IoSlice::new(&[]),
+                IoSlice::new(b"c"),
+            ])
+            .unwrap(),
+            3,
+        );
+        assert_eq!(a.get_ref(), b"\n");
+        a.flush().unwrap();
+        assert_eq!(a.get_ref(), b"\nabac");
+        assert_eq!(a.write_vectored(&[]).unwrap(), 0);
+        assert_eq!(
+            a.write_vectored(&[
+                IoSlice::new(&[]),
+                IoSlice::new(&[]),
+                IoSlice::new(&[]),
+                IoSlice::new(&[]),
+            ])
+            .unwrap(),
+            0,
+        );
+        assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3);
+        assert_eq!(a.get_ref(), b"\nabaca\n");
+    }
+
+    #[test]
+    fn line_vectored_partial_and_errors() {
+        enum Call {
+            Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> },
+            Flush { output: io::Result<()> },
+        }
+        struct Writer {
+            calls: Vec<Call>,
+        }
+
+        impl Write for Writer {
+            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+                self.write_vectored(&[IoSlice::new(buf)])
+            }
+
+            fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
+                match self.calls.pop().unwrap() {
+                    Call::Write { inputs, output } => {
+                        assert_eq!(inputs, buf.iter().map(|b| &**b).collect::<Vec<_>>());
+                        output
+                    }
+                    _ => panic!("unexpected call to write"),
+                }
+            }
+
+            fn flush(&mut self) -> io::Result<()> {
+                match self.calls.pop().unwrap() {
+                    Call::Flush { output } => output,
+                    _ => panic!("unexpected call to flush"),
+                }
+            }
+        }
+
+        impl Drop for Writer {
+            fn drop(&mut self) {
+                if !thread::panicking() {
+                    assert_eq!(self.calls.len(), 0);
+                }
+            }
+        }
+
+        // partial writes keep going
+        let mut a = LineWriter::new(Writer { calls: Vec::new() });
+        a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap();
+        a.get_mut().calls.push(Call::Flush { output: Ok(()) });
+        a.get_mut().calls.push(Call::Write { inputs: vec![b"bcx\n"], output: Ok(4) });
+        a.get_mut().calls.push(Call::Write { inputs: vec![b"abcx\n"], output: Ok(1) });
+        a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap();
+        a.get_mut().calls.push(Call::Flush { output: Ok(()) });
+        a.flush().unwrap();
+
+        // erroneous writes stop and don't write more
+        a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Err(err()) });
+        assert_eq!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).unwrap(), 2);
+        a.get_mut().calls.push(Call::Flush { output: Ok(()) });
+        a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Ok(2) });
+        a.flush().unwrap();
+
+        fn err() -> io::Error {
+            io::Error::new(io::ErrorKind::Other, "x")
+        }
+    }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 1dbb0c6ec83..9930b8f63af 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -281,9 +281,8 @@
 #![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(needs_panic_runtime)]
-#![cfg_attr(bootstrap, feature(never_type))]
+#![feature(never_type)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(on_unimplemented))]
 #![feature(optin_builtin_traits)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
@@ -293,7 +292,6 @@
 #![feature(raw)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
-#![feature(rustc_const_unstable)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
@@ -526,8 +524,8 @@ pub use core::{
     unreachable,
     write,
     writeln,
-    // Unstable
     todo,
+    // Unstable
     matches,
 };
 
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index d5f4ece726b..a9d88370c61 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -4,7 +4,7 @@ use crate::hash;
 use crate::io;
 use crate::iter;
 use crate::mem;
-use crate::net::{hton, ntoh, IpAddr, Ipv4Addr, Ipv6Addr};
+use crate::net::{htons, ntohs, IpAddr, Ipv4Addr, Ipv6Addr};
 use crate::option;
 use crate::slice;
 use crate::sys::net::netc as c;
@@ -276,7 +276,7 @@ impl SocketAddrV4 {
         SocketAddrV4 {
             inner: c::sockaddr_in {
                 sin_family: c::AF_INET as c::sa_family_t,
-                sin_port: hton(port),
+                sin_port: htons(port),
                 sin_addr: *ip.as_inner(),
                 ..unsafe { mem::zeroed() }
             },
@@ -326,7 +326,7 @@ impl SocketAddrV4 {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn port(&self) -> u16 {
-        ntoh(self.inner.sin_port)
+        ntohs(self.inner.sin_port)
     }
 
     /// Changes the port number associated with this socket address.
@@ -342,7 +342,7 @@ impl SocketAddrV4 {
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_port(&mut self, new_port: u16) {
-        self.inner.sin_port = hton(new_port);
+        self.inner.sin_port = htons(new_port);
     }
 }
 
@@ -368,7 +368,7 @@ impl SocketAddrV6 {
         SocketAddrV6 {
             inner: c::sockaddr_in6 {
                 sin6_family: c::AF_INET6 as c::sa_family_t,
-                sin6_port: hton(port),
+                sin6_port: htons(port),
                 sin6_addr: *ip.as_inner(),
                 sin6_flowinfo: flowinfo,
                 sin6_scope_id: scope_id,
@@ -420,7 +420,7 @@ impl SocketAddrV6 {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn port(&self) -> u16 {
-        ntoh(self.inner.sin6_port)
+        ntohs(self.inner.sin6_port)
     }
 
     /// Changes the port number associated with this socket address.
@@ -436,7 +436,7 @@ impl SocketAddrV6 {
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_port(&mut self, new_port: u16) {
-        self.inner.sin6_port = hton(new_port);
+        self.inner.sin6_port = htons(new_port);
     }
 
     /// Returns the flow information associated with this address.
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index e51a9b62449..9e24d707f77 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -319,6 +319,7 @@ impl Ipv4Addr {
     /// let addr = Ipv4Addr::new(127, 0, 0, 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")]
     pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
         // FIXME: should just be u32::from_be_bytes([a, b, c, d]),
         // once that method is no longer rustc_const_unstable
@@ -406,6 +407,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
     /// ```
     #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")]
     pub const fn is_unspecified(&self) -> bool {
         self.inner.s_addr == 0
     }
@@ -1015,6 +1017,7 @@ impl Ipv6Addr {
     /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
     pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16,
                      g: u16, h: u16) -> Ipv6Addr {
         Ipv6Addr {
@@ -1480,6 +1483,7 @@ impl Ipv6Addr {
     ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
     /// ```
     #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+    #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
     pub const fn octets(&self) -> [u8; 16] {
         self.inner.s6_addr
     }
diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs
index b68146939fd..8652ed8b046 100644
--- a/src/libstd/net/mod.rs
+++ b/src/libstd/net/mod.rs
@@ -85,21 +85,10 @@ pub enum Shutdown {
     Both,
 }
 
-#[doc(hidden)]
-trait NetInt {
-    fn from_be(i: Self) -> Self;
-    fn to_be(&self) -> Self;
-}
-macro_rules! doit {
-    ($($t:ident)*) => ($(impl NetInt for $t {
-        fn from_be(i: Self) -> Self { <$t>::from_be(i) }
-        fn to_be(&self) -> Self { <$t>::to_be(*self) }
-    })*)
-}
-doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
-
-fn hton<I: NetInt>(i: I) -> I { i.to_be() }
-fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }
+#[inline]
+const fn htons(i: u16) -> u16 { i.to_be() }
+#[inline]
+const fn ntohs(i: u16) -> u16 { u16::from_be(i) }
 
 fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
     where F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 5c022159970..c33f98bdd83 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1313,21 +1313,6 @@ mod tests {
     }
 
     #[test]
-    fn fast_rebind() {
-        each_ip(&mut |addr| {
-            let acceptor = t!(TcpListener::bind(&addr));
-
-            let _t = thread::spawn(move || {
-                t!(TcpStream::connect(&addr));
-            });
-
-            t!(acceptor.accept());
-            drop(acceptor);
-            t!(TcpListener::bind(&addr));
-        });
-    }
-
-    #[test]
     fn tcp_clone_smoke() {
         each_ip(&mut |addr| {
             let acceptor = t!(TcpListener::bind(&addr));
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index b4495588c99..a72951c0346 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -71,6 +71,7 @@ mod prim_bool { }
 /// write:
 ///
 /// ```
+/// #![feature(never_type)]
 /// # fn foo() -> u32 {
 /// let x: ! = {
 ///     return 123
@@ -200,6 +201,7 @@ mod prim_bool { }
 /// for example:
 ///
 /// ```
+/// #![feature(never_type)]
 /// # use std::fmt;
 /// # trait Debug {
 /// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
@@ -237,7 +239,7 @@ mod prim_bool { }
 /// [`Default`]: default/trait.Default.html
 /// [`default()`]: default/trait.Default.html#tymethod.default
 ///
-#[stable(feature = "never_type", since = "1.41.0")]
+#[unstable(feature = "never_type", issue = "35121")]
 mod prim_never { }
 
 #[doc(primitive = "char")]
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index e8e395247f9..61c4d0c2dbf 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -188,6 +188,7 @@ struct WaiterQueue<'a> {
 impl Once {
     /// Creates a new `Once` value.
     #[stable(feature = "once_new", since = "1.2.0")]
+    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
     pub const fn new() -> Once {
         Once { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: marker::PhantomData }
     }
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index cd26c7ca200..a3e059e8131 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -104,6 +104,36 @@ IMAGE_BASE:
         and %gs:tcsls_flags,%\reg
 .endm
 
+/* We place the ELF entry point in a separate section so it can be removed by
+   elf2sgxs */
+.section .text_no_sgx, "ax"
+.Lelf_entry_error_msg:
+    .ascii "Error: This file is an SGX enclave which cannot be executed as a standard Linux binary.\nSee the installation guide at https://edp.fortanix.com/docs/installation/guide/ on how to use 'cargo run' or follow the steps at https://edp.fortanix.com/docs/tasks/deployment/ for manual deployment.\n"
+.Lelf_entry_error_msg_end:
+
+.global elf_entry
+.type elf_entry,function
+elf_entry:
+/* print error message */
+    movq $2,%rdi                      /* write to stderr (fd 2) */
+    lea .Lelf_entry_error_msg(%rip),%rsi
+    movq $.Lelf_entry_error_msg_end-.Lelf_entry_error_msg,%rdx
+.Lelf_entry_call:
+    movq $1,%rax                      /* write() syscall        */
+    syscall
+    test %rax,%rax
+    jle .Lelf_exit                    /* exit on error          */
+    add %rax,%rsi
+    sub %rax,%rdx                     /* all chars written?     */
+    jnz .Lelf_entry_call
+
+.Lelf_exit:    
+    movq $60,%rax                     /* exit() syscall         */
+    movq $1,%rdi                      /* exit code 1            */
+    syscall
+    ud2                               /* should not be reached  */
+/*  end elf_entry */
+
 .text
 .global sgx_entry
 .type sgx_entry,function
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index 946b2b9d8de..4c23aabf497 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -18,24 +18,6 @@ pub extern crate libc as netc;
 
 pub type wrlen_t = size_t;
 
-// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on
-// Linux currently (e.g., support doesn't exist on other platforms). In order to
-// get name resolution to work and things to compile we just define a dummy
-// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't
-// actually ever used (the blocks below are wrapped in `if cfg!` as well.
-#[cfg(target_os = "linux")]
-use libc::SOCK_CLOEXEC;
-#[cfg(not(target_os = "linux"))]
-const SOCK_CLOEXEC: c_int = 0;
-
-// Another conditional constant for name resolution: Macos et iOS use
-// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
-// Other platforms do otherwise.
-#[cfg(target_vendor = "apple")]
-use libc::SO_NOSIGPIPE;
-#[cfg(not(target_vendor = "apple"))]
-const SO_NOSIGPIPE: c_int = 0;
-
 pub struct Socket(FileDesc);
 
 pub fn init() {}
@@ -77,8 +59,9 @@ impl Socket {
             // this option, however, was added in 2.6.27, and we still support
             // 2.6.18 as a kernel, so if the returned error is EINVAL we
             // fallthrough to the fallback.
-            if cfg!(target_os = "linux") {
-                match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
+            #[cfg(target_os = "linux")]
+            {
+                match cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0)) {
                     Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
                     Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
                     Err(e) => return Err(e),
@@ -89,9 +72,12 @@ impl Socket {
             let fd = FileDesc::new(fd);
             fd.set_cloexec()?;
             let socket = Socket(fd);
-            if cfg!(target_vendor = "apple") {
-                setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?;
-            }
+
+            // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
+            // flag to disable `SIGPIPE` emission on socket.
+            #[cfg(target_vendor = "apple")]
+            setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
+
             Ok(socket)
         }
     }
@@ -101,8 +87,9 @@ impl Socket {
             let mut fds = [0, 0];
 
             // Like above, see if we can set cloexec atomically
-            if cfg!(target_os = "linux") {
-                match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
+            #[cfg(target_os = "linux")]
+            {
+                match cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
                     Ok(_) => {
                         return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
                     }
@@ -192,7 +179,8 @@ impl Socket {
         // atomically set the CLOEXEC flag is to use the `accept4` syscall on
         // Linux. This was added in 2.6.28, however, and because we support
         // 2.6.18 we must detect this support dynamically.
-        if cfg!(target_os = "linux") {
+        #[cfg(target_os = "linux")]
+        {
             syscall! {
                 fn accept4(
                     fd: c_int,
@@ -201,7 +189,7 @@ impl Socket {
                     flags: c_int
                 ) -> c_int
             }
-            let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, SOCK_CLOEXEC) });
+            let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) });
             match res {
                 Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
                 Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs
index c9109b0c9d4..e66d6fdc56a 100644
--- a/src/libstd/sys/unix/process/process_common.rs
+++ b/src/libstd/sys/unix/process/process_common.rs
@@ -375,8 +375,12 @@ impl ChildStdio {
 
 impl fmt::Debug for Command {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.program)?;
-        for arg in &self.args {
+        if self.program != self.args[0] {
+            write!(f, "[{:?}] ", self.program)?;
+        }
+        write!(f, "{:?}", self.args[0])?;
+
+        for arg in &self.args[1..] {
             write!(f, " {:?}", arg)?;
         }
         Ok(())
diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs
index 85f5fcff2c2..74cbd246fe8 100644
--- a/src/libstd/sys/vxworks/net.rs
+++ b/src/libstd/sys/vxworks/net.rs
@@ -18,9 +18,6 @@ pub extern crate libc as netc;
 
 pub type wrlen_t = size_t;
 
-const SOCK_CLOEXEC: c_int = 0;
-const SO_NOSIGPIPE: c_int = 0;
-
 pub struct Socket(FileDesc);
 
 pub fn init() {}
diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs
index fad092e35c3..04bfdf67e12 100644
--- a/src/libstd/sys/wasi/fs.rs
+++ b/src/libstd/sys/wasi/fs.rs
@@ -364,7 +364,7 @@ impl OpenOptions {
 
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        let (dir, file) = open_parent(path, wasi::RIGHTS_PATH_OPEN)?;
+        let (dir, file) = open_parent(path)?;
         open_at(&dir, &file, opts)
     }
 
@@ -452,7 +452,7 @@ impl DirBuilder {
     }
 
     pub fn mkdir(&self, p: &Path) -> io::Result<()> {
-        let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_CREATE_DIRECTORY)?;
+        let (dir, file) = open_parent(p)?;
         dir.create_directory(osstr2str(file.as_ref())?)
     }
 }
@@ -478,13 +478,13 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
-    let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_UNLINK_FILE)?;
+    let (dir, file) = open_parent(p)?;
     dir.unlink_file(osstr2str(file.as_ref())?)
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    let (old, old_file) = open_parent(old, wasi::RIGHTS_PATH_RENAME_SOURCE)?;
-    let (new, new_file) = open_parent(new, wasi::RIGHTS_PATH_RENAME_TARGET)?;
+    let (old, old_file) = open_parent(old)?;
+    let (new, new_file) = open_parent(new)?;
     old.rename(osstr2str(old_file.as_ref())?, &new, osstr2str(new_file.as_ref())?)
 }
 
@@ -495,12 +495,12 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
-    let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_REMOVE_DIRECTORY)?;
+    let (dir, file) = open_parent(p)?;
     dir.remove_directory(osstr2str(file.as_ref())?)
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_READLINK)?;
+    let (dir, file) = open_parent(p)?;
     read_link(&dir, &file)
 }
 
@@ -536,13 +536,13 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
-    let (dst, dst_file) = open_parent(dst, wasi::RIGHTS_PATH_SYMLINK)?;
+    let (dst, dst_file) = open_parent(dst)?;
     dst.symlink(osstr2str(src.as_ref())?, osstr2str(dst_file.as_ref())?)
 }
 
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
-    let (src, src_file) = open_parent(src, wasi::RIGHTS_PATH_LINK_SOURCE)?;
-    let (dst, dst_file) = open_parent(dst, wasi::RIGHTS_PATH_LINK_TARGET)?;
+    let (src, src_file) = open_parent(src)?;
+    let (dst, dst_file) = open_parent(dst)?;
     src.link(
         wasi::LOOKUPFLAGS_SYMLINK_FOLLOW,
         osstr2str(src_file.as_ref())?,
@@ -552,12 +552,12 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_FILESTAT_GET)?;
+    let (dir, file) = open_parent(p)?;
     metadata_at(&dir, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW, &file)
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    let (dir, file) = open_parent(p, wasi::RIGHTS_PATH_FILESTAT_GET)?;
+    let (dir, file) = open_parent(p)?;
     metadata_at(&dir, 0, &file)
 }
 
@@ -611,11 +611,11 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
 ///
 /// Note that this can fail if `p` doesn't look like it can be opened relative
 /// to any preopened file descriptor.
-fn open_parent(p: &Path, rights: wasi::Rights) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
+fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
     let p = CString::new(p.as_os_str().as_bytes())?;
     unsafe {
         let mut ret = ptr::null();
-        let fd = libc::__wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
+        let fd = __wasilibc_find_relpath(p.as_ptr(), &mut ret);
         if fd == -1 {
             let msg = format!(
                 "failed to find a preopened file descriptor \
@@ -635,6 +635,13 @@ fn open_parent(p: &Path, rights: wasi::Rights) -> io::Result<(ManuallyDrop<WasiF
 
         return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path));
     }
+
+    extern "C" {
+        pub fn __wasilibc_find_relpath(
+            path: *const libc::c_char,
+            relative_path: *mut *const libc::c_char,
+        ) -> libc::c_int;
+    }
 }
 
 pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 92ba071a03d..cf54fd2887a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -254,7 +254,7 @@ pub struct ParenthesizedArgs {
     pub inputs: Vec<P<Ty>>,
 
     /// `C`
-    pub output: Option<P<Ty>>,
+    pub output: FunctionRetTy,
 }
 
 impl ParenthesizedArgs {
@@ -728,13 +728,13 @@ impl Mutability {
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 #[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
 pub enum BorrowKind {
-    /// A raw borrow, `&raw const $expr` or `&raw mut $expr`.
-    /// The resulting type is either `*const T` or `*mut T`
-    /// where `T = typeof($expr)`.
-    Ref,
     /// A normal borrow, `&$expr` or `&mut $expr`.
     /// The resulting type is either `&'a T` or `&'a mut T`
     /// where `T = typeof($expr)` and `'a` is some lifetime.
+    Ref,
+    /// A raw borrow, `&raw const $expr` or `&raw mut $expr`.
+    /// The resulting type is either `*const T` or `*mut T`
+    /// where `T = typeof($expr)`.
     Raw,
 }
 
@@ -1603,54 +1603,43 @@ pub struct FnSig {
     pub decl: P<FnDecl>,
 }
 
-/// Represents an item declaration within a trait declaration,
-/// possibly including a default implementation. A trait item is
-/// either required (meaning it doesn't have an implementation, just a
-/// signature) or provided (meaning it has a default implementation).
+/// Represents associated items.
+/// These include items in `impl` and `trait` definitions.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct TraitItem {
+pub struct AssocItem {
     pub attrs: Vec<Attribute>,
     pub id: NodeId,
     pub span: Span,
     pub vis: Visibility,
     pub ident: Ident,
 
+    pub defaultness: Defaultness,
     pub generics: Generics,
-    pub kind: TraitItemKind,
+    pub kind: AssocItemKind,
     /// See `Item::tokens` for what this is.
     pub tokens: Option<TokenStream>,
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum TraitItemKind {
+/// Represents various kinds of content within an `impl`.
+///
+/// The term "provided" in the variants below refers to the item having a default
+/// definition / body. Meanwhile, a "required" item lacks a definition / body.
+/// In an implementation, all items must be provided.
+/// The `Option`s below denote the bodies, where `Some(_)`
+/// means "provided" and conversely `None` means "required".
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum AssocItemKind  {
+    /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
+    /// If `def` is parsed, then the associated constant is provided, and otherwise required.
     Const(P<Ty>, Option<P<Expr>>),
-    Method(FnSig, Option<P<Block>>),
-    Type(GenericBounds, Option<P<Ty>>),
-    Macro(Mac),
-}
 
-/// Represents anything within an `impl` block.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct ImplItem {
-    pub attrs: Vec<Attribute>,
-    pub id: NodeId,
-    pub span: Span,
-    pub vis: Visibility,
-    pub ident: Ident,
+    /// An associated function.
+    Fn(FnSig, Option<P<Block>>),
 
-    pub defaultness: Defaultness,
-    pub generics: Generics,
-    pub kind: ImplItemKind,
-    /// See `Item::tokens` for what this is.
-    pub tokens: Option<TokenStream>,
-}
+    /// An associated type.
+    TyAlias(GenericBounds, Option<P<Ty>>),
 
-/// Represents various kinds of content within an `impl`.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum ImplItemKind {
-    Const(P<Ty>, P<Expr>),
-    Method(FnSig, P<Block>),
-    TyAlias(P<Ty>),
+    /// A macro expanding to an associated item.
     Macro(Mac),
 }
 
@@ -2189,7 +2178,7 @@ impl fmt::Debug for ImplPolarity {
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum FunctionRetTy {
+pub enum FunctionRetTy { // FIXME(Centril): Rename to `FnRetTy` and in HIR also.
     /// Returns type is not specified.
     ///
     /// Functions default to `()` and closures default to inference.
@@ -2602,7 +2591,7 @@ pub enum ItemKind {
     /// A trait declaration (`trait`).
     ///
     /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
-    Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<TraitItem>),
+    Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<AssocItem>),
     /// Trait alias
     ///
     /// E.g., `trait Foo = Bar + Quux;`.
@@ -2617,7 +2606,7 @@ pub enum ItemKind {
         Generics,
         Option<TraitRef>, // (optional) trait this impl implements
         P<Ty>,            // self
-        Vec<ImplItem>,
+        Vec<AssocItem>,
     ),
     /// A macro invocation.
     ///
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 3c10f27b60a..a37b27f67bc 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -120,17 +120,21 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
     })
 }
 
-/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
+/// Represents the #[stable], #[unstable], #[rustc_deprecated] attributes.
 #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug,
          PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
     pub rustc_depr: Option<RustcDeprecation>,
-    /// `None` means the function is stable but needs to be a stable const fn, too
-    /// `Some` contains the feature gate required to be able to use the function
-    /// as const fn
-    pub const_stability: Option<Symbol>,
+}
+
+/// Represents the #[rustc_const_unstable] and #[rustc_const_stable] attributes.
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug,
+         PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct ConstStability {
+    pub level: StabilityLevel,
+    pub feature: Symbol,
     /// whether the function has a `#[rustc_promotable]` attribute
     pub promotable: bool,
     /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute
@@ -186,21 +190,21 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool
 /// Collects stability info from all stability attributes in `attrs`.
 /// Returns `None` if no stability attributes are found.
 pub fn find_stability(sess: &ParseSess, attrs: &[Attribute],
-                      item_sp: Span) -> Option<Stability> {
+                      item_sp: Span) -> (Option<Stability>, Option<ConstStability>) {
     find_stability_generic(sess, attrs.iter(), item_sp)
 }
 
 fn find_stability_generic<'a, I>(sess: &ParseSess,
                                  attrs_iter: I,
                                  item_sp: Span)
-                                 -> Option<Stability>
+                                 -> (Option<Stability>, Option<ConstStability>)
     where I: Iterator<Item = &'a Attribute>
 {
     use StabilityLevel::*;
 
     let mut stab: Option<Stability> = None;
     let mut rustc_depr: Option<RustcDeprecation> = None;
-    let mut rustc_const_unstable: Option<Symbol> = None;
+    let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
     let mut allow_const_fn_ptr = false;
     let diagnostic = &sess.span_diagnostic;
@@ -209,6 +213,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
         if ![
             sym::rustc_deprecated,
             sym::rustc_const_unstable,
+            sym::rustc_const_stable,
             sym::unstable,
             sym::stable,
             sym::rustc_promotable,
@@ -287,7 +292,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                 }
             }
 
-            match meta.name_or_empty() {
+            let meta_name = meta.name_or_empty();
+            match meta_name {
                 sym::rustc_deprecated => {
                     if rustc_depr.is_some() {
                         span_err!(diagnostic, item_sp, E0540,
@@ -315,23 +321,12 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         }
                     }
                 }
-                sym::rustc_const_unstable => {
-                    if rustc_const_unstable.is_some() {
-                        span_err!(diagnostic, item_sp, E0553,
-                                  "multiple rustc_const_unstable attributes");
-                        continue 'outer
-                    }
-
-                    get_meta!(feature);
-                    if let Some(feature) = feature {
-                        rustc_const_unstable = Some(feature);
-                    } else {
-                        span_err!(diagnostic, attr.span, E0629, "missing 'feature'");
-                        continue
-                    }
-                }
+                sym::rustc_const_unstable |
                 sym::unstable => {
-                    if stab.is_some() {
+                    if meta_name == sym::unstable && stab.is_some() {
+                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        break
+                    } else if meta_name == sym::rustc_const_unstable && const_stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
                         break
                     }
@@ -398,18 +393,25 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                                     }
                                 }
                             };
-                            stab = Some(Stability {
-                                level: Unstable {
-                                    reason,
-                                    issue,
-                                    is_soft,
-                                },
-                                feature,
-                                rustc_depr: None,
-                                const_stability: None,
-                                promotable: false,
-                                allow_const_fn_ptr: false,
-                            })
+                            let level = Unstable {
+                                reason,
+                                issue,
+                                is_soft,
+                            };
+                            if sym::unstable == meta_name {
+                                stab = Some(Stability {
+                                    level,
+                                    feature,
+                                    rustc_depr: None,
+                                });
+                            } else {
+                                const_stab = Some(ConstStability {
+                                    level,
+                                    feature,
+                                    promotable: false,
+                                    allow_const_fn_ptr: false,
+                                });
+                            }
                         }
                         (None, _, _) => {
                             handle_errors(sess, attr.span, AttrError::MissingFeature);
@@ -421,8 +423,12 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         }
                     }
                 }
+                sym::rustc_const_stable |
                 sym::stable => {
-                    if stab.is_some() {
+                    if meta_name == sym::stable && stab.is_some() {
+                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        break
+                    } else if meta_name == sym::rustc_const_stable &&const_stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
                         break
                     }
@@ -464,16 +470,21 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
 
                     match (feature, since) {
                         (Some(feature), Some(since)) => {
-                            stab = Some(Stability {
-                                level: Stable {
-                                    since,
-                                },
-                                feature,
-                                rustc_depr: None,
-                                const_stability: None,
-                                promotable: false,
-                                allow_const_fn_ptr: false,
-                            })
+                            let level =  Stable { since };
+                            if sym::stable == meta_name {
+                                stab = Some(Stability {
+                                    level,
+                                    feature,
+                                    rustc_depr: None,
+                                });
+                            } else {
+                                const_stab = Some(ConstStability {
+                                    level,
+                                    feature,
+                                    promotable: false,
+                                    allow_const_fn_ptr: false,
+                                });
+                            }
                         }
                         (None, _) => {
                             handle_errors(sess, attr.span, AttrError::MissingFeature);
@@ -502,29 +513,19 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
     }
 
     // Merge the const-unstable info into the stability info
-    if let Some(feature) = rustc_const_unstable {
-        if let Some(ref mut stab) = stab {
-            stab.const_stability = Some(feature);
-        } else {
-            span_err!(diagnostic, item_sp, E0630,
-                      "rustc_const_unstable attribute must be paired with \
-                       either stable or unstable attribute");
-        }
-    }
-
-    // Merge the const-unstable info into the stability info
     if promotable || allow_const_fn_ptr {
-        if let Some(ref mut stab) = stab {
+        if let Some(ref mut stab) = const_stab {
             stab.promotable = promotable;
             stab.allow_const_fn_ptr = allow_const_fn_ptr;
         } else {
             span_err!(diagnostic, item_sp, E0717,
                       "rustc_promotable and rustc_allow_const_fn_ptr attributes \
-                      must be paired with either stable or unstable attribute");
+                      must be paired with either a rustc_const_unstable or a rustc_const_stable \
+                      attribute");
         }
     }
 
-    stab
+    (stab, const_stab)
 }
 
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index 079a0f6fafa..13a9ed5f215 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -749,6 +749,6 @@ macro_rules! derive_has_attrs {
 }
 
 derive_has_attrs! {
-    Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
+    Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::AssocItem, ast::Arm,
     ast::Field, ast::FieldPat, ast::Variant, ast::Param
 }
diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs
index 3d2c3b1d4f9..aacd14c3af7 100644
--- a/src/libsyntax/feature_gate/check.rs
+++ b/src/libsyntax/feature_gate/check.rs
@@ -464,11 +464,25 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::TyKind::BareFn(ref bare_fn_ty) => {
                 self.check_extern(bare_fn_ty.ext);
             }
+            ast::TyKind::Never => {
+                gate_feature_post!(&self, never_type, ty.span,
+                                   "The `!` type is experimental");
+            }
             _ => {}
         }
         visit::walk_ty(self, ty)
     }
 
+    fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
+        if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
+            if let ast::TyKind::Never = output_ty.kind {
+                // Do nothing.
+            } else {
+                self.visit_ty(output_ty)
+            }
+        }
+    }
+
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         match e.kind {
             ast::ExprKind::Box(_) => {
@@ -499,6 +513,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_expr(self, e)
     }
 
+    fn visit_arm(&mut self, arm: &'a ast::Arm) {
+        visit::walk_arm(self, arm)
+    }
+
     fn visit_pat(&mut self, pattern: &'a ast::Pat) {
         match &pattern.kind {
             PatKind::Slice(pats) => {
@@ -571,54 +589,52 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_assoc_ty_constraint(self, constraint)
     }
 
-    fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
         match ti.kind {
-            ast::TraitItemKind::Method(ref sig, ref block) => {
+            ast::AssocItemKind::Fn(ref sig, ref block) => {
                 if block.is_none() {
                     self.check_extern(sig.header.ext);
                 }
-                if sig.decl.c_variadic() {
-                    gate_feature_post!(&self, c_variadic, ti.span,
-                                       "C-variadic functions are unstable");
-                }
                 if sig.header.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
                 }
             }
-            ast::TraitItemKind::Type(_, ref default) => {
-                if let Some(ty) = default {
-                    self.check_impl_trait(ty);
-                    gate_feature_post!(&self, associated_type_defaults, ti.span,
-                                       "associated type defaults are unstable");
+            ast::AssocItemKind::TyAlias(_, ref default) => {
+                if let Some(_) = default {
+                    gate_feature_post!(
+                        &self, associated_type_defaults, ti.span,
+                        "associated type defaults are unstable"
+                    );
                 }
-                self.check_gat(&ti.generics, ti.span);
             }
             _ => {}
         }
         visit::walk_trait_item(self, ti)
     }
 
-    fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) {
+    fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
         if ii.defaultness == ast::Defaultness::Default {
-            gate_feature_post!(&self, specialization,
-                              ii.span,
-                              "specialization is unstable");
+            gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
         }
 
         match ii.kind {
-            ast::ImplItemKind::Method(ref sig, _) => {
+            ast::AssocItemKind::Fn(ref sig, _) => {
                 if sig.decl.c_variadic() {
-                    gate_feature_post!(&self, c_variadic, ii.span,
-                                       "C-variadic functions are unstable");
+                    gate_feature_post!(
+                        &self, c_variadic, ii.span,
+                        "C-variadic functions are unstable"
+                    );
                 }
             }
-            ast::ImplItemKind::TyAlias(ref ty) => {
-                self.check_impl_trait(ty);
+            ast::AssocItemKind::TyAlias(_, ref ty) => {
+                if let Some(ty) = ty {
+                    self.check_impl_trait(ty);
+                }
                 self.check_gat(&ii.generics, ii.span);
             }
             _ => {}
         }
-        visit::walk_impl_item(self, ii)
+        visit::walk_assoc_item(self, ii)
     }
 
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index f8795d885d2..2a6cff5971c 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -103,12 +103,12 @@ pub trait MutVisitor: Sized {
         noop_visit_item_kind(i, self);
     }
 
-    fn flat_map_trait_item(&mut self, i: TraitItem) -> SmallVec<[TraitItem; 1]> {
-        noop_flat_map_trait_item(i, self)
+    fn flat_map_trait_item(&mut self, i: AssocItem) -> SmallVec<[AssocItem; 1]> {
+        noop_flat_map_assoc_item(i, self)
     }
 
-    fn flat_map_impl_item(&mut self, i: ImplItem) -> SmallVec<[ImplItem; 1]> {
-        noop_flat_map_impl_item(i, self)
+    fn flat_map_impl_item(&mut self, i: AssocItem) -> SmallVec<[AssocItem; 1]> {
+        noop_flat_map_assoc_item(i, self)
     }
 
     fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
@@ -553,7 +553,7 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(args: &mut Parenth
                                                               vis: &mut T) {
     let ParenthesizedArgs { inputs, output, span } = args;
     visit_vec(inputs, |input| vis.visit_ty(input));
-    visit_opt(output, |output| vis.visit_ty(output));
+    noop_visit_fn_ret_ty(output, vis);
     vis.visit_span(span);
 }
 
@@ -742,7 +742,11 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
 pub fn noop_visit_fn_decl<T: MutVisitor>(decl: &mut P<FnDecl>, vis: &mut T) {
     let FnDecl { inputs, output } = decl.deref_mut();
     inputs.flat_map_in_place(|param| vis.flat_map_param(param));
-    match output {
+    noop_visit_fn_ret_ty(output, vis);
+}
+
+pub fn noop_visit_fn_ret_ty<T: MutVisitor>(fn_ret_ty: &mut FunctionRetTy, vis: &mut T) {
+    match fn_ret_ty {
         FunctionRetTy::Default(span) => vis.visit_span(span),
         FunctionRetTy::Ty(ty) => vis.visit_ty(ty),
     }
@@ -936,58 +940,30 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
     }
 }
 
-pub fn noop_flat_map_trait_item<T: MutVisitor>(mut item: TraitItem, visitor: &mut T)
-    -> SmallVec<[TraitItem; 1]>
+pub fn noop_flat_map_assoc_item<T: MutVisitor>(mut item: AssocItem, visitor: &mut T)
+    -> SmallVec<[AssocItem; 1]>
 {
-    let TraitItem { id, ident, vis, attrs, generics, kind, span, tokens: _ } = &mut item;
+    let AssocItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } =
+        &mut item;
     visitor.visit_id(id);
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
     visit_attrs(attrs, visitor);
     visitor.visit_generics(generics);
-    match kind {
-        TraitItemKind::Const(ty, default) => {
+    match kind  {
+        AssocItemKind::Const(ty, expr) => {
             visitor.visit_ty(ty);
-            visit_opt(default, |default| visitor.visit_expr(default));
+            visit_opt(expr, |expr| visitor.visit_expr(expr));
         }
-        TraitItemKind::Method(sig, body) => {
+        AssocItemKind::Fn(sig, body) => {
             visit_fn_sig(sig, visitor);
             visit_opt(body, |body| visitor.visit_block(body));
         }
-        TraitItemKind::Type(bounds, default) => {
+        AssocItemKind::TyAlias(bounds, ty) => {
             visit_bounds(bounds, visitor);
-            visit_opt(default, |default| visitor.visit_ty(default));
-        }
-        TraitItemKind::Macro(mac) => {
-            visitor.visit_mac(mac);
-        }
-    }
-    visitor.visit_span(span);
-
-    smallvec![item]
-}
-
-pub fn noop_flat_map_impl_item<T: MutVisitor>(mut item: ImplItem, visitor: &mut T)
-                                              -> SmallVec<[ImplItem; 1]>
-{
-    let ImplItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } =
-        &mut item;
-    visitor.visit_id(id);
-    visitor.visit_ident(ident);
-    visitor.visit_vis(vis);
-    visit_attrs(attrs, visitor);
-    visitor.visit_generics(generics);
-    match kind  {
-        ImplItemKind::Const(ty, expr) => {
-            visitor.visit_ty(ty);
-            visitor.visit_expr(expr);
-        }
-        ImplItemKind::Method(sig, body) => {
-            visit_fn_sig(sig, visitor);
-            visitor.visit_block(body);
+            visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
-        ImplItemKind::TyAlias(ty) => visitor.visit_ty(ty),
-        ImplItemKind::Macro(mac) => visitor.visit_mac(mac),
+        AssocItemKind::Macro(mac) => visitor.visit_mac(mac),
     }
     visitor.visit_span(span);
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index f0c5fb32fb1..87f6ae85b69 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -335,8 +335,8 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
         token::NtLifetime(e)        => e.to_string(),
         token::NtLiteral(ref e)     => expr_to_string(e),
         token::NtTT(ref tree)       => tt_to_string(tree.clone()),
-        token::NtImplItem(ref e)    => impl_item_to_string(e),
-        token::NtTraitItem(ref e)   => trait_item_to_string(e),
+        // FIXME(Centril): merge these variants.
+        token::NtImplItem(ref e) | token::NtTraitItem(ref e) => assoc_item_to_string(e),
         token::NtVis(ref e)         => vis_to_string(e),
         token::NtForeignItem(ref e) => foreign_item_to_string(e),
     }
@@ -374,12 +374,8 @@ pub fn item_to_string(i: &ast::Item) -> String {
     to_string(|s| s.print_item(i))
 }
 
-fn impl_item_to_string(i: &ast::ImplItem) -> String {
-    to_string(|s| s.print_impl_item(i))
-}
-
-fn trait_item_to_string(i: &ast::TraitItem) -> String {
-    to_string(|s| s.print_trait_item(i))
+fn assoc_item_to_string(i: &ast::AssocItem) -> String {
+    to_string(|s| s.print_assoc_item(i))
 }
 
 pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
@@ -887,17 +883,9 @@ impl<'a> PrintState<'a> for State<'a> {
 
             ast::GenericArgs::Parenthesized(ref data) => {
                 self.s.word("(");
-                self.commasep(
-                    Inconsistent,
-                    &data.inputs,
-                    |s, ty| s.print_type(ty));
+                self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
                 self.s.word(")");
-
-                if let Some(ref ty) = data.output {
-                    self.space_if_not_bol();
-                    self.word_space("->");
-                    self.print_type(ty);
-                }
+                self.print_fn_ret_ty(&data.output);
             }
         }
     }
@@ -1128,16 +1116,15 @@ impl<'a> State<'a> {
         self.s.word(";")
     }
 
-    fn print_associated_type(&mut self,
-                             ident: ast::Ident,
-                             bounds: Option<&ast::GenericBounds>,
-                             ty: Option<&ast::Ty>)
-                             {
+    fn print_associated_type(
+        &mut self,
+        ident: ast::Ident,
+        bounds: &ast::GenericBounds,
+        ty: Option<&ast::Ty>,
+    ) {
         self.word_space("type");
         self.print_ident(ident);
-        if let Some(bounds) = bounds {
-            self.print_type_bounds(":", bounds);
-        }
+        self.print_type_bounds(":", bounds);
         if let Some(ty) = ty {
             self.s.space();
             self.word_space("=");
@@ -1310,7 +1297,7 @@ impl<'a> State<'a> {
                 self.bopen();
                 self.print_inner_attributes(&item.attrs);
                 for impl_item in impl_items {
-                    self.print_impl_item(impl_item);
+                    self.print_assoc_item(impl_item);
                 }
                 self.bclose(item.span);
             }
@@ -1337,7 +1324,7 @@ impl<'a> State<'a> {
                 self.s.word(" ");
                 self.bopen();
                 for trait_item in trait_items {
-                    self.print_trait_item(trait_item);
+                    self.print_assoc_item(trait_item);
                 }
                 self.bclose(item.span);
             }
@@ -1531,92 +1518,39 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_method_sig(&mut self,
-                            ident: ast::Ident,
-                            generics: &ast::Generics,
-                            m: &ast::FnSig,
-                            vis: &ast::Visibility)
-                            {
-        self.print_fn(&m.decl,
-                      m.header,
-                      Some(ident),
-                      &generics,
-                      vis)
-    }
-
-    crate fn print_trait_item(&mut self, ti: &ast::TraitItem)
-                            {
-        self.ann.pre(self, AnnNode::SubItem(ti.id));
+    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+        self.ann.pre(self, AnnNode::SubItem(item.id));
         self.hardbreak_if_not_bol();
-        self.maybe_print_comment(ti.span.lo());
-        self.print_outer_attributes(&ti.attrs);
-        match ti.kind {
-            ast::TraitItemKind::Const(ref ty, ref default) => {
-                self.print_associated_const(
-                    ti.ident,
-                    ty,
-                    default.as_ref().map(|expr| &**expr),
-                    &source_map::respan(ti.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
-                );
+        self.maybe_print_comment(item.span.lo());
+        self.print_outer_attributes(&item.attrs);
+        self.print_defaultness(item.defaultness);
+        match &item.kind {
+            ast::AssocItemKind::Const(ty, expr) => {
+                self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
             }
-            ast::TraitItemKind::Method(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(sig, body) => {
                 if body.is_some() {
                     self.head("");
                 }
-                self.print_method_sig(
-                    ti.ident,
-                    &ti.generics,
-                    sig,
-                    &source_map::respan(ti.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
-                );
-                if let Some(ref body) = *body {
+                self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis);
+                if let Some(body) = body {
                     self.nbsp();
-                    self.print_block_with_attrs(body, &ti.attrs);
+                    self.print_block_with_attrs(body, &item.attrs);
                 } else {
                     self.s.word(";");
                 }
             }
-            ast::TraitItemKind::Type(ref bounds, ref default) => {
-                self.print_associated_type(ti.ident, Some(bounds),
-                                           default.as_ref().map(|ty| &**ty));
+            ast::AssocItemKind::TyAlias(bounds, ty) => {
+                self.print_associated_type(item.ident, bounds, ty.as_deref());
             }
-            ast::TraitItemKind::Macro(ref mac) => {
+            ast::AssocItemKind::Macro(mac) => {
                 self.print_mac(mac);
                 if mac.args.need_semicolon() {
                     self.s.word(";");
                 }
             }
         }
-        self.ann.post(self, AnnNode::SubItem(ti.id))
-    }
-
-    crate fn print_impl_item(&mut self, ii: &ast::ImplItem) {
-        self.ann.pre(self, AnnNode::SubItem(ii.id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(ii.span.lo());
-        self.print_outer_attributes(&ii.attrs);
-        self.print_defaultness(ii.defaultness);
-        match ii.kind {
-            ast::ImplItemKind::Const(ref ty, ref expr) => {
-                self.print_associated_const(ii.ident, ty, Some(expr), &ii.vis);
-            }
-            ast::ImplItemKind::Method(ref sig, ref body) => {
-                self.head("");
-                self.print_method_sig(ii.ident, &ii.generics, sig, &ii.vis);
-                self.nbsp();
-                self.print_block_with_attrs(body, &ii.attrs);
-            }
-            ast::ImplItemKind::TyAlias(ref ty) => {
-                self.print_associated_type(ii.ident, None, Some(ty));
-            }
-            ast::ImplItemKind::Macro(ref mac) => {
-                self.print_mac(mac);
-                if mac.args.need_semicolon() {
-                    self.s.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(ii.id))
+        self.ann.post(self, AnnNode::SubItem(item.id))
     }
 
     crate fn print_stmt(&mut self, st: &ast::Stmt) {
@@ -2109,7 +2043,7 @@ impl<'a> State<'a> {
                 self.print_asyncness(asyncness);
                 self.print_capture_clause(capture_clause);
 
-                self.print_fn_block_params(decl);
+                self.print_fn_params_and_ret(decl, true);
                 self.s.space();
                 self.print_expr(body);
                 self.end(); // need to close a box
@@ -2540,36 +2474,16 @@ impl<'a> State<'a> {
             self.print_ident(name);
         }
         self.print_generic_params(&generics.params);
-        self.print_fn_params_and_ret(decl);
+        self.print_fn_params_and_ret(decl, false);
         self.print_where_clause(&generics.where_clause)
     }
 
-    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl) {
-        self.popen();
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, false));
-        self.pclose();
-
-        self.print_fn_output(decl)
-    }
-
-    crate fn print_fn_block_params(&mut self, decl: &ast::FnDecl) {
-        self.s.word("|");
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, true));
-        self.s.word("|");
-
-        if let ast::FunctionRetTy::Default(..) = decl.output {
-            return;
-        }
-
-        self.space_if_not_bol();
-        self.word_space("->");
-        match decl.output {
-            ast::FunctionRetTy::Ty(ref ty) => {
-                self.print_type(ty);
-                self.maybe_print_comment(ty.span.lo())
-            }
-            ast::FunctionRetTy::Default(..) => unreachable!(),
-        }
+    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+        self.word(open);
+        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+        self.word(close);
+        self.print_fn_ret_ty(&decl.output)
     }
 
     crate fn print_movability(&mut self, movability: ast::Movability) {
@@ -2791,24 +2705,14 @@ impl<'a> State<'a> {
         self.end();
     }
 
-    crate fn print_fn_output(&mut self, decl: &ast::FnDecl) {
-        if let ast::FunctionRetTy::Default(..) = decl.output {
-            return;
-        }
-
-        self.space_if_not_bol();
-        self.ibox(INDENT_UNIT);
-        self.word_space("->");
-        match decl.output {
-            ast::FunctionRetTy::Default(..) => unreachable!(),
-            ast::FunctionRetTy::Ty(ref ty) =>
-                self.print_type(ty),
-        }
-        self.end();
-
-        match decl.output {
-            ast::FunctionRetTy::Ty(ref output) => self.maybe_print_comment(output.span.lo()),
-            _ => {}
+    crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FunctionRetTy) {
+        if let ast::FunctionRetTy::Ty(ty) = fn_ret_ty {
+            self.space_if_not_bol();
+            self.ibox(INDENT_UNIT);
+            self.word_space("->");
+            self.print_type(ty);
+            self.end();
+            self.maybe_print_comment(ty.span.lo());
         }
     }
 
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index d987dc855b6..e75cc8b1756 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -1,17 +1,12 @@
 //! The AST pointer.
 //!
-//! Provides `P<T>`, a frozen owned smart pointer, as a replacement for `@T` in
-//! the AST.
+//! Provides `P<T>`, a frozen owned smart pointer.
 //!
 //! # Motivations and benefits
 //!
 //! * **Identity**: sharing AST nodes is problematic for the various analysis
 //!   passes (e.g., one may be able to bypass the borrow checker with a shared
-//!   `ExprKind::AddrOf` node taking a mutable borrow). The only reason `@T` in the
-//!   AST hasn't caused issues is because of inefficient folding passes which
-//!   would always deduplicate any such shared nodes. Even if the AST were to
-//!   switch to an arena, this would still hold, i.e., it couldn't use `&'a T`,
-//!   but rather a wrapper like `P<'a, T>`.
+//!   `ExprKind::AddrOf` node taking a mutable borrow).
 //!
 //! * **Immutability**: `P<T>` disallows mutating its inner `T`, unlike `Box<T>`
 //!   (unless it contains an `Unsafe` interior, but that may be denied later).
diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs
index 6f45211ac5f..263f8192241 100644
--- a/src/libsyntax/token.rs
+++ b/src/libsyntax/token.rs
@@ -685,8 +685,8 @@ pub enum Nonterminal {
     // Used only for passing items to proc macro attributes (they are not
     // strictly necessary for that, `Annotatable` can be converted into
     // tokens directly, but doing that naively regresses pretty-printing).
-    NtTraitItem(ast::TraitItem),
-    NtImplItem(ast::ImplItem),
+    NtTraitItem(ast::AssocItem),
+    NtImplItem(ast::AssocItem),
     NtForeignItem(ast::ForeignItem),
 }
 
diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs
index a64fec70961..3db9955d304 100644
--- a/src/libsyntax/util/node_count.rs
+++ b/src/libsyntax/util/node_count.rs
@@ -73,13 +73,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_fn(self, fk, fd, s)
     }
-    fn visit_trait_item(&mut self, ti: &TraitItem) {
+    fn visit_assoc_item(&mut self, ti: &AssocItem) {
         self.count += 1;
-        walk_trait_item(self, ti)
-    }
-    fn visit_impl_item(&mut self, ii: &ImplItem) {
-        self.count += 1;
-        walk_impl_item(self, ii)
+        walk_assoc_item(self, ti)
     }
     fn visit_trait_ref(&mut self, t: &TraitRef) {
         self.count += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 4ee09b4b87a..51e7fa1eb38 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -25,7 +25,7 @@ pub enum FnKind<'a> {
     ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block),
 
     /// E.g., `fn foo(&self)`.
-    Method(Ident, &'a FnSig, Option<&'a Visibility>, &'a Block),
+    Method(Ident, &'a FnSig, &'a Visibility, &'a Block),
 
     /// E.g., `|x, y| body`.
     Closure(&'a Expr),
@@ -83,8 +83,9 @@ pub trait Visitor<'ast>: Sized {
     fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
         walk_fn(self, fk, fd, s)
     }
-    fn visit_trait_item(&mut self, ti: &'ast TraitItem) { walk_trait_item(self, ti) }
-    fn visit_impl_item(&mut self, ii: &'ast ImplItem) { walk_impl_item(self, ii) }
+    fn visit_trait_item(&mut self, i: &'ast AssocItem) { walk_trait_item(self, i) }
+    fn visit_impl_item(&mut self, i: &'ast AssocItem) { walk_impl_item(self, i) }
+    fn visit_assoc_item(&mut self, i: &'ast AssocItem) { walk_assoc_item(self, i) }
     fn visit_trait_ref(&mut self, t: &'ast TraitRef) { walk_trait_ref(self, t) }
     fn visit_param_bound(&mut self, bounds: &'ast GenericBound) {
         walk_param_bound(self, bounds)
@@ -420,7 +421,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V,
         }
         GenericArgs::Parenthesized(ref data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
-            walk_list!(visitor, visit_ty, &data.output);
+            walk_fn_ret_ty(visitor, &data.output);
         }
     }
 }
@@ -581,52 +582,37 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
     }
 }
 
-pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, trait_item: &'a TraitItem) {
-    visitor.visit_vis(&trait_item.vis);
-    visitor.visit_ident(trait_item.ident);
-    walk_list!(visitor, visit_attribute, &trait_item.attrs);
-    visitor.visit_generics(&trait_item.generics);
-    match trait_item.kind {
-        TraitItemKind::Const(ref ty, ref default) => {
+pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+    visitor.visit_assoc_item(item);
+}
+
+pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+    visitor.visit_assoc_item(item);
+}
+
+pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+    visitor.visit_vis(&item.vis);
+    visitor.visit_ident(item.ident);
+    walk_list!(visitor, visit_attribute, &item.attrs);
+    visitor.visit_generics(&item.generics);
+    match item.kind {
+        AssocItemKind::Const(ref ty, ref expr) => {
             visitor.visit_ty(ty);
-            walk_list!(visitor, visit_expr, default);
+            walk_list!(visitor, visit_expr, expr);
         }
-        TraitItemKind::Method(ref sig, None) => {
+        AssocItemKind::Fn(ref sig, None) => {
             visitor.visit_fn_header(&sig.header);
             walk_fn_decl(visitor, &sig.decl);
         }
-        TraitItemKind::Method(ref sig, Some(ref body)) => {
-            visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, body),
-                             &sig.decl, trait_item.span, trait_item.id);
+        AssocItemKind::Fn(ref sig, Some(ref body)) => {
+            visitor.visit_fn(FnKind::Method(item.ident, sig, &item.vis, body),
+                             &sig.decl, item.span, item.id);
         }
-        TraitItemKind::Type(ref bounds, ref default) => {
+        AssocItemKind::TyAlias(ref bounds, ref ty) => {
             walk_list!(visitor, visit_param_bound, bounds);
-            walk_list!(visitor, visit_ty, default);
-        }
-        TraitItemKind::Macro(ref mac) => {
-            visitor.visit_mac(mac);
-        }
-    }
-}
-
-pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, impl_item: &'a ImplItem) {
-    visitor.visit_vis(&impl_item.vis);
-    visitor.visit_ident(impl_item.ident);
-    walk_list!(visitor, visit_attribute, &impl_item.attrs);
-    visitor.visit_generics(&impl_item.generics);
-    match impl_item.kind {
-        ImplItemKind::Const(ref ty, ref expr) => {
-            visitor.visit_ty(ty);
-            visitor.visit_expr(expr);
-        }
-        ImplItemKind::Method(ref sig, ref body) => {
-            visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), body),
-                             &sig.decl, impl_item.span, impl_item.id);
-        }
-        ImplItemKind::TyAlias(ref ty) => {
-            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_ty, ty);
         }
-        ImplItemKind::Macro(ref mac) => {
+        AssocItemKind::Macro(ref mac) => {
             visitor.visit_mac(mac);
         }
     }
diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs
index a4449ca5b1d..75066a006bf 100644
--- a/src/libsyntax_expand/base.rs
+++ b/src/libsyntax_expand/base.rs
@@ -31,8 +31,8 @@ crate use syntax_pos::hygiene::MacroKind;
 #[derive(Debug,Clone)]
 pub enum Annotatable {
     Item(P<ast::Item>),
-    TraitItem(P<ast::TraitItem>),
-    ImplItem(P<ast::ImplItem>),
+    TraitItem(P<ast::AssocItem>),
+    ImplItem(P<ast::AssocItem>),
     ForeignItem(P<ast::ForeignItem>),
     Stmt(P<ast::Stmt>),
     Expr(P<ast::Expr>),
@@ -137,14 +137,14 @@ impl Annotatable {
         }
     }
 
-    pub fn expect_trait_item(self) -> ast::TraitItem {
+    pub fn expect_trait_item(self) -> ast::AssocItem {
         match self {
             Annotatable::TraitItem(i) => i.into_inner(),
             _ => panic!("expected Item")
         }
     }
 
-    pub fn expect_impl_item(self) -> ast::ImplItem {
+    pub fn expect_impl_item(self) -> ast::AssocItem {
         match self {
             Annotatable::ImplItem(i) => i.into_inner(),
             _ => panic!("expected Item")
@@ -382,12 +382,12 @@ pub trait MacResult {
     }
 
     /// Creates zero or more impl items.
-    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
+    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         None
     }
 
     /// Creates zero or more trait items.
-    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
+    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         None
     }
 
@@ -468,8 +468,8 @@ make_MacEager! {
     expr: P<ast::Expr>,
     pat: P<ast::Pat>,
     items: SmallVec<[P<ast::Item>; 1]>,
-    impl_items: SmallVec<[ast::ImplItem; 1]>,
-    trait_items: SmallVec<[ast::TraitItem; 1]>,
+    impl_items: SmallVec<[ast::AssocItem; 1]>,
+    trait_items: SmallVec<[ast::AssocItem; 1]>,
     foreign_items: SmallVec<[ast::ForeignItem; 1]>,
     stmts: SmallVec<[ast::Stmt; 1]>,
     ty: P<ast::Ty>,
@@ -484,11 +484,11 @@ impl MacResult for MacEager {
         self.items
     }
 
-    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
+    fn make_impl_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         self.impl_items
     }
 
-    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
+    fn make_trait_items(self: Box<Self>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         self.trait_items
     }
 
@@ -588,11 +588,11 @@ impl MacResult for DummyResult {
         Some(SmallVec::new())
     }
 
-    fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::ImplItem; 1]>> {
+    fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         Some(SmallVec::new())
     }
 
-    fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::TraitItem; 1]>> {
+    fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVec<[ast::AssocItem; 1]>> {
         Some(SmallVec::new())
     }
 
@@ -775,6 +775,10 @@ impl SyntaxExtension {
         }
 
         let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro);
+        let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
+        if const_stability.is_some() {
+            sess.span_diagnostic.span_err(span, "macros cannot have const stability attributes");
+        }
 
         SyntaxExtension {
             kind,
@@ -782,7 +786,7 @@ impl SyntaxExtension {
             allow_internal_unstable,
             allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe),
             local_inner_macros,
-            stability: attr::find_stability(&sess, attrs, span),
+            stability,
             deprecation: attr::find_deprecation(&sess, attrs, span),
             helper_attrs,
             edition,
diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs
index 9bfedb3b617..25c6c287120 100644
--- a/src/libsyntax_expand/expand.rs
+++ b/src/libsyntax_expand/expand.rs
@@ -85,7 +85,6 @@ macro_rules! ast_fragments {
                     $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
                         // We are repeating through arguments with `many`, to do that we have to
                         // mention some macro variable from those arguments even if it's not used.
-                        #[cfg_attr(bootstrap, allow(unused_macros))]
                         macro _repeating($flat_map_ast_elt) {}
                         placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
                     })),)?)*
@@ -155,10 +154,10 @@ ast_fragments! {
     Items(SmallVec<[P<ast::Item>; 1]>) {
         "item"; many fn flat_map_item; fn visit_item; fn make_items;
     }
-    TraitItems(SmallVec<[ast::TraitItem; 1]>) {
+    TraitItems(SmallVec<[ast::AssocItem; 1]>) {
         "trait item"; many fn flat_map_trait_item; fn visit_trait_item; fn make_trait_items;
     }
-    ImplItems(SmallVec<[ast::ImplItem; 1]>) {
+    ImplItems(SmallVec<[ast::AssocItem; 1]>) {
         "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items;
     }
     ForeignItems(SmallVec<[ast::ForeignItem; 1]>) {
@@ -1317,7 +1316,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
     }
 
-    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         let mut item = configure!(self, item);
 
         let (attr, traits, after_derive) = self.classify_item(&mut item);
@@ -1327,16 +1326,16 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
 
         match item.kind {
-            ast::TraitItemKind::Macro(mac) => {
-                let ast::TraitItem { attrs, span, .. } = item;
+            ast::AssocItemKind::Macro(mac) => {
+                let ast::AssocItem { attrs, span, .. } = item;
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::TraitItems).make_trait_items()
             }
-            _ => noop_flat_map_trait_item(item, self),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
-    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+    fn flat_map_impl_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         let mut item = configure!(self, item);
 
         let (attr, traits, after_derive) = self.classify_item(&mut item);
@@ -1346,12 +1345,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
 
         match item.kind {
-            ast::ImplItemKind::Macro(mac) => {
-                let ast::ImplItem { attrs, span, .. } = item;
+            ast::AssocItemKind::Macro(mac) => {
+                let ast::AssocItem { attrs, span, .. } = item;
                 self.check_attributes(&attrs);
                 self.collect_bang(mac, span, AstFragmentKind::ImplItems).make_impl_items()
             }
-            _ => noop_flat_map_impl_item(item, self),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs
index bf7960f9066..1e2f3f9d1e5 100644
--- a/src/libsyntax_expand/mbe/macro_parser.rs
+++ b/src/libsyntax_expand/mbe/macro_parser.rs
@@ -83,7 +83,7 @@ use syntax::print::pprust;
 use syntax::sess::ParseSess;
 use syntax::symbol::{kw, sym, Symbol};
 use syntax::token::{self, DocComment, Nonterminal, Token};
-use syntax::tokenstream::{DelimSpan, TokenStream};
+use syntax::tokenstream::TokenStream;
 
 use errors::{PResult, FatalError};
 use smallvec::{smallvec, SmallVec};
@@ -164,11 +164,6 @@ struct MatcherPos<'root, 'tt> {
     /// The position of the "dot" in this matcher
     idx: usize,
 
-    /// The first span of source that the beginning of this matcher corresponds to. In other
-    /// words, the token in the source whose span is `sp_open` is matched against the first token of
-    /// the matcher.
-    sp_open: Span,
-
     /// For each named metavar in the matcher, we keep track of token trees matched against the
     /// metavar by the black box parser. In particular, there may be more than one match per
     /// metavar if we are in a repetition (each repetition matches each of the variables).
@@ -307,8 +302,8 @@ fn create_matches(len: usize) -> Box<[Lrc<NamedMatchVec>]> {
 }
 
 /// Generates the top-level matcher position in which the "dot" is before the first token of the
-/// matcher `ms` and we are going to start matching at the span `open` in the source.
-fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherPos<'root, 'tt> {
+/// matcher `ms`.
+fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree]) -> MatcherPos<'root, 'tt> {
     let match_idx_hi = count_names(ms);
     let matches = create_matches(match_idx_hi);
     MatcherPos {
@@ -316,8 +311,6 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP
         top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
         // The "dot" is before the first token of the matcher
         idx: 0,
-        // We start matching at the span `open` in the source code
-        sp_open: open,
 
         // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
         // `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
@@ -355,7 +348,7 @@ fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree], open: Span) -> MatcherP
 /// token tree it was derived from.
 #[derive(Debug, Clone)]
 crate enum NamedMatch {
-    MatchedSeq(Lrc<NamedMatchVec>, DelimSpan),
+    MatchedSeq(Lrc<NamedMatchVec>),
     MatchedNonterminal(Lrc<Nonterminal>),
 }
 
@@ -497,8 +490,7 @@ fn inner_parse_loop<'root, 'tt>(
                     // Add matches from this repetition to the `matches` of `up`
                     for idx in item.match_lo..item.match_hi {
                         let sub = item.matches[idx].clone();
-                        let span = DelimSpan::from_pair(item.sp_open, token.span);
-                        new_pos.push_match(idx, MatchedSeq(sub, span));
+                        new_pos.push_match(idx, MatchedSeq(sub));
                     }
 
                     // Move the "dot" past the repetition in `up`
@@ -552,7 +544,7 @@ fn inner_parse_loop<'root, 'tt>(
                         new_item.match_cur += seq.num_captures;
                         new_item.idx += 1;
                         for idx in item.match_cur..item.match_cur + seq.num_captures {
-                            new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![]), sp));
+                            new_item.push_match(idx, MatchedSeq(Lrc::new(smallvec![])));
                         }
                         cur_items.push(new_item);
                     }
@@ -568,7 +560,6 @@ fn inner_parse_loop<'root, 'tt>(
                         match_cur: item.match_cur,
                         match_hi: item.match_cur + seq.num_captures,
                         up: Some(item),
-                        sp_open: sp.open,
                         top_elts: Tt(TokenTree::Sequence(sp, seq)),
                     })));
                 }
@@ -663,7 +654,7 @@ pub(super) fn parse(
     //
     // This MatcherPos instance is allocated on the stack. All others -- and
     // there are frequently *no* others! -- are allocated on the heap.
-    let mut initial = initial_matcher_pos(ms, parser.token.span);
+    let mut initial = initial_matcher_pos(ms);
     let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
     let mut next_items = Vec::new();
 
diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs
index e3c3655bcf8..2dd15872a9f 100644
--- a/src/libsyntax_expand/mbe/macro_rules.rs
+++ b/src/libsyntax_expand/mbe/macro_rules.rs
@@ -379,7 +379,7 @@ pub fn compile_declarative_macro(
 
     // Extract the arguments:
     let lhses = match argument_map[&lhs_nm] {
-        MatchedSeq(ref s, _) => s
+        MatchedSeq(ref s) => s
             .iter()
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
@@ -402,7 +402,7 @@ pub fn compile_declarative_macro(
     };
 
     let rhses = match argument_map[&rhs_nm] {
-        MatchedSeq(ref s, _) => s
+        MatchedSeq(ref s) => s
             .iter()
             .map(|m| {
                 if let MatchedNonterminal(ref nt) = *m {
diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs
index a1157667df1..0605f7ff36d 100644
--- a/src/libsyntax_expand/mbe/transcribe.rs
+++ b/src/libsyntax_expand/mbe/transcribe.rs
@@ -299,7 +299,7 @@ fn lookup_cur_matched<'a>(
         for &(idx, _) in repeats {
             match matched {
                 MatchedNonterminal(_) => break,
-                MatchedSeq(ref ads, _) => matched = ads.get(idx).unwrap(),
+                MatchedSeq(ref ads) => matched = ads.get(idx).unwrap(),
             }
         }
 
@@ -382,7 +382,7 @@ fn lockstep_iter_size(
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
                     MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
-                    MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name),
+                    MatchedSeq(ref ads) => LockstepIterSize::Constraint(ads.len(), name),
                 },
                 _ => LockstepIterSize::Unconstrained,
             }
diff --git a/src/libsyntax_expand/placeholders.rs b/src/libsyntax_expand/placeholders.rs
index faea04e691b..22e99baae5b 100644
--- a/src/libsyntax_expand/placeholders.rs
+++ b/src/libsyntax_expand/placeholders.rs
@@ -50,14 +50,15 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId, vis: Option<ast::Visi
             kind: ast::ItemKind::Mac(mac_placeholder()),
             tokens: None,
         })]),
-        AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::TraitItem {
+        AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![ast::AssocItem {
             id, span, ident, vis, attrs, generics,
-            kind: ast::TraitItemKind::Macro(mac_placeholder()),
+            kind: ast::AssocItemKind::Macro(mac_placeholder()),
+            defaultness: ast::Defaultness::Final,
             tokens: None,
         }]),
-        AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![ast::ImplItem {
+        AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![ast::AssocItem {
             id, span, ident, vis, attrs, generics,
-            kind: ast::ImplItemKind::Macro(mac_placeholder()),
+            kind: ast::AssocItemKind::Macro(mac_placeholder()),
             defaultness: ast::Defaultness::Final,
             tokens: None,
         }]),
@@ -252,17 +253,17 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
         noop_flat_map_item(item, self)
     }
 
-    fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> {
+    fn flat_map_trait_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         match item.kind {
-            ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
-            _ => noop_flat_map_trait_item(item, self),
+            ast::AssocItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
-    fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> {
+    fn flat_map_impl_item(&mut self, item: ast::AssocItem) -> SmallVec<[ast::AssocItem; 1]> {
         match item.kind {
-            ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
-            _ => noop_flat_map_impl_item(item, self),
+            ast::AssocItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
+            _ => noop_flat_map_assoc_item(item, self),
         }
     }
 
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 5bd84b43a78..b7707bfb8e5 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -504,13 +504,13 @@ impl<'a> TraitDef<'a> {
                            type_ident: Ident,
                            generics: &Generics,
                            field_tys: Vec<P<ast::Ty>>,
-                           methods: Vec<ast::ImplItem>)
+                           methods: Vec<ast::AssocItem>)
                            -> P<ast::Item> {
         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
 
-        // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem`
+        // Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
         let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
-            ast::ImplItem {
+            ast::AssocItem {
                 id: ast::DUMMY_NODE_ID,
                 span: self.span,
                 ident,
@@ -518,8 +518,10 @@ impl<'a> TraitDef<'a> {
                 defaultness: ast::Defaultness::Final,
                 attrs: Vec::new(),
                 generics: Generics::default(),
-                kind: ast::ImplItemKind::TyAlias(
-                    type_def.to_ty(cx, self.span, type_ident, generics)),
+                kind: ast::AssocItemKind::TyAlias(
+                    Vec::new(),
+                    Some(type_def.to_ty(cx, self.span, type_ident, generics)),
+                ),
                 tokens: None,
             }
         });
@@ -910,7 +912,7 @@ impl<'a> MethodDef<'a> {
                      explicit_self: Option<ast::ExplicitSelf>,
                      arg_types: Vec<(Ident, P<ast::Ty>)>,
                      body: P<Expr>)
-                     -> ast::ImplItem {
+                     -> ast::AssocItem {
         // Create the generics that aren't for `Self`.
         let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics);
 
@@ -948,7 +950,7 @@ impl<'a> MethodDef<'a> {
         };
 
         // Create the method.
-        ast::ImplItem {
+        ast::AssocItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
             generics: fn_generics,
@@ -956,7 +958,7 @@ impl<'a> MethodDef<'a> {
             vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited),
             defaultness: ast::Defaultness::Final,
             ident: method_ident,
-            kind: ast::ImplItemKind::Method(sig, body_block),
+            kind: ast::AssocItemKind::Fn(sig, Some(body_block)),
             tokens: None,
         }
     }
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 92de56bd09a..ae34064c926 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -213,6 +213,7 @@ symbols! {
         const_indexing,
         const_in_array_repeat_expressions,
         const_let,
+        const_loop,
         const_mut_refs,
         const_panic,
         const_raw_ptr_deref,
@@ -605,6 +606,7 @@ symbols! {
         rustc_builtin_macro,
         rustc_clean,
         rustc_const_unstable,
+        rustc_const_stable,
         rustc_conversion_suggestion,
         rustc_def_path,
         rustc_deprecated,
diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs
index be90195065e..09bea80c95a 100644
--- a/src/libterm/terminfo/mod.rs
+++ b/src/libterm/terminfo/mod.rs
@@ -74,7 +74,7 @@ impl TermInfo {
             Err(..) => return Err(Error::TermUnset),
         };
 
-        if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) {
+        if term.is_err() && env::var("MSYSCON").map_or(false, |s| "mintty.exe" == s) {
             // msys terminal
             Ok(msys_terminfo())
         } else {
diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml
index 997d1393837..86a93d7d0cb 100644
--- a/src/rustc/Cargo.toml
+++ b/src/rustc/Cargo.toml
@@ -23,3 +23,4 @@ features = ['unprefixed_malloc_on_supported_platforms']
 
 [features]
 jemalloc = ['jemalloc-sys']
+llvm = ['rustc_driver/llvm']
diff --git a/src/stage0.txt b/src/stage0.txt
index 3c848901583..999218efa29 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.x.0` for Cargo where they were released on `date`.
 
-date: 2019-11-06
+date: 2019-12-18
 rustc: beta
 cargo: beta
 
diff --git a/src/test/codegen/enum-debug-niche-2.rs b/src/test/codegen/enum-debug-niche-2.rs
index 7e00dc5463f..0f17976ef49 100644
--- a/src/test/codegen/enum-debug-niche-2.rs
+++ b/src/test/codegen/enum-debug-niche-2.rs
@@ -12,6 +12,8 @@
 // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Placeholder",{{.*}}extraData: i64 4294967295{{[,)].*}}
 // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}}
 
+#![feature(never_type)]
+
 #[derive(Copy, Clone)]
 pub struct Entity {
     private: std::num::NonZeroU32,
diff --git a/src/test/mir-opt/address-of.rs b/src/test/mir-opt/address-of.rs
new file mode 100644
index 00000000000..bbd1ca68a86
--- /dev/null
+++ b/src/test/mir-opt/address-of.rs
@@ -0,0 +1,112 @@
+fn address_of_reborrow() {
+    let y = &[0; 10];
+    let mut z = &mut [0; 10];
+
+    y as *const _;
+    y as *const [i32; 10];
+    y as *const dyn Send;
+    y as *const [i32];
+    y as *const i32;            // This is a cast, not a coercion
+
+    let p: *const _ = y;
+    let p: *const [i32; 10] = y;
+    let p: *const dyn Send = y;
+    let p: *const [i32] = y;
+
+    z as *const _;
+    z as *const [i32; 10];
+    z as *const dyn Send;
+    z as *const [i32];
+
+    let p: *const _ = z;
+    let p: *const [i32; 10] = z;
+    let p: *const dyn Send = z;
+    let p: *const [i32] = z;
+
+    z as *mut _;
+    z as *mut [i32; 10];
+    z as *mut dyn Send;
+    z as *mut [i32];
+
+    let p: *mut _ = z;
+    let p: *mut [i32; 10] = z;
+    let p: *mut dyn Send = z;
+    let p: *mut [i32] = z;
+}
+
+// The normal borrows here should be preserved
+fn borrow_and_cast(mut x: i32) {
+    let p = &x as *const i32;
+    let q = &mut x as *const i32;
+    let r = &mut x as *mut i32;
+}
+
+fn main() {}
+
+// START rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
+// bb0: {
+//  ...
+//  _5 = &raw const (*_1); // & to *const casts
+//  ...
+//  _7 = &raw const (*_1);
+//  ...
+//  _11 = &raw const (*_1);
+//  ...
+//  _14 = &raw const (*_1);
+//  ...
+//  _16 = &raw const (*_1);
+//  ...
+//  _17 = &raw const (*_1); // & to *const coercions
+//  ...
+//  _18 = &raw const (*_1);
+//  ...
+//  _20 = &raw const (*_1);
+//  ...
+//  _22 = &raw const (*_1);
+// ...
+//  _24 = &raw const (*_2); // &mut to *const casts
+// ...
+//  _26 = &raw const (*_2);
+// ...
+//  _30 = &raw const (*_2);
+// ...
+//  _33 = &raw const (*_2);
+// ...
+//  _34 = &raw const (*_2); // &mut to *const coercions
+// ...
+//  _35 = &raw const (*_2);
+// ...
+//  _37 = &raw const (*_2);
+// ...
+//  _39 = &raw const (*_2);
+// ...
+//  _41 = &raw mut (*_2); // &mut to *mut casts
+// ...
+//  _43 = &raw mut (*_2);
+// ...
+//  _47 = &raw mut (*_2);
+// ...
+//  _50 = &raw mut (*_2);
+// ...
+//  _51 = &raw mut (*_2); // &mut to *mut coercions
+// ...
+//  _52 = &raw mut (*_2);
+// ...
+//  _54 = &raw mut (*_2);
+// ...
+//  _56 = &raw mut (*_2);
+// ...
+// }
+// END rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
+
+// START rustc.borrow_and_cast.EraseRegions.after.mir
+// bb0: {
+//  ...
+//  _4 = &_1;
+//  ...
+//  _7 = &mut _1;
+//  ...
+//  _10 = &mut _1;
+//  ...
+// }
+// END rustc.borrow_and_cast.EraseRegions.after.mir
diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs
index 00a6b26d0cf..096f98bade2 100644
--- a/src/test/mir-opt/array-index-is-temporary.rs
+++ b/src/test/mir-opt/array-index-is-temporary.rs
@@ -18,24 +18,23 @@ fn main() {
 // START rustc.main.EraseRegions.after.mir
 //     bb0: {
 //         ...
-//         _5 = &mut _2;
-//         _4 = &mut (*_5);
-//         _3 = move _4 as *mut usize (Misc);
+//         _4 = &mut _2;
+//         _3 = &raw mut (*_4);
 //         ...
-//         _7 = _3;
-//         _6 = const foo(move _7) -> bb1;
+//         _6 = _3;
+//         _5 = const foo(move _6) -> bb1;
 //     }
 //
 //     bb1: {
 //         ...
-//         _8 = _2;
-//         _9 = Len(_1);
-//         _10 = Lt(_8, _9);
-//         assert(move _10, "index out of bounds: the len is move _9 but the index is _8") -> bb2;
+//         _7 = _2;
+//         _8 = Len(_1);
+//         _9 = Lt(_7, _8);
+//         assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2;
 //     }
 //
 //     bb2: {
-//         _1[_8] = move _6;
+//         _1[_7] = move _5;
 //         ...
 //         return;
 //     }
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
index 3f82b81a47d..3c8c0ff4493 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
@@ -11,25 +11,21 @@ fn main() {
 // START rustc.main.ConstProp.before.mir
 //  bb0: {
 //      ...
-//      _3 = _4;
-//      _2 = move _3 as *const i32 (Misc);
-//      ...
+//      _2 = &raw const (*_3);
 //      _1 = move _2 as usize (Misc);
 //      ...
-//      _6 = _1;
-//      _5 = const read(move _6) -> bb1;
+//      _5 = _1;
+//      _4 = const read(move _5) -> bb1;
 //  }
 // END rustc.main.ConstProp.before.mir
 // START rustc.main.ConstProp.after.mir
 //  bb0: {
 //      ...
-//      _4 = const main::FOO;
-//      _3 = _4;
-//      _2 = move _3 as *const i32 (Misc);
-//      ...
+//      _3 = const main::FOO;
+//      _2 = &raw const (*_3);
 //      _1 = move _2 as usize (Misc);
 //      ...
-//      _6 = _1;
-//      _5 = const read(move _6) -> bb1;
+//      _5 = _1;
+//      _4 = const read(move _5) -> bb1;
 //  }
 // END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs
index 32995448a21..ccecaeac96b 100644
--- a/src/test/mir-opt/retag.rs
+++ b/src/test/mir-opt/retag.rs
@@ -82,18 +82,16 @@ fn main() {
 //         _10 = move _8;
 //         Retag(_10);
 //         ...
-//         _13 = &mut (*_10);
-//         Retag(_13);
-//         _12 = move _13 as *mut i32 (Misc);
+//         _12 = &raw mut (*_10);
 //         Retag([raw] _12);
 //         ...
-//         _16 = move _17(move _18) -> bb5;
+//         _15 = move _16(move _17) -> bb5;
 //     }
 //
 //     bb5: {
-//         Retag(_16);
+//         Retag(_15);
 //         ...
-//         _20 = const Test::foo_shr(move _21, move _23) -> [return: bb6, unwind: bb7];
+//         _19 = const Test::foo_shr(move _20, move _22) -> [return: bb6, unwind: bb7];
 //     }
 //
 //     ...
diff --git a/src/test/mir-opt/retain-never-const.rs b/src/test/mir-opt/retain-never-const.rs
index 5d59b2f4842..04394dcdf13 100644
--- a/src/test/mir-opt/retain-never-const.rs
+++ b/src/test/mir-opt/retain-never-const.rs
@@ -5,6 +5,7 @@
 // compile-flags: --emit mir,link
 
 #![feature(const_panic)]
+#![feature(never_type)]
 
 struct PrintName<T>(T);
 
diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs
index f270dec5fe2..5a37b67229c 100644
--- a/src/test/mir-opt/slice-drop-shim.rs
+++ b/src/test/mir-opt/slice-drop-shim.rs
@@ -10,15 +10,15 @@ fn main() {
 // let mut _2: usize;
 // let mut _3: usize;
 // let mut _4: usize;
-// let mut _5: &mut std::string::String;
+// let mut _5: *mut std::string::String;
 // let mut _6: bool;
-// let mut _7: &mut std::string::String;
+// let mut _7: *mut std::string::String;
 // let mut _8: bool;
 // let mut _9: *mut std::string::String;
 // let mut _10: *mut std::string::String;
-// let mut _11: &mut std::string::String;
+// let mut _11: *mut std::string::String;
 // let mut _12: bool;
-// let mut _13: &mut std::string::String;
+// let mut _13: *mut std::string::String;
 // let mut _14: bool;
 // let mut _15: *mut [std::string::String];
 // bb0: {
@@ -31,7 +31,7 @@ fn main() {
 //     resume;
 // }
 // bb3 (cleanup): {
-//     _5 = &mut (*_1)[_4];
+//     _5 = &raw mut (*_1)[_4];
 //     _4 = Add(move _4, const 1usize);
 //     drop((*_5)) -> bb4;
 // }
@@ -40,7 +40,7 @@ fn main() {
 //     switchInt(move _6) -> [false: bb3, otherwise: bb2];
 // }
 // bb5: {
-//     _7 = &mut (*_1)[_4];
+//     _7 = &raw mut (*_1)[_4];
 //     _4 = Add(move _4, const 1usize);
 //     drop((*_7)) -> [return: bb6, unwind: bb4];
 // }
@@ -56,7 +56,7 @@ fn main() {
 //     goto -> bb7;
 // }
 // bb9 (cleanup): {
-//     _11 = &mut (*_9);
+//     _11 = _9;
 //     _9 = Offset(move _9, const 1usize);
 //     drop((*_11)) -> bb10;
 // }
@@ -65,7 +65,7 @@ fn main() {
 //     switchInt(move _12) -> [false: bb9, otherwise: bb2];
 // }
 // bb11: {
-//     _13 = &mut (*_9);
+//     _13 = _9;
 //     _9 = Offset(move _9, const 1usize);
 //     drop((*_13)) -> [return: bb12, unwind: bb10];
 // }
@@ -74,7 +74,7 @@ fn main() {
 //     switchInt(move _14) -> [false: bb11, otherwise: bb1];
 // }
 // bb13: {
-//     _15 = &mut (*_1);
+//     _15 = &raw mut (*_1);
 //     _9 = move _15 as *mut std::string::String (Misc);
 //     _10 = Offset(_9, move _3);
 //     goto -> bb12;
diff --git a/src/test/mir-opt/uninhabited-enum.rs b/src/test/mir-opt/uninhabited-enum.rs
index 409be8587cf..904a9c43c1b 100644
--- a/src/test/mir-opt/uninhabited-enum.rs
+++ b/src/test/mir-opt/uninhabited-enum.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 pub enum Void {}
 
 #[no_mangle]
diff --git a/src/test/pretty/raw-address-of.rs b/src/test/pretty/raw-address-of.rs
new file mode 100644
index 00000000000..6ccc434a1e7
--- /dev/null
+++ b/src/test/pretty/raw-address-of.rs
@@ -0,0 +1,12 @@
+// pp-exact
+#![feature(raw_ref_op)]
+
+const C_PTR: () = { let a = 1; &raw const a; };
+static S_PTR: () = { let b = false; &raw const b; };
+
+fn main() {
+    let x = 123;
+    let mut y = 345;
+    let c_p = &raw const x;
+    let parens = unsafe { *(&raw mut (y)) };
+}
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
index 9df0368c40d..bc7ad04b6a2 100644
--- a/src/test/rustdoc/const-display.rs
+++ b/src/test/rustdoc/const-display.rs
@@ -4,12 +4,12 @@
             reason = "who ever let humans program computers, we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(foo, foo2)]
 #![feature(staged_api)]
 
 // @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32'
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 pub const unsafe fn foo() -> u32 { 42 }
 
 // @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32'
@@ -18,6 +18,7 @@ pub const fn foo2() -> u32 { 42 }
 
 // @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const fn bar2() -> u32 { 42 }
 
 // @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32'
@@ -26,6 +27,7 @@ pub const unsafe fn foo2_gated() -> u32 { 42 }
 
 // @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const unsafe fn bar2_gated() -> u32 { 42 }
 
 // @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32'
diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr
index bb217bd182d..92a8d19021a 100644
--- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr
+++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32`
    |
 LL |     const ID: i32 = 1;
    |     ^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `Foo::ID(...)` instead
 note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32`
   --> $DIR/associated-const-ambiguity-report.rs:14:5
    |
 LL |     const ID: i32 = 3;
    |     ^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `Bar::ID(...)` instead
+help: disambiguate the associated constant for candidate #1
+   |
+LL | const X: i32 = Foo::ID;
+   |                ^^^^^^^
+help: disambiguate the associated constant for candidate #2
+   |
+LL | const X: i32 = Bar::ID;
+   |                ^^^^^^^
 
 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
index 311c48b5e48..f9f663af5e2 100644
--- a/src/test/ui/associated-const/issue-63496.rs
+++ b/src/test/ui/associated-const/issue-63496.rs
@@ -2,8 +2,8 @@ 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
+    //~^ ERROR: type annotations needed
+    //~| ERROR: type annotations needed
 }
 
 fn main() {}
diff --git a/src/test/ui/associated-const/issue-63496.stderr b/src/test/ui/associated-const/issue-63496.stderr
index 70bb12de1fb..23916a3ba44 100644
--- a/src/test/ui/associated-const/issue-63496.stderr
+++ b/src/test/ui/associated-const/issue-63496.stderr
@@ -1,20 +1,24 @@
-error[E0283]: type annotations needed: cannot resolve `_: A`
+error[E0283]: type annotations needed
   --> $DIR/issue-63496.rs:4:21
    |
 LL |     const C: usize;
    |     --------------- required by `A::C`
 LL | 
 LL |     fn f() -> ([u8; A::C], [u8; A::C]);
-   |                     ^^^^
+   |                     ^^^^ cannot infer type
+   |
+   = note: cannot resolve `_: A`
 
-error[E0283]: type annotations needed: cannot resolve `_: A`
+error[E0283]: type annotations needed
   --> $DIR/issue-63496.rs:4:33
    |
 LL |     const C: usize;
    |     --------------- required by `A::C`
 LL | 
 LL |     fn f() -> ([u8; A::C], [u8; A::C]);
-   |                                 ^^^^
+   |                                 ^^^^ cannot infer type
+   |
+   = note: cannot resolve `_: A`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-item/issue-48027.stderr b/src/test/ui/associated-item/issue-48027.stderr
index 562146a426d..9c825d593d3 100644
--- a/src/test/ui/associated-item/issue-48027.stderr
+++ b/src/test/ui/associated-item/issue-48027.stderr
@@ -7,13 +7,15 @@ LL |     const X: usize;
 LL | impl dyn Bar {}
    |      ^^^^^^^ the trait `Bar` cannot be made into an object
 
-error[E0283]: type annotations needed: cannot resolve `_: Bar`
+error[E0283]: type annotations needed
   --> $DIR/issue-48027.rs:3:32
    |
 LL |     const X: usize;
    |     --------------- required by `Bar::X`
 LL |     fn return_n(&self) -> [u8; Bar::X];
-   |                                ^^^^^^
+   |                                ^^^^^^ cannot infer type
+   |
+   = note: cannot resolve `_: Bar`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr
index 5ef1b23cbcd..069da955b67 100644
--- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr
+++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr
@@ -1,18 +1,23 @@
-error[E0284]: type annotations needed: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
+error[E0284]: type annotations needed
   --> $DIR/associated-types-overridden-binding.rs:4:1
    |
 LL | trait Foo: Iterator<Item = i32> {}
    | ------------------------------- required by `Foo`
 LL | trait Bar: Foo<Item = u32> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self`
+   |
+   = note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
 
-error[E0282]: type annotations needed
+error[E0284]: type annotations needed
   --> $DIR/associated-types-overridden-binding.rs:7:1
    |
+LL | trait I32Iterator = Iterator<Item = i32>;
+   | ----------------------------------------- required by `I32Iterator`
 LL | trait U32Iterator = I32Iterator<Item = u32>;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self`
+   |
+   = note: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0284.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/associated-types/associated-types-unconstrained.stderr b/src/test/ui/associated-types/associated-types-unconstrained.stderr
index 4e9e54d3688..14ce4836f97 100644
--- a/src/test/ui/associated-types/associated-types-unconstrained.stderr
+++ b/src/test/ui/associated-types/associated-types-unconstrained.stderr
@@ -1,8 +1,10 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as Foo>::A == _`
+error[E0284]: type annotations needed
   --> $DIR/associated-types-unconstrained.rs:14:20
    |
 LL |     let x: isize = Foo::bar();
-   |                    ^^^^^^^^
+   |                    ^^^^^^^^ cannot infer type
+   |
+   = note: cannot resolve `<_ as Foo>::A == _`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.rs b/src/test/ui/async-await/issue-67252-unnamed-future.rs
new file mode 100644
index 00000000000..1a7ff613341
--- /dev/null
+++ b/src/test/ui/async-await/issue-67252-unnamed-future.rs
@@ -0,0 +1,24 @@
+// edition:2018
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+fn spawn<T: Send>(_: T) {}
+
+pub struct AFuture;
+impl Future for AFuture{
+    type Output = ();
+
+    fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<()> {
+        unimplemented!()
+    }
+}
+
+async fn foo() {
+    spawn(async { //~ ERROR future cannot be sent between threads safely
+        let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+        AFuture.await;
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr
new file mode 100644
index 00000000000..24aedeb9659
--- /dev/null
+++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr
@@ -0,0 +1,22 @@
+error: future cannot be sent between threads safely
+  --> $DIR/issue-67252-unnamed-future.rs:18:5
+   |
+LL | fn spawn<T: Send>(_: T) {}
+   |    -----    ---- required by this bound in `spawn`
+...
+LL |     spawn(async {
+   |     ^^^^^ future is not `Send`
+   |
+   = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*mut ()`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/issue-67252-unnamed-future.rs:20:9
+   |
+LL |         let _a = std::ptr::null_mut::<()>(); // `*mut ()` is not `Send`
+   |             -- has type `*mut ()`
+LL |         AFuture.await;
+   |         ^^^^^^^^^^^^^ await occurs here, with `_a` maybe used later
+LL |     });
+   |     - `_a` is later dropped here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index 2876f9fea0e..79c043b701d 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -8,7 +8,7 @@ async fn bar<T>() -> () {}
 async fn foo() {
     bar().await;
     //~^ ERROR type inside `async fn` body must be known in this context
-    //~| NOTE cannot infer type for `T`
+    //~| NOTE cannot infer type for type parameter `T`
     //~| NOTE the type is part of the `async fn` body because of this `await`
     //~| NOTE in this expansion of desugaring of `await`
 }
diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr
index c7866fc7744..3ffdb8ce6b9 100644
--- a/src/test/ui/async-await/unresolved_type_param.stderr
+++ b/src/test/ui/async-await/unresolved_type_param.stderr
@@ -2,7 +2,7 @@ error[E0698]: type inside `async fn` body must be known in this context
   --> $DIR/unresolved_type_param.rs:9:5
    |
 LL |     bar().await;
-   |     ^^^ cannot infer type for `T`
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `bar`
    |
 note: the type is part of the `async fn` body because of this `await`
   --> $DIR/unresolved_type_param.rs:9:5
diff --git a/src/test/ui/autoderef-full-lval.rs b/src/test/ui/autoderef-full-lval.rs
index db09d036ad3..4bef1012e33 100644
--- a/src/test/ui/autoderef-full-lval.rs
+++ b/src/test/ui/autoderef-full-lval.rs
@@ -13,13 +13,13 @@ fn main() {
     let a: Clam = Clam{x: box 1, y: box 2};
     let b: Clam = Clam{x: box 10, y: box 20};
     let z: isize = a.x + b.y;
-    //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box<isize>`
+    //~^ ERROR cannot add `std::boxed::Box<isize>` to `std::boxed::Box<isize>`
     println!("{}", z);
     assert_eq!(z, 21);
     let forty: Fish = Fish{a: box 40};
     let two: Fish = Fish{a: box 2};
     let answer: isize = forty.a + two.a;
-    //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box<isize>`
+    //~^ ERROR cannot add `std::boxed::Box<isize>` to `std::boxed::Box<isize>`
     println!("{}", answer);
     assert_eq!(answer, 42);
 }
diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr
index c9f3e8b2e26..e2870ef8062 100644
--- a/src/test/ui/autoderef-full-lval.stderr
+++ b/src/test/ui/autoderef-full-lval.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box<isize>`
+error[E0369]: cannot add `std::boxed::Box<isize>` to `std::boxed::Box<isize>`
   --> $DIR/autoderef-full-lval.rs:15:24
    |
 LL |     let z: isize = a.x + b.y;
@@ -8,7 +8,7 @@ LL |     let z: isize = a.x + b.y;
    |
    = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box<isize>`
 
-error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box<isize>`
+error[E0369]: cannot add `std::boxed::Box<isize>` to `std::boxed::Box<isize>`
   --> $DIR/autoderef-full-lval.rs:21:33
    |
 LL |     let answer: isize = forty.a + two.a;
diff --git a/src/test/ui/binary-op-on-double-ref.rs b/src/test/ui/binary-op-on-double-ref.rs
index 6490cc7fe56..67e01b9327d 100644
--- a/src/test/ui/binary-op-on-double-ref.rs
+++ b/src/test/ui/binary-op-on-double-ref.rs
@@ -2,7 +2,7 @@ fn main() {
     let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
     let vr = v.iter().filter(|x| {
         x % 2 == 0
-        //~^ ERROR binary operation `%` cannot be applied to type `&&{integer}`
+        //~^ ERROR cannot mod `&&{integer}` by `{integer}`
     });
     println!("{:?}", vr);
 }
diff --git a/src/test/ui/binary-op-on-double-ref.stderr b/src/test/ui/binary-op-on-double-ref.stderr
index d036f06a8c7..6c405333ec6 100644
--- a/src/test/ui/binary-op-on-double-ref.stderr
+++ b/src/test/ui/binary-op-on-double-ref.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `%` cannot be applied to type `&&{integer}`
+error[E0369]: cannot mod `&&{integer}` by `{integer}`
   --> $DIR/binary-op-on-double-ref.rs:4:11
    |
 LL |         x % 2 == 0
diff --git a/src/test/ui/binding/empty-types-in-patterns.rs b/src/test/ui/binding/empty-types-in-patterns.rs
index 1864d4bb820..4271ffb7b1b 100644
--- a/src/test/ui/binding/empty-types-in-patterns.rs
+++ b/src/test/ui/binding/empty-types-in-patterns.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(never_type_fallback)]
+#![feature(never_type, never_type_fallback)]
 #![feature(exhaustive_patterns)]
 #![feature(slice_patterns)]
 #![allow(unreachable_patterns)]
diff --git a/src/test/ui/binop/binop-bitxor-str.rs b/src/test/ui/binop/binop-bitxor-str.rs
index 6021c344dfb..e98ea4df97d 100644
--- a/src/test/ui/binop/binop-bitxor-str.rs
+++ b/src/test/ui/binop/binop-bitxor-str.rs
@@ -1,3 +1,3 @@
-// error-pattern:`^` cannot be applied to type `std::string::String`
+// error-pattern:no implementation for `std::string::String ^ std::string::String`
 
 fn main() { let x = "a".to_string() ^ "b".to_string(); }
diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr
index 9e8992235ed..9a0d301d863 100644
--- a/src/test/ui/binop/binop-bitxor-str.stderr
+++ b/src/test/ui/binop/binop-bitxor-str.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `^` cannot be applied to type `std::string::String`
+error[E0369]: no implementation for `std::string::String ^ std::string::String`
   --> $DIR/binop-bitxor-str.rs:3:37
    |
 LL | fn main() { let x = "a".to_string() ^ "b".to_string(); }
diff --git a/src/test/ui/binop/binop-mul-bool.rs b/src/test/ui/binop/binop-mul-bool.rs
index 3d5349ba880..27b2f8bb3ff 100644
--- a/src/test/ui/binop/binop-mul-bool.rs
+++ b/src/test/ui/binop/binop-mul-bool.rs
@@ -1,3 +1,3 @@
-// error-pattern:`*` cannot be applied to type `bool`
+// error-pattern:cannot multiply `bool` to `bool`
 
 fn main() { let x = true * false; }
diff --git a/src/test/ui/binop/binop-mul-bool.stderr b/src/test/ui/binop/binop-mul-bool.stderr
index 92e14bccccd..ade22025589 100644
--- a/src/test/ui/binop/binop-mul-bool.stderr
+++ b/src/test/ui/binop/binop-mul-bool.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `*` cannot be applied to type `bool`
+error[E0369]: cannot multiply `bool` to `bool`
   --> $DIR/binop-mul-bool.rs:3:26
    |
 LL | fn main() { let x = true * false; }
diff --git a/src/test/ui/binop/binop-typeck.rs b/src/test/ui/binop/binop-typeck.rs
index e1185cfba26..812fe95db4e 100644
--- a/src/test/ui/binop/binop-typeck.rs
+++ b/src/test/ui/binop/binop-typeck.rs
@@ -4,5 +4,5 @@ fn main() {
     let x = true;
     let y = 1;
     let z = x + y;
-    //~^ ERROR binary operation `+` cannot be applied to type `bool`
+    //~^ ERROR cannot add `{integer}` to `bool`
 }
diff --git a/src/test/ui/binop/binop-typeck.stderr b/src/test/ui/binop/binop-typeck.stderr
index d33cff313e7..ebf82079ef2 100644
--- a/src/test/ui/binop/binop-typeck.stderr
+++ b/src/test/ui/binop/binop-typeck.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `bool`
+error[E0369]: cannot add `{integer}` to `bool`
   --> $DIR/binop-typeck.rs:6:15
    |
 LL |     let z = x + y;
diff --git a/src/test/ui/borrowck/assign-never-type.rs b/src/test/ui/borrowck/assign-never-type.rs
index 52b2e70d159..4f30ea14670 100644
--- a/src/test/ui/borrowck/assign-never-type.rs
+++ b/src/test/ui/borrowck/assign-never-type.rs
@@ -2,6 +2,8 @@
 
 // check-pass
 
+#![feature(never_type)]
+
 pub fn main() {
     loop {
         match None {
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-borrowed.rs b/src/test/ui/borrowck/borrow-raw-address-of-borrowed.rs
new file mode 100644
index 00000000000..f25fd7f66b3
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-borrowed.rs
@@ -0,0 +1,22 @@
+#![feature(raw_ref_op)]
+
+fn address_of_shared() {
+    let mut x = 0;
+    let y = &x;
+
+    let q = &raw mut x;                 //~ ERROR cannot borrow
+
+    drop(y);
+}
+
+fn address_of_mutably_borrowed() {
+    let mut x = 0;
+    let y = &mut x;
+
+    let p = &raw const x;               //~ ERROR cannot borrow
+    let q = &raw mut x;                 //~ ERROR cannot borrow
+
+    drop(y);
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-borrowed.stderr b/src/test/ui/borrowck/borrow-raw-address-of-borrowed.stderr
new file mode 100644
index 00000000000..ff461b748be
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-borrowed.stderr
@@ -0,0 +1,40 @@
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-raw-address-of-borrowed.rs:7:13
+   |
+LL |     let y = &x;
+   |             -- immutable borrow occurs here
+LL | 
+LL |     let q = &raw mut x;
+   |             ^^^^^^^^^^ mutable borrow occurs here
+LL | 
+LL |     drop(y);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-raw-address-of-borrowed.rs:16:13
+   |
+LL |     let y = &mut x;
+   |             ------ mutable borrow occurs here
+LL | 
+LL |     let p = &raw const x;
+   |             ^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |     drop(y);
+   |          - mutable borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrow-raw-address-of-borrowed.rs:17:13
+   |
+LL |     let y = &mut x;
+   |             ------ first mutable borrow occurs here
+...
+LL |     let q = &raw mut x;
+   |             ^^^^^^^^^^ second mutable borrow occurs here
+LL | 
+LL |     drop(y);
+   |          - first borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0499, E0502.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs b/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs
new file mode 100644
index 00000000000..e381384fe65
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(raw_ref_op)]
+
+fn raw_reborrow() {
+    let x = &0;
+    let y = &mut 0;
+
+    let p = &raw const *x;
+    let r = &raw const *y;
+    let s = &raw mut *y;
+}
+
+unsafe fn raw_reborrow_of_raw() {
+    let x = &0 as *const i32;
+    let y = &mut 0 as *mut i32;
+
+    let p = &raw const *x;
+    let r = &raw const *y;
+    let s = &raw mut *y;
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.rs b/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.rs
new file mode 100644
index 00000000000..712873528b5
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.rs
@@ -0,0 +1,17 @@
+// Check that `&raw mut` cannot be used to turn a `&T` into a `*mut T`.
+
+#![feature(raw_ref_op)]
+
+fn raw_reborrow() {
+    let x = &0;
+
+    let q = &raw mut *x;                //~ ERROR cannot borrow
+}
+
+unsafe fn raw_reborrow_of_raw() {
+    let x = &0 as *const i32;
+
+    let q = &raw mut *x;                //~ ERROR cannot borrow
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
new file mode 100644
index 00000000000..31af38507c7
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr
@@ -0,0 +1,21 @@
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
+  --> $DIR/borrow-raw-address-of-deref-mutability.rs:8:13
+   |
+LL |     let x = &0;
+   |             -- help: consider changing this to be a mutable reference: `&mut 0`
+LL | 
+LL |     let q = &raw mut *x;
+   |             ^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
+  --> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13
+   |
+LL |     let x = &0 as *const i32;
+   |             -- help: consider changing this to be a mutable pointer: `&mut 0`
+LL | 
+LL |     let q = &raw mut *x;
+   |             ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability-ok.rs b/src/test/ui/borrowck/borrow-raw-address-of-mutability-ok.rs
new file mode 100644
index 00000000000..e1cf2dc5386
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability-ok.rs
@@ -0,0 +1,44 @@
+// check-pass
+
+#![feature(raw_ref_op)]
+
+fn mutable_address_of() {
+    let mut x = 0;
+    let y = &raw mut x;
+}
+
+fn mutable_address_of_closure() {
+    let mut x = 0;
+    let mut f = || {
+        let y = &raw mut x;
+    };
+    f();
+}
+
+fn const_address_of_closure() {
+    let x = 0;
+    let f = || {
+        let y = &raw const x;
+    };
+    f();
+}
+
+fn make_fn<F: Fn()>(f: F) -> F { f }
+
+fn const_address_of_fn_closure() {
+    let x = 0;
+    let f = make_fn(|| {
+        let y = &raw const x;
+    });
+    f();
+}
+
+fn const_address_of_fn_closure_move() {
+    let x = 0;
+    let f = make_fn(move || {
+        let y = &raw const x;
+    });
+    f();
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.rs b/src/test/ui/borrowck/borrow-raw-address-of-mutability.rs
new file mode 100644
index 00000000000..320c54b806a
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.rs
@@ -0,0 +1,42 @@
+#![feature(raw_ref_op)]
+
+fn mutable_address_of() {
+    let x = 0;
+    let y = &raw mut x;                 //~ ERROR cannot borrow
+}
+
+fn mutable_address_of_closure() {
+    let x = 0;
+    let mut f = || {
+        let y = &raw mut x;             //~ ERROR cannot borrow
+    };
+    f();
+}
+
+fn mutable_address_of_imm_closure() {
+    let mut x = 0;
+    let f = || {
+        let y = &raw mut x;
+    };
+    f();                                //~ ERROR cannot borrow
+}
+
+fn make_fn<F: Fn()>(f: F) -> F { f }
+
+fn mutable_address_of_fn_closure() {
+    let mut x = 0;
+    let f = make_fn(|| {
+        let y = &raw mut x;             //~ ERROR cannot borrow
+    });
+    f();
+}
+
+fn mutable_address_of_fn_closure_move() {
+    let mut x = 0;
+    let f = make_fn(move || {
+        let y = &raw mut x;             //~ ERROR cannot borrow
+    });
+    f();
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
new file mode 100644
index 00000000000..cf01c362d50
--- /dev/null
+++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
@@ -0,0 +1,59 @@
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-raw-address-of-mutability.rs:5:13
+   |
+LL |     let x = 0;
+   |         - help: consider changing this to be mutable: `mut x`
+LL |     let y = &raw mut x;
+   |             ^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-raw-address-of-mutability.rs:11:17
+   |
+LL |     let x = 0;
+   |         - help: consider changing this to be mutable: `mut x`
+LL |     let mut f = || {
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-raw-address-of-mutability.rs:21:5
+   |
+LL |     let f = || {
+   |         - help: consider changing this to be mutable: `mut f`
+...
+LL |     f();
+   |     ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-raw-address-of-mutability.rs:29:17
+   |
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to accept closures that implement `FnMut`
+  --> $DIR/borrow-raw-address-of-mutability.rs:28:21
+   |
+LL |       let f = make_fn(|| {
+   |  _____________________^
+LL | |         let y = &raw mut x;
+LL | |     });
+   | |_____^
+
+error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
+  --> $DIR/borrow-raw-address-of-mutability.rs:37:17
+   |
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to accept closures that implement `FnMut`
+  --> $DIR/borrow-raw-address-of-mutability.rs:36:21
+   |
+LL |       let f = make_fn(move || {
+   |  _____________________^
+LL | |         let y = &raw mut x;
+LL | |     });
+   | |_____^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/break-while-condition.rs b/src/test/ui/break-while-condition.rs
index 7aa5682b923..6064e6ab002 100644
--- a/src/test/ui/break-while-condition.rs
+++ b/src/test/ui/break-while-condition.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 fn main() {
     // The `if false` expressions are simply to
     // make sure we don't avoid checking everything
diff --git a/src/test/ui/break-while-condition.stderr b/src/test/ui/break-while-condition.stderr
index bbc9f21edb0..6960c4fd867 100644
--- a/src/test/ui/break-while-condition.stderr
+++ b/src/test/ui/break-while-condition.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/break-while-condition.rs:7:20
+  --> $DIR/break-while-condition.rs:9:20
    |
 LL |           let _: ! = {
    |  ____________________^
@@ -11,7 +11,7 @@ LL | |         };
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/break-while-condition.rs:14:13
+  --> $DIR/break-while-condition.rs:16:13
    |
 LL | /             while false {
 LL | |                 break
@@ -22,7 +22,7 @@ LL | |             }
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/break-while-condition.rs:22:13
+  --> $DIR/break-while-condition.rs:24:13
    |
 LL | /             while false {
 LL | |                 return
diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
index cb6060525fc..7af38c88f43 100644
--- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
@@ -1,8 +1,8 @@
 error: C-variadic function must be declared with at least one named argument
-  --> $DIR/variadic-ffi-no-fixed-args.rs:2:11
+  --> $DIR/variadic-ffi-no-fixed-args.rs:2:12
    |
 LL |     fn foo(...);
-   |           ^
+   |            ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/cast/cast-as-bool.rs b/src/test/ui/cast/cast-as-bool.rs
index 8130f4dedc9..1aed218aeb4 100644
--- a/src/test/ui/cast/cast-as-bool.rs
+++ b/src/test/ui/cast/cast-as-bool.rs
@@ -5,5 +5,5 @@ fn main() {
     let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
                              //~| HELP compare with zero instead
                              //~| SUGGESTION (1 + 2) != 0
-    let v = "hello" as bool; //~ ERROR cannot cast as `bool`
+    let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid
 }
diff --git a/src/test/ui/cast/cast-as-bool.stderr b/src/test/ui/cast/cast-as-bool.stderr
index 30f8459c2e1..15d94ab69d8 100644
--- a/src/test/ui/cast/cast-as-bool.stderr
+++ b/src/test/ui/cast/cast-as-bool.stderr
@@ -10,12 +10,13 @@ error[E0054]: cannot cast as `bool`
 LL |     let t = (1 + 2) as bool;
    |             ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
 
-error[E0054]: cannot cast as `bool`
+error[E0606]: casting `&'static str` as `bool` is invalid
   --> $DIR/cast-as-bool.rs:8:13
    |
 LL |     let v = "hello" as bool;
-   |             ^^^^^^^^^^^^^^^ unsupported cast
+   |             ^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0054`.
+Some errors have detailed explanations: E0054, E0606.
+For more information about an error, try `rustc --explain E0054`.
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
index b4b40336aa9..4d13a80e4cc 100644
--- a/src/test/ui/closures/issue-52437.stderr
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -4,11 +4,14 @@ error: invalid label name `'static`
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |             ^^^^^^^
 
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-52437.rs:2:13
    |
 LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0282]: type annotations needed
   --> $DIR/issue-52437.rs:2:30
@@ -18,5 +21,5 @@ LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0282, E0744.
+Some errors have detailed explanations: E0282, E0658.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
index 55beb7c2528..0824ce8cd58 100644
--- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs
+++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(never_type_fallback)]
+#![feature(never_type, never_type_fallback)]
 #![allow(unreachable_code)]
 
 use std::error::Error;
diff --git a/src/test/ui/coercion/coerce-to-bang-cast.rs b/src/test/ui/coercion/coerce-to-bang-cast.rs
index ea1384a1dab..8ef19480846 100644
--- a/src/test/ui/coercion/coerce-to-bang-cast.rs
+++ b/src/test/ui/coercion/coerce-to-bang-cast.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 fn foo(x: usize, y: !, z: usize) { }
 
 fn cast_a() {
diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr
index 0e17f32511f..ff30ebc09c6 100644
--- a/src/test/ui/coercion/coerce-to-bang-cast.stderr
+++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr
@@ -1,5 +1,5 @@
 error[E0605]: non-primitive cast: `i32` as `!`
-  --> $DIR/coerce-to-bang-cast.rs:4:13
+  --> $DIR/coerce-to-bang-cast.rs:6:13
    |
 LL |     let y = {return; 22} as !;
    |             ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     let y = {return; 22} as !;
    = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
 
 error[E0605]: non-primitive cast: `i32` as `!`
-  --> $DIR/coerce-to-bang-cast.rs:9:13
+  --> $DIR/coerce-to-bang-cast.rs:11:13
    |
 LL |     let y = 22 as !;
    |             ^^^^^^^
diff --git a/src/test/ui/coercion/coerce-to-bang.rs b/src/test/ui/coercion/coerce-to-bang.rs
index d52f79fbb7a..1e06934d09f 100644
--- a/src/test/ui/coercion/coerce-to-bang.rs
+++ b/src/test/ui/coercion/coerce-to-bang.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 fn foo(x: usize, y: !, z: usize) { }
 
 fn call_foo_a() {
diff --git a/src/test/ui/coercion/coerce-to-bang.stderr b/src/test/ui/coercion/coerce-to-bang.stderr
index ca427059737..390aa7c692d 100644
--- a/src/test/ui/coercion/coerce-to-bang.stderr
+++ b/src/test/ui/coercion/coerce-to-bang.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:4:17
+  --> $DIR/coerce-to-bang.rs:6:17
    |
 LL |     foo(return, 22, 44);
    |                 ^^ expected `!`, found integer
@@ -8,7 +8,7 @@ LL |     foo(return, 22, 44);
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:16:13
+  --> $DIR/coerce-to-bang.rs:18:13
    |
 LL |     foo(22, 44, return);
    |             ^^ expected `!`, found integer
@@ -17,7 +17,7 @@ LL |     foo(22, 44, return);
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:24:12
+  --> $DIR/coerce-to-bang.rs:26:12
    |
 LL |     foo(a, b, c); // ... and hence a reference to `a` is expected to diverge.
    |            ^ expected `!`, found integer
@@ -26,7 +26,7 @@ LL |     foo(a, b, c); // ... and hence a reference to `a` is expected to diverg
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:34:12
+  --> $DIR/coerce-to-bang.rs:36:12
    |
 LL |     foo(a, b, c);
    |            ^ expected `!`, found integer
@@ -35,7 +35,7 @@ LL |     foo(a, b, c);
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:43:12
+  --> $DIR/coerce-to-bang.rs:45:12
    |
 LL |     foo(a, b, c);
    |            ^ expected `!`, found integer
@@ -44,7 +44,7 @@ LL |     foo(a, b, c);
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:48:21
+  --> $DIR/coerce-to-bang.rs:50:21
    |
 LL |     let x: [!; 2] = [return, 22];
    |            ------   ^^^^^^^^^^^^ expected `!`, found integer
@@ -55,7 +55,7 @@ LL |     let x: [!; 2] = [return, 22];
               found array `[{integer}; 2]`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:53:22
+  --> $DIR/coerce-to-bang.rs:55:22
    |
 LL |     let x: [!; 2] = [22, return];
    |                      ^^ expected `!`, found integer
@@ -64,7 +64,7 @@ LL |     let x: [!; 2] = [22, return];
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:58:37
+  --> $DIR/coerce-to-bang.rs:60:37
    |
 LL |     let x: (usize, !, usize) = (22, 44, 66);
    |                                     ^^ expected `!`, found integer
@@ -73,7 +73,7 @@ LL |     let x: (usize, !, usize) = (22, 44, 66);
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:63:41
+  --> $DIR/coerce-to-bang.rs:65:41
    |
 LL |     let x: (usize, !, usize) = (return, 44, 66);
    |                                         ^^ expected `!`, found integer
@@ -82,7 +82,7 @@ LL |     let x: (usize, !, usize) = (return, 44, 66);
               found type `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/coerce-to-bang.rs:74:37
+  --> $DIR/coerce-to-bang.rs:76:37
    |
 LL |     let x: (usize, !, usize) = (22, 44, return);
    |                                     ^^ expected `!`, found integer
diff --git a/src/test/ui/command/command-argv0-debug.rs b/src/test/ui/command/command-argv0-debug.rs
new file mode 100644
index 00000000000..133d2ada2b2
--- /dev/null
+++ b/src/test/ui/command/command-argv0-debug.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+// ignore-windows - this is a unix-specific test
+// ignore-cloudabi no processes
+// ignore-emscripten no processes
+// ignore-sgx no processes
+#![feature(process_set_argv0)]
+
+use std::os::unix::process::CommandExt;
+use std::process::Command;
+
+fn main() {
+    let mut command = Command::new("some-boring-name");
+
+    assert_eq!(format!("{:?}", command), r#""some-boring-name""#);
+
+    command.args(&["1", "2", "3"]);
+
+    assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#);
+
+    command.arg0("exciting-name");
+
+    assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#);
+}
diff --git a/src/test/ui/command-argv0.rs b/src/test/ui/command/command-argv0.rs
index 56a9fb4d391..56a9fb4d391 100644
--- a/src/test/ui/command-argv0.rs
+++ b/src/test/ui/command/command-argv0.rs
diff --git a/src/test/ui/command-exec.rs b/src/test/ui/command/command-exec.rs
index 568be67abe3..568be67abe3 100644
--- a/src/test/ui/command-exec.rs
+++ b/src/test/ui/command/command-exec.rs
diff --git a/src/test/ui/command-pre-exec.rs b/src/test/ui/command/command-pre-exec.rs
index c0fc554183a..c0fc554183a 100644
--- a/src/test/ui/command-pre-exec.rs
+++ b/src/test/ui/command/command-pre-exec.rs
diff --git a/src/test/ui/command-uid-gid.rs b/src/test/ui/command/command-uid-gid.rs
index f867106c35d..f867106c35d 100644
--- a/src/test/ui/command-uid-gid.rs
+++ b/src/test/ui/command/command-uid-gid.rs
diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs
index 8397d204f35..7fa059583f5 100644
--- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs
+++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.rs
@@ -6,6 +6,7 @@ pub fn no_debug() {
 pub fn no_hash() {
     use std::collections::HashSet;
     let mut set = HashSet::new();
+    //~^ ERROR arrays only have std trait implementations for lengths 0..=32
     set.insert([0_usize; 33]);
     //~^ ERROR arrays only have std trait implementations for lengths 0..=32
 }
diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
index 594a0d4b5d8..d885c98dcb2 100644
--- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
@@ -8,15 +8,24 @@ LL |     println!("{:?}", [0_usize; 33]);
    = note: required by `std::fmt::Debug::fmt`
 
 error[E0277]: arrays only have std trait implementations for lengths 0..=32
-  --> $DIR/core-traits-no-impls-length-33.rs:9:16
+  --> $DIR/core-traits-no-impls-length-33.rs:10:16
    |
 LL |     set.insert([0_usize; 33]);
    |                ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]`
    |
    = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]`
 
+error[E0277]: arrays only have std trait implementations for lengths 0..=32
+  --> $DIR/core-traits-no-impls-length-33.rs:8:19
+   |
+LL |     let mut set = HashSet::new();
+   |                   ^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]`
+   |
+   = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]`
+   = note: required by `std::collections::HashSet::<T>::new`
+
 error[E0369]: binary operation `==` cannot be applied to type `[usize; 33]`
-  --> $DIR/core-traits-no-impls-length-33.rs:14:19
+  --> $DIR/core-traits-no-impls-length-33.rs:15:19
    |
 LL |     [0_usize; 33] == [1_usize; 33]
    |     ------------- ^^ ------------- [usize; 33]
@@ -26,7 +35,7 @@ LL |     [0_usize; 33] == [1_usize; 33]
    = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]`
 
 error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]`
-  --> $DIR/core-traits-no-impls-length-33.rs:19:19
+  --> $DIR/core-traits-no-impls-length-33.rs:20:19
    |
 LL |     [0_usize; 33] < [1_usize; 33]
    |     ------------- ^ ------------- [usize; 33]
@@ -36,7 +45,7 @@ LL |     [0_usize; 33] < [1_usize; 33]
    = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]`
 
 error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied
-  --> $DIR/core-traits-no-impls-length-33.rs:24:14
+  --> $DIR/core-traits-no-impls-length-33.rs:25:14
    |
 LL |     for _ in &[0_usize; 33] {
    |              ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]`
@@ -48,7 +57,7 @@ LL |     for _ in &[0_usize; 33] {
              <&'a mut [T] as std::iter::IntoIterator>
    = note: required by `std::iter::IntoIterator::into_iter`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0277, E0369.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr
index 32adc63156a..8379cbd4908 100644
--- a/src/test/ui/const-generics/cannot-infer-const-args.stderr
+++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr
@@ -10,7 +10,7 @@ error[E0282]: type annotations needed
   --> $DIR/cannot-infer-const-args.rs:9:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for `fn() -> usize {foo::<_: usize>}`
+   |     ^^^ cannot infer type for fn item `fn() -> usize {foo::<_: usize>}`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
index 2d9b6edb8a2..44eab8baa40 100644
--- a/src/test/ui/const-generics/fn-const-param-infer.stderr
+++ b/src/test/ui/const-generics/fn-const-param-infer.stderr
@@ -30,7 +30,7 @@ error[E0282]: type annotations needed
   --> $DIR/fn-const-param-infer.rs:22:23
    |
 LL |     let _ = Checked::<generic>;
-   |                       ^^^^^^^ cannot infer type for `T`
+   |                       ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic`
 
 error[E0308]: mismatched types
   --> $DIR/fn-const-param-infer.rs:25:40
diff --git a/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs b/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs
index e54cbb09804..b1d5440b41a 100644
--- a/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs
+++ b/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs
@@ -7,6 +7,7 @@
 
 #[rustc_promotable]
 #[stable(since="1.0.0", feature = "mep")]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 #[inline]
 pub const fn foo() -> usize { 22 }
 
@@ -15,6 +16,7 @@ pub struct Foo(usize);
 
 impl Foo {
     #[stable(since="1.0.0", feature = "mep")]
+    #[rustc_const_stable(feature = "mep", since = "1.0.0")]
     #[inline]
     #[rustc_promotable]
     pub const fn foo() -> usize { 22 }
diff --git a/src/test/ui/consts/const-address-of-interior-mut.rs b/src/test/ui/consts/const-address-of-interior-mut.rs
new file mode 100644
index 00000000000..60c7c31daca
--- /dev/null
+++ b/src/test/ui/consts/const-address-of-interior-mut.rs
@@ -0,0 +1,16 @@
+#![feature(raw_ref_op)]
+
+use std::cell::Cell;
+
+const A: () = { let x = Cell::new(2); &raw const x; };      //~ ERROR interior mutability
+
+static B: () = { let x = Cell::new(2); &raw const x; };     //~ ERROR interior mutability
+
+static mut C: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
+
+const fn foo() {
+    let x = Cell::new(0);
+    let y = &raw const x;                                   //~ ERROR interior mutability
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-address-of-interior-mut.stderr b/src/test/ui/consts/const-address-of-interior-mut.stderr
new file mode 100644
index 00000000000..f15174c33b3
--- /dev/null
+++ b/src/test/ui/consts/const-address-of-interior-mut.stderr
@@ -0,0 +1,27 @@
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/const-address-of-interior-mut.rs:5:39
+   |
+LL | const A: () = { let x = Cell::new(2); &raw const x; };
+   |                                       ^^^^^^^^^^^^
+
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/const-address-of-interior-mut.rs:7:40
+   |
+LL | static B: () = { let x = Cell::new(2); &raw const x; };
+   |                                        ^^^^^^^^^^^^
+
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/const-address-of-interior-mut.rs:9:44
+   |
+LL | static mut C: () = { let x = Cell::new(2); &raw const x; };
+   |                                            ^^^^^^^^^^^^
+
+error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
+  --> $DIR/const-address-of-interior-mut.rs:13:13
+   |
+LL |     let y = &raw const x;
+   |             ^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0492`.
diff --git a/src/test/ui/consts/const-address-of-mut.rs b/src/test/ui/consts/const-address-of-mut.rs
new file mode 100644
index 00000000000..fe9188cb490
--- /dev/null
+++ b/src/test/ui/consts/const-address-of-mut.rs
@@ -0,0 +1,14 @@
+#![feature(raw_ref_op)]
+
+const A: () = { let mut x = 2; &raw mut x; };           //~ ERROR `&raw mut` is not allowed
+
+static B: () = { let mut x = 2; &raw mut x; };          //~ ERROR `&raw mut` is not allowed
+
+static mut C: () = { let mut x = 2; &raw mut x; };      //~ ERROR `&raw mut` is not allowed
+
+const fn foo() {
+    let mut x = 0;
+    let y = &raw mut x;                                 //~ ERROR `&raw mut` is not allowed
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-address-of-mut.stderr b/src/test/ui/consts/const-address-of-mut.stderr
new file mode 100644
index 00000000000..15f2296c42c
--- /dev/null
+++ b/src/test/ui/consts/const-address-of-mut.stderr
@@ -0,0 +1,39 @@
+error[E0658]: `&raw mut` is not allowed in constants
+  --> $DIR/const-address-of-mut.rs:3:32
+   |
+LL | const A: () = { let mut x = 2; &raw mut x; };
+   |                                ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: `&raw mut` is not allowed in statics
+  --> $DIR/const-address-of-mut.rs:5:33
+   |
+LL | static B: () = { let mut x = 2; &raw mut x; };
+   |                                 ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: `&raw mut` is not allowed in statics
+  --> $DIR/const-address-of-mut.rs:7:37
+   |
+LL | static mut C: () = { let mut x = 2; &raw mut x; };
+   |                                     ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: `&raw mut` is not allowed in constant functions
+  --> $DIR/const-address-of-mut.rs:11:13
+   |
+LL |     let y = &raw mut x;
+   |             ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-address-of.rs b/src/test/ui/consts/const-address-of.rs
new file mode 100644
index 00000000000..ba162f2a2ba
--- /dev/null
+++ b/src/test/ui/consts/const-address-of.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(raw_ref_op)]
+
+const A: *const i32 = &raw const *&2;
+static B: () = { &raw const *&2; };
+static mut C: *const i32 = &raw const *&2;
+const D: () = { let x = 2; &raw const x; };
+static E: () = { let x = 2; &raw const x; };
+static mut F: () = { let x = 2; &raw const x; };
+
+const fn const_ptr() {
+    let x = 0;
+    let ptr = &raw const x;
+    let r = &x;
+    let ptr2 = &raw const *r;
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/auxiliary/stability.rs b/src/test/ui/consts/const-eval/auxiliary/stability.rs
index 5551d35bcc8..830db55207f 100644
--- a/src/test/ui/consts/const-eval/auxiliary/stability.rs
+++ b/src/test/ui/consts/const-eval/auxiliary/stability.rs
@@ -3,9 +3,9 @@
 #![crate_type="rlib"]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#![feature(rustc_const_unstable, const_fn)]
+#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 pub const fn foo() -> u32 { 42 }
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
index 90028690990..c4b89b50bc4 100644
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
+++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
@@ -3,11 +3,11 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn)]
+#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const fn foo() -> u32 { 42 }
 
 fn meh() -> u32 { 42 }
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
index 516ca4f3f77..f6ab0bd7dbe 100644
--- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs
@@ -1,5 +1,6 @@
 // Regression test for #66975
 #![warn(const_err)]
+#![feature(never_type)]
 
 struct PrintName<T>(T);
 
diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
index e2bd8d0cc85..24830f7344c 100644
--- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
+++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr
@@ -1,5 +1,5 @@
 warning: any use of this value will cause an error
-  --> $DIR/index-out-of-bounds-never-type.rs:7:61
+  --> $DIR/index-out-of-bounds-never-type.rs:8:61
    |
 LL |     const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
    |     --------------------------------------------------------^^^^^---
@@ -13,7 +13,7 @@ LL | #![warn(const_err)]
    |         ^^^^^^^^^
 
 error: erroneous constant encountered
-  --> $DIR/index-out-of-bounds-never-type.rs:12:13
+  --> $DIR/index-out-of-bounds-never-type.rs:13:13
    |
 LL |     let _ = PrintName::<T>::VOID;
    |             ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/consts/const-eval/infinite_loop.stderr b/src/test/ui/consts/const-eval/infinite_loop.stderr
index de2624d7f7a..ed3c66db2cd 100644
--- a/src/test/ui/consts/const-eval/infinite_loop.stderr
+++ b/src/test/ui/consts/const-eval/infinite_loop.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/infinite_loop.rs:7:9
    |
 LL | /         while n != 0 {
@@ -8,6 +8,10 @@ LL | |
 LL | |
 LL | |         }
    | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
   --> $DIR/infinite_loop.rs:9:17
@@ -39,5 +43,5 @@ LL |             n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0658, E0744.
+Some errors have detailed explanations: E0080, E0658.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-52442.stderr b/src/test/ui/consts/const-eval/issue-52442.stderr
index fa2272f8d63..c8ac4b1a762 100644
--- a/src/test/ui/consts/const-eval/issue-52442.stderr
+++ b/src/test/ui/consts/const-eval/issue-52442.stderr
@@ -1,8 +1,11 @@
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-52442.rs:2:14
    |
 LL |     [();  { &loop { break } as *const _ as usize } ];
    |              ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constants is unstable
   --> $DIR/issue-52442.rs:2:13
@@ -21,5 +24,5 @@ LL |     [();  { &loop { break } as *const _ as usize } ];
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0658, E0744.
+Some errors have detailed explanations: E0080, E0658.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr
index b8267f495de..7c0c735f9a4 100644
--- a/src/test/ui/consts/const-eval/issue-52475.stderr
+++ b/src/test/ui/consts/const-eval/issue-52475.stderr
@@ -1,4 +1,4 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/issue-52475.rs:6:9
    |
 LL | /         while n < 5 {
@@ -7,6 +7,10 @@ LL | |             n = (n + 1) % 5;
 LL | |             x = &0; // Materialize a new AllocId
 LL | |         }
    | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 warning: Constant evaluating a complex constant, this might take some time
   --> $DIR/issue-52475.rs:2:18
@@ -29,5 +33,5 @@ LL |             n = (n + 1) % 5;
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0080, E0744.
+Some errors have detailed explanations: E0080, E0658.
 For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-62272.stderr b/src/test/ui/consts/const-eval/issue-62272.stderr
index 573d04f5e47..a02bbe557cf 100644
--- a/src/test/ui/consts/const-eval/issue-62272.stderr
+++ b/src/test/ui/consts/const-eval/issue-62272.stderr
@@ -1,15 +1,21 @@
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-62272.rs:7:17
    |
 LL | const FOO: () = loop { break; };
    |                 ^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
+error[E0658]: `loop` is not allowed in a `const`
   --> $DIR/issue-62272.rs:10:20
    |
 LL |     [FOO; { let x; loop { x = 5; break; } x }];
    |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0744`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
index b39d9af5546..a7cbdb40ef1 100644
--- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -1,6 +1,7 @@
 // Regression test for #66975
 #![warn(const_err)]
 #![feature(const_panic)]
+#![feature(never_type)]
 
 struct PrintName;
 
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
index c07c8c65a2f..e15952c20e4 100644
--- a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
@@ -1,10 +1,10 @@
 warning: any use of this value will cause an error
-  --> $DIR/panic-assoc-never-type.rs:8:21
+  --> $DIR/panic-assoc-never-type.rs:9:21
    |
 LL |     const VOID: ! = panic!();
    |     ----------------^^^^^^^^-
    |                     |
-   |                     the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:8:21
+   |                     the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:9:21
    |
 note: lint level defined here
   --> $DIR/panic-assoc-never-type.rs:2:9
@@ -14,7 +14,7 @@ LL | #![warn(const_err)]
    = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
-  --> $DIR/panic-assoc-never-type.rs:13:13
+  --> $DIR/panic-assoc-never-type.rs:14:13
    |
 LL |     let _ = PrintName::VOID;
    |             ^^^^^^^^^^^^^^^ referenced constant has errors
diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs
index 42eabbf5847..b1a7d8ae676 100644
--- a/src/test/ui/consts/const-eval/panic-never-type.rs
+++ b/src/test/ui/consts/const-eval/panic-never-type.rs
@@ -1,6 +1,7 @@
 // Regression test for #66975
 #![warn(const_err)]
 #![feature(const_panic)]
+#![feature(never_type)]
 
 const VOID: ! = panic!();
 //~^ WARN any use of this value will cause an error
diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr
index 4fb11a61525..9e91fdf4514 100644
--- a/src/test/ui/consts/const-eval/panic-never-type.stderr
+++ b/src/test/ui/consts/const-eval/panic-never-type.stderr
@@ -1,10 +1,10 @@
 warning: any use of this value will cause an error
-  --> $DIR/panic-never-type.rs:5:17
+  --> $DIR/panic-never-type.rs:6:17
    |
 LL | const VOID: ! = panic!();
    | ----------------^^^^^^^^-
    |                 |
-   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17
+   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17
    |
 note: lint level defined here
   --> $DIR/panic-never-type.rs:2:9
@@ -14,7 +14,7 @@ LL | #![warn(const_err)]
    = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
-  --> $DIR/panic-never-type.rs:9:13
+  --> $DIR/panic-never-type.rs:10:13
    |
 LL |     let _ = VOID;
    |             ^^^^ referenced constant has errors
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
index 1f810c40572..a5c2a57c6c8 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs
@@ -2,7 +2,6 @@
 #![allow(unused)]
 #![allow(const_err)] // make sure we cannot allow away the errors tested here
 
-// normalize-stderr-test "alignment \d+" -> "alignment N"
 // normalize-stderr-test "offset \d+" -> "offset N"
 // normalize-stderr-test "allocation \d+" -> "allocation N"
 // normalize-stderr-test "size \d+" -> "size N"
@@ -149,11 +148,23 @@ const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }
 //~^ ERROR it is undefined behavior to use this value
 
 // # raw trait object
-const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust};
+const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust};
 //~^ ERROR it is undefined behavior to use this value
 const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust};
 //~^ ERROR it is undefined behavior to use this value
 const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw
 
+// Const eval fails for these, so they need to be statics to error.
+static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe {
+    DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust
+    //~^ ERROR could not evaluate static initializer
+};
+static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
+    DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust
+    //~^ ERROR could not evaluate static initializer
+};
+
 fn main() {
+    let _ = RAW_TRAIT_OBJ_VTABLE_NULL;
+    let _ = RAW_TRAIT_OBJ_VTABLE_INVALID;
 }
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
index 85fb8ac2a4a..ce57d680dc9 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:87:1
+  --> $DIR/ub-wide-ptr.rs:86:1
    |
 LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds)
@@ -7,7 +7,7 @@ LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr:
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:90:1
+  --> $DIR/ub-wide-ptr.rs:89:1
    |
 LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -15,7 +15,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr {
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:93:1
+  --> $DIR/ub-wide-ptr.rs:92:1
    |
 LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -23,7 +23,7 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRe
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:97:1
+  --> $DIR/ub-wide-ptr.rs:96:1
    |
 LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
@@ -31,7 +31,7 @@ LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:100:1
+  --> $DIR/ub-wide-ptr.rs:99:1
    |
 LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0
@@ -39,7 +39,7 @@ LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:107:1
+  --> $DIR/ub-wide-ptr.rs:106:1
    |
 LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer
@@ -47,7 +47,7 @@ LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.sli
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:110:1
+  --> $DIR/ub-wide-ptr.rs:109:1
    |
 LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds)
@@ -55,7 +55,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { p
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:113:1
+  --> $DIR/ub-wide-ptr.rs:112:1
    |
 LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
@@ -63,7 +63,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:117:1
+  --> $DIR/ub-wide-ptr.rs:116:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something less or equal to 1
@@ -71,7 +71,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:123:1
+  --> $DIR/ub-wide-ptr.rs:122:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something less or equal to 1
@@ -79,7 +79,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute {
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:126:1
+  --> $DIR/ub-wide-ptr.rs:125:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something less or equal to 1
@@ -87,7 +87,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTrans
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:133:1
+  --> $DIR/ub-wide-ptr.rs:132:1
    |
 LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer
@@ -95,7 +95,7 @@ LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:138:1
+  --> $DIR/ub-wide-ptr.rs:137:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
@@ -103,7 +103,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr:
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:141:1
+  --> $DIR/ub-wide-ptr.rs:140:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
@@ -111,7 +111,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2:
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:144:1
+  --> $DIR/ub-wide-ptr.rs:143:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
@@ -119,7 +119,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDy
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:148:1
+  --> $DIR/ub-wide-ptr.rs:147:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.<dyn-downcast>, but expected something less or equal to 1
@@ -127,21 +127,33 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:152:1
+  --> $DIR/ub-wide-ptr.rs:151:1
    |
-LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust};
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
+LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust};
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-wide-ptr.rs:154:1
+  --> $DIR/ub-wide-ptr.rs:153:1
    |
 LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
 
-error: aborting due to 18 previous errors
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ub-wide-ptr.rs:159:5
+   |
+LL |     DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/ub-wide-ptr.rs:163:5
+   |
+LL |     DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N
+
+error: aborting due to 20 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-labeled-break.stderr b/src/test/ui/consts/const-labeled-break.stderr
index ec32386439f..1282008fb63 100644
--- a/src/test/ui/consts/const-labeled-break.stderr
+++ b/src/test/ui/consts/const-labeled-break.stderr
@@ -1,9 +1,13 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/const-labeled-break.rs:10:19
    |
 LL | const CRASH: () = 'a: while break 'a {};
    |                   ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0744`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
new file mode 100644
index 00000000000..130ba9283b1
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+#![feature(const_mut_refs)]
+#![feature(const_fn)]
+#![feature(raw_ref_op)]
+
+struct Foo {
+    x: usize
+}
+
+const fn foo() -> Foo {
+    Foo { x: 0 }
+}
+
+impl Foo {
+    const fn bar(&mut self) -> *mut usize {
+        &raw mut self.x
+    }
+}
+
+const fn baz(foo: &mut Foo)-> *mut usize {
+    &raw mut foo.x
+}
+
+const _: () = {
+    foo().bar();
+    baz(&mut foo());
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
index 99006a20b1b..33abfec02a8 100644
--- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_mut_refs)]
+#![feature(const_fn)]
 
 struct Foo {
     x: usize
diff --git a/src/test/ui/consts/const-prop-ice3.rs b/src/test/ui/consts/const-prop-ice3.rs
new file mode 100644
index 00000000000..8ab011661e3
--- /dev/null
+++ b/src/test/ui/consts/const-prop-ice3.rs
@@ -0,0 +1,7 @@
+// run-pass (ensure that const-prop is run)
+
+struct A<T: ?Sized>(T);
+
+fn main() {
+    let _x = &(&A([2, 3]) as &A<[i32]>).0 as *const [i32] as *const i32;
+}
diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs
index 8bd1929956f..a53293743d5 100644
--- a/src/test/ui/consts/control-flow/basics.rs
+++ b/src/test/ui/consts/control-flow/basics.rs
@@ -1,9 +1,11 @@
-// Test basic functionality of `if` and `match` in a const context.
+// Test basic functionality of control flow in a const context.
 
 // run-pass
 
 #![feature(const_panic)]
 #![feature(const_if_match)]
+#![feature(const_loop)]
+#![feature(const_fn)]
 
 const X: u32 = 4;
 const Y: u32 = 5;
@@ -29,15 +31,57 @@ const fn gcd(a: u32, b: u32) -> u32 {
     gcd(b, a % b)
 }
 
+const fn fib(n: u64) -> u64 {
+    if n == 0 {
+        return 0;
+    }
+
+    let mut fib = (0, 1);
+    let mut i = 1;
+    while i < n {
+        fib = (fib.1, fib.0 + fib.1);
+        i += 1;
+    }
+
+    fib.1
+}
+
+const fn is_prime(n: u64) -> bool {
+    if n % 2 == 0 {
+        return false;
+    }
+
+    let mut div = 3;
+    loop {
+        if n % div == 0 {
+            return false;
+        }
+
+        if div * div > n {
+            return true;
+        }
+
+        div += 2;
+    }
+}
+
+macro_rules! const_assert {
+    ($expr:expr) => {
+        const _: () = assert!($expr);
+        assert!($expr);
+    }
+}
+
 fn main() {
-    const _: () = assert!(abs_diff(4, 5) == abs_diff(5, 4));
-    assert_eq!(abs_diff(4, 5), abs_diff(5, 4));
+    const_assert!(abs_diff(4, 5) == abs_diff(5, 4));
+    const_assert!(ABS_DIFF == abs_diff(5, 4));
+
+    const_assert!(gcd(48, 18) == 6);
+    const_assert!(gcd(18, 48) == 6);
 
-    const _: () = assert!(ABS_DIFF == abs_diff(5, 4));
-    assert_eq!(ABS_DIFF, abs_diff(5, 4));
+    const_assert!(fib(2) == 1);
+    const_assert!(fib(8) == 21);
 
-    const _: () = assert!(gcd(48, 18) == 6);
-    const _: () = assert!(gcd(18, 48) == 6);
-    assert_eq!(gcd(48, 18), 6);
-    assert_eq!(gcd(18, 48), 6);
+    const_assert!(is_prime(113));
+    const_assert!(!is_prime(117));
 }
diff --git a/src/test/ui/consts/control-flow/drop-failure.rs b/src/test/ui/consts/control-flow/drop-failure.rs
index c6bea89e6e6..9da5546976c 100644
--- a/src/test/ui/consts/control-flow/drop-failure.rs
+++ b/src/test/ui/consts/control-flow/drop-failure.rs
@@ -1,4 +1,5 @@
 #![feature(const_if_match)]
+#![feature(const_loop)]
 
 // `x` is *not* always moved into the final value may be dropped inside the initializer.
 const _: Option<Vec<i32>> = {
@@ -32,4 +33,29 @@ const _: Vec<i32> = {
     }
 };
 
+const _: Option<Vec<i32>> = {
+    let mut some = Some(Vec::new());
+    let mut tmp = None;
+    //~^ ERROR destructors cannot be evaluated at compile-time
+
+    let mut i = 0;
+    while i < 10 {
+        tmp = some;
+        some = None;
+
+        // We can escape the loop with `Some` still in `tmp`,
+        // which would require that it be dropped at the end of the block.
+        if i > 100 {
+            break;
+        }
+
+        some = tmp;
+        tmp = None;
+
+        i += 1;
+    }
+
+    some
+};
+
 fn main() {}
diff --git a/src/test/ui/consts/control-flow/drop-failure.stderr b/src/test/ui/consts/control-flow/drop-failure.stderr
index 35ceb3b2770..3eec3a929a0 100644
--- a/src/test/ui/consts/control-flow/drop-failure.stderr
+++ b/src/test/ui/consts/control-flow/drop-failure.stderr
@@ -1,21 +1,27 @@
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:6:9
+  --> $DIR/drop-failure.rs:7:9
    |
 LL |     let x = Some(Vec::new());
    |         ^ constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:19:9
+  --> $DIR/drop-failure.rs:20:9
    |
 LL |     let vec_tuple = (Vec::new(),);
    |         ^^^^^^^^^ constants cannot evaluate destructors
 
 error[E0493]: destructors cannot be evaluated at compile-time
-  --> $DIR/drop-failure.rs:27:9
+  --> $DIR/drop-failure.rs:28:9
    |
 LL |     let x: Result<_, Vec<i32>> = Ok(Vec::new());
    |         ^ constants cannot evaluate destructors
 
-error: aborting due to 3 previous errors
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-failure.rs:38:9
+   |
+LL |     let mut tmp = None;
+   |         ^^^^^^^ constants cannot evaluate destructors
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/control-flow/drop-success.rs b/src/test/ui/consts/control-flow/drop-success.rs
index 92b3f6ec92e..185d6b63996 100644
--- a/src/test/ui/consts/control-flow/drop-success.rs
+++ b/src/test/ui/consts/control-flow/drop-success.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(const_if_match)]
+#![feature(const_loop)]
 
 // `x` is always moved into the final value and is not dropped inside the initializer.
 const _: Option<Vec<i32>> = {
@@ -21,4 +22,24 @@ const _: Option<Vec<i32>> = {
     }
 };
 
+const _: Option<Vec<i32>> = {
+    let mut some = Some(Vec::new());
+    let mut tmp = None;
+
+    let mut i = 0;
+    while i < 10 {
+        tmp = some;
+        some = None;
+
+        // We can never exit the loop with `Some` in `tmp`.
+
+        some = tmp;
+        tmp = None;
+
+        i += 1;
+    }
+
+    some
+};
+
 fn main() {}
diff --git a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
index 6bbbdd972a2..7887fd12e57 100644
--- a/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
+++ b/src/test/ui/consts/control-flow/exhaustive-c-like-enum-match.rs
@@ -3,6 +3,7 @@
 // check-pass
 
 #![feature(const_if_match)]
+#![feature(const_fn)]
 
 enum E {
     A,
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
index 21e3f2af15a..95096723b3c 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.if_match.stderr
@@ -1,5 +1,5 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate-const-if-match.rs:108:1
+  --> $DIR/feature-gate-const-if-match.rs:109:1
    |
 LL | / fn main() {
 LL | |     let _ = [0; {
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
index 00576d50ac6..e4b65257531 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.rs
@@ -6,6 +6,7 @@
 
 #![feature(rustc_attrs)]
 #![cfg_attr(if_match, feature(const_if_match))]
+#![feature(const_fn)]
 
 const _: i32 = if true { //[stock]~ ERROR `if` is not allowed in a `const`
     5
diff --git a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
index d3c6a51923f..e846ee4ab6a 100644
--- a/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
+++ b/src/test/ui/consts/control-flow/feature-gate-const-if-match.stock.stderr
@@ -1,5 +1,5 @@
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:10:16
+  --> $DIR/feature-gate-const-if-match.rs:11:16
    |
 LL |   const _: i32 = if true {
    |  ________________^
@@ -13,7 +13,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:16:16
+  --> $DIR/feature-gate-const-if-match.rs:17:16
    |
 LL |   const _: i32 = if let Some(true) = Some(false) {
    |  ________________^
@@ -27,7 +27,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:22:16
+  --> $DIR/feature-gate-const-if-match.rs:23:16
    |
 LL |   const _: i32 = match 1 {
    |  ________________^
@@ -41,7 +41,7 @@ LL | | };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:29:13
+  --> $DIR/feature-gate-const-if-match.rs:30:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,7 +50,7 @@ LL |     let x = if true { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:31:13
+  --> $DIR/feature-gate-const-if-match.rs:32:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL |     let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static`
-  --> $DIR/feature-gate-const-if-match.rs:33:5
+  --> $DIR/feature-gate-const-if-match.rs:34:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:38:13
+  --> $DIR/feature-gate-const-if-match.rs:39:13
    |
 LL |     let x = if true { 0 } else { 1 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     let x = if true { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:40:13
+  --> $DIR/feature-gate-const-if-match.rs:41:13
    |
 LL |     let x = match x { 0 => 1, _ => 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -86,7 +86,7 @@ LL |     let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `static mut`
-  --> $DIR/feature-gate-const-if-match.rs:42:5
+  --> $DIR/feature-gate-const-if-match.rs:43:5
    |
 LL |     if let Some(x) = Some(x) { x } else { 1 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,7 +95,7 @@ LL |     if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:47:5
+  --> $DIR/feature-gate-const-if-match.rs:48:5
    |
 LL |     if true { 5 } else { 6 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +104,7 @@ LL |     if true { 5 } else { 6 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:51:5
+  --> $DIR/feature-gate-const-if-match.rs:52:5
    |
 LL | /     if let Some(true) = a {
 LL | |         0
@@ -117,7 +117,7 @@ LL | |     }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:59:5
+  --> $DIR/feature-gate-const-if-match.rs:60:5
    |
 LL | /     match i {
 LL | |         i if i > 10 => i,
@@ -130,7 +130,7 @@ LL | |     }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:90:17
+  --> $DIR/feature-gate-const-if-match.rs:91:17
    |
 LL |         let x = if y { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL |         let x = if y { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:92:17
+  --> $DIR/feature-gate-const-if-match.rs:93:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL |         let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const fn`
-  --> $DIR/feature-gate-const-if-match.rs:94:9
+  --> $DIR/feature-gate-const-if-match.rs:95:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:110:17
+  --> $DIR/feature-gate-const-if-match.rs:111:17
    |
 LL |         let x = if false { 0 } else { 1 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -166,7 +166,7 @@ LL |         let x = if false { 0 } else { 1 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:112:17
+  --> $DIR/feature-gate-const-if-match.rs:113:17
    |
 LL |         let x = match x { 0 => 1, _ => 0 };
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@ LL |         let x = match x { 0 => 1, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:114:9
+  --> $DIR/feature-gate-const-if-match.rs:115:9
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@ LL |         if let Some(x) = Some(x) { x } else { 1 }
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:67:21
+  --> $DIR/feature-gate-const-if-match.rs:68:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL |     const IF: i32 = if true { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:70:25
+  --> $DIR/feature-gate-const-if-match.rs:71:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,7 +202,7 @@ LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:73:24
+  --> $DIR/feature-gate-const-if-match.rs:74:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:78:21
+  --> $DIR/feature-gate-const-if-match.rs:79:21
    |
 LL |     const IF: i32 = if true { 5 } else { 6 };
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL |     const IF: i32 = if true { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:81:25
+  --> $DIR/feature-gate-const-if-match.rs:82:25
    |
 LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL |     const IF_LET: i32 = if let Some(true) = None { 5 } else { 6 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0658]: `match` is not allowed in a `const`
-  --> $DIR/feature-gate-const-if-match.rs:84:24
+  --> $DIR/feature-gate-const-if-match.rs:85:24
    |
 LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -238,7 +238,7 @@ LL |     const MATCH: i32 = match 0 { 1 => 2, _ => 0 };
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0019]: constant contains unimplemented expression type
-  --> $DIR/feature-gate-const-if-match.rs:114:21
+  --> $DIR/feature-gate-const-if-match.rs:115:21
    |
 LL |         if let Some(x) = Some(x) { x } else { 1 }
    |                     ^
diff --git a/src/test/ui/consts/control-flow/interior-mutability.rs b/src/test/ui/consts/control-flow/interior-mutability.rs
index fcced75fcb0..c2439f4a7bf 100644
--- a/src/test/ui/consts/control-flow/interior-mutability.rs
+++ b/src/test/ui/consts/control-flow/interior-mutability.rs
@@ -2,6 +2,7 @@
 // disqualifies it from promotion.
 
 #![feature(const_if_match)]
+#![feature(const_loop)]
 
 use std::cell::Cell;
 
@@ -21,7 +22,26 @@ const Y: Option<Cell<i32>> = {
     y
 };
 
+const Z: Option<Cell<i32>> = {
+    let mut z = None;
+    let mut i = 0;
+    while i < 10 {
+        if i == 8 {
+            z = Some(Cell::new(4));
+        }
+
+        if i == 9 {
+            z = None;
+        }
+
+        i += 1;
+    }
+    z
+};
+
+
 fn main() {
     let x: &'static _ = &X; //~ ERROR temporary value dropped while borrowed
     let y: &'static _ = &Y; //~ ERROR temporary value dropped while borrowed
+    let z: &'static _ = &Z; //~ ERROR temporary value dropped while borrowed
 }
diff --git a/src/test/ui/consts/control-flow/interior-mutability.stderr b/src/test/ui/consts/control-flow/interior-mutability.stderr
index 49e8ea3ade7..0977c84d12d 100644
--- a/src/test/ui/consts/control-flow/interior-mutability.stderr
+++ b/src/test/ui/consts/control-flow/interior-mutability.stderr
@@ -1,24 +1,35 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/interior-mutability.rs:25:26
+  --> $DIR/interior-mutability.rs:44:26
    |
 LL |     let x: &'static _ = &X;
    |            ----------    ^ creates a temporary which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
-LL |     let y: &'static _ = &Y;
+...
 LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/interior-mutability.rs:26:26
+  --> $DIR/interior-mutability.rs:45:26
    |
 LL |     let y: &'static _ = &Y;
    |            ----------    ^ creates a temporary which is freed while still in use
    |            |
    |            type annotation requires that borrow lasts for `'static`
+LL |     let z: &'static _ = &Z;
+LL | }
+   | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/interior-mutability.rs:46:26
+   |
+LL |     let z: &'static _ = &Z;
+   |            ----------    ^ creates a temporary which is freed while still in use
+   |            |
+   |            type annotation requires that borrow lasts for `'static`
 LL | }
    | - temporary value is freed at the end of this statement
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/control-flow/loop.both.stderr b/src/test/ui/consts/control-flow/loop.both.stderr
new file mode 100644
index 00000000000..71d96b216f9
--- /dev/null
+++ b/src/test/ui/consts/control-flow/loop.both.stderr
@@ -0,0 +1,19 @@
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:63:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:67:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0744`.
diff --git a/src/test/ui/consts/control-flow/loop.if_match.stderr b/src/test/ui/consts/control-flow/loop.if_match.stderr
index 15b9eb02861..e01081638ec 100644
--- a/src/test/ui/consts/control-flow/loop.if_match.stderr
+++ b/src/test/ui/consts/control-flow/loop.if_match.stderr
@@ -1,51 +1,72 @@
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:8:15
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:10:15
    |
 LL | const _: () = loop {};
    |               ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `static`
-  --> $DIR/loop.rs:10:19
+error[E0658]: `loop` is not allowed in a `static`
+  --> $DIR/loop.rs:12:19
    |
 LL | static FOO: i32 = loop { break 4; };
    |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:13:5
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:15:5
    |
 LL |     loop {}
    |     ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:26:9
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:28:9
    |
 LL |         loop {}
    |         ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:38:9
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:40:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:47:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:49:5
    |
 LL | /     while x < 4 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:51:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
    |
 LL | /     while x < 8 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:61:5
+  --> $DIR/loop.rs:63:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
@@ -53,15 +74,15 @@ LL | |     }
    | |_____^
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:65:5
+  --> $DIR/loop.rs:67:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
 LL | |     }
    | |_____^
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:75:5
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:77:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -70,9 +91,12 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:82:5
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:84:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -81,31 +105,47 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:94:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:96:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:95:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:97:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:17:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:19:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:21:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:23:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error: aborting due to 15 previous errors
 
-For more information about this error, try `rustc --explain E0744`.
+Some errors have detailed explanations: E0658, E0744.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/loop.loop_.stderr b/src/test/ui/consts/control-flow/loop.loop_.stderr
new file mode 100644
index 00000000000..cf871c9a78c
--- /dev/null
+++ b/src/test/ui/consts/control-flow/loop.loop_.stderr
@@ -0,0 +1,96 @@
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:40:9
+   |
+LL |         while false {}
+   |         ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:49:5
+   |
+LL | /     while x < 4 {
+LL | |         x += 1;
+LL | |     }
+   | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
+   |
+LL | /     while x < 8 {
+LL | |         x += 1;
+LL | |     }
+   | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:63:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0744]: `for` is not allowed in a `const`
+  --> $DIR/loop.rs:67:5
+   |
+LL | /     for i in 0..4 {
+LL | |         x += i;
+LL | |     }
+   | |_____^
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/loop.rs:79:9
+   |
+LL | /         if x == 4 {
+LL | |             break;
+LL | |         }
+   | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `if` is not allowed in a `const`
+  --> $DIR/loop.rs:86:9
+   |
+LL | /         if x == 8 {
+LL | |             break;
+LL | |         }
+   | |_________^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:96:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:97:5
+   |
+LL |     while let None = Some(x) { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/49146
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
+   = note: `#![feature(const_loop)]` alone is not sufficient, since this loop expression contains an implicit conditional
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0658, E0744.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/loop.rs b/src/test/ui/consts/control-flow/loop.rs
index 4be341f2d38..bc57f7568a7 100644
--- a/src/test/ui/consts/control-flow/loop.rs
+++ b/src/test/ui/consts/control-flow/loop.rs
@@ -1,9 +1,11 @@
-// Ensure that all loops are forbidden in a const context, even if `#![feature(const_if_match)]` is
-// enabled.
+// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` is enabled.
+// `while` loops require `#![feature(const_if_match)]` to be enabled as well.
 
-// revisions: stock if_match
+// gate-test-const_loop
+// revisions: stock if_match loop_ both
 
-#![cfg_attr(if_match, feature(const_if_match))]
+#![cfg_attr(any(both, if_match), feature(const_if_match))]
+#![cfg_attr(any(both, loop_), feature(const_loop))]
 
 const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
 
@@ -36,7 +38,7 @@ const fn const_outside() {
 fn main() {
     let x = [0; {
         while false {}
-        //[stock,if_match]~^ ERROR `while` is not allowed in a `const`
+        //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const`
         4
     }];
 }
@@ -44,11 +46,11 @@ fn main() {
 const _: i32 = {
     let mut x = 0;
 
-    while x < 4 { //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
         x += 1;
     }
 
-    while x < 8 { //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
         x += 1;
     }
 
@@ -58,11 +60,11 @@ const _: i32 = {
 const _: i32 = {
     let mut x = 0;
 
-    for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const`
+    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
-    for i in 0..4 { //[stock,if_match]~ ERROR `for` is not allowed in a `const`
+    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
         x += i;
     }
 
@@ -74,14 +76,14 @@ const _: i32 = {
 
     loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
         x += 1;
-        if x == 4 { //[stock]~ ERROR `if` is not allowed in a `const`
+        if x == 4 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
             break;
         }
     }
 
     loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
         x += 1;
-        if x == 8 { //[stock]~ ERROR `if` is not allowed in a `const`
+        if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
             break;
         }
     }
@@ -91,7 +93,7 @@ const _: i32 = {
 
 const _: i32 = {
     let mut x = 0;
-    while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const`
-    while let None = Some(x) { } //[stock,if_match]~ ERROR `while` is not allowed in a `const`
+    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
+    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
     x
 };
diff --git a/src/test/ui/consts/control-flow/loop.stock.stderr b/src/test/ui/consts/control-flow/loop.stock.stderr
index bb651d23179..e3687cf12ac 100644
--- a/src/test/ui/consts/control-flow/loop.stock.stderr
+++ b/src/test/ui/consts/control-flow/loop.stock.stderr
@@ -1,51 +1,75 @@
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:8:15
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:10:15
    |
 LL | const _: () = loop {};
    |               ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `static`
-  --> $DIR/loop.rs:10:19
+error[E0658]: `loop` is not allowed in a `static`
+  --> $DIR/loop.rs:12:19
    |
 LL | static FOO: i32 = loop { break 4; };
    |                   ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:13:5
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:15:5
    |
 LL |     loop {}
    |     ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const fn`
-  --> $DIR/loop.rs:26:9
+error[E0658]: `loop` is not allowed in a `const fn`
+  --> $DIR/loop.rs:28:9
    |
 LL |         loop {}
    |         ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:38:9
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:40:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:47:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:49:5
    |
 LL | /     while x < 4 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:51:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:53:5
    |
 LL | /     while x < 8 {
 LL | |         x += 1;
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:61:5
+  --> $DIR/loop.rs:63:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
@@ -53,15 +77,15 @@ LL | |     }
    | |_____^
 
 error[E0744]: `for` is not allowed in a `const`
-  --> $DIR/loop.rs:65:5
+  --> $DIR/loop.rs:67:5
    |
 LL | /     for i in 0..4 {
 LL | |         x += i;
 LL | |     }
    | |_____^
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:75:5
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:77:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -70,9 +94,12 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:77:9
+  --> $DIR/loop.rs:79:9
    |
 LL | /         if x == 4 {
 LL | |             break;
@@ -82,8 +109,8 @@ LL | |         }
    = note: for more information, see https://github.com/rust-lang/rust/issues/49146
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:82:5
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:84:5
    |
 LL | /     loop {
 LL | |         x += 1;
@@ -92,9 +119,12 @@ LL | |             break;
 LL | |         }
 LL | |     }
    | |_____^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error[E0658]: `if` is not allowed in a `const`
-  --> $DIR/loop.rs:84:9
+  --> $DIR/loop.rs:86:9
    |
 LL | /         if x == 8 {
 LL | |             break;
@@ -104,29 +134,43 @@ LL | |         }
    = note: for more information, see https://github.com/rust-lang/rust/issues/49146
    = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:94:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:96:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `while` is not allowed in a `const`
-  --> $DIR/loop.rs:95:5
+error[E0658]: `while` is not allowed in a `const`
+  --> $DIR/loop.rs:97:5
    |
 LL |     while let None = Some(x) { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:17:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:19:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
-error[E0744]: `loop` is not allowed in a `const`
-  --> $DIR/loop.rs:21:22
+error[E0658]: `loop` is not allowed in a `const`
+  --> $DIR/loop.rs:23:22
    |
 LL |     const BAR: i32 = loop { break 4; };
    |                      ^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs
index 8cee2a54f56..4b20a2124c3 100644
--- a/src/test/ui/consts/control-flow/short-circuit-let.rs
+++ b/src/test/ui/consts/control-flow/short-circuit-let.rs
@@ -4,6 +4,7 @@
 
 #![feature(const_if_match)]
 #![feature(const_panic)]
+#![feature(const_fn)]
 
 const X: i32 = {
     let mut x = 0;
diff --git a/src/test/ui/consts/control-flow/single_variant_match_ice.rs b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
index 823605ff034..bb0fce66c4d 100644
--- a/src/test/ui/consts/control-flow/single_variant_match_ice.rs
+++ b/src/test/ui/consts/control-flow/single_variant_match_ice.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_if_match)]
+#![feature(const_if_match, const_fn)]
 
 enum Foo {
     Prob,
diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr
index b81daae330b..dd281e911da 100644
--- a/src/test/ui/consts/issue-64662.stderr
+++ b/src/test/ui/consts/issue-64662.stderr
@@ -2,13 +2,13 @@ error[E0282]: type annotations needed
   --> $DIR/issue-64662.rs:2:9
    |
 LL |     A = foo(),
-   |         ^^^ cannot infer type for `T`
+   |         ^^^ cannot infer type for type parameter `T` declared on the function `foo`
 
 error[E0282]: type annotations needed
   --> $DIR/issue-64662.rs:3:9
    |
 LL |     B = foo(),
-   |         ^^^ cannot infer type for `T`
+   |         ^^^ cannot infer type for type parameter `T` declared on the function `foo`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/min_const_fn/address_of.rs b/src/test/ui/consts/min_const_fn/address_of.rs
new file mode 100644
index 00000000000..f8506d70b24
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/address_of.rs
@@ -0,0 +1,17 @@
+#![feature(raw_ref_op)]
+
+const fn mutable_address_of_in_const() {
+    let mut a = 0;
+    let b = &raw mut a;         //~ ERROR `&raw mut` is not allowed
+}
+
+struct X;
+
+impl X {
+    const fn inherent_mutable_address_of_in_const() {
+        let mut a = 0;
+        let b = &raw mut a;     //~ ERROR `&raw mut` is not allowed
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/address_of.stderr b/src/test/ui/consts/min_const_fn/address_of.stderr
new file mode 100644
index 00000000000..3554b8112b1
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/address_of.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `&raw mut` is not allowed in constant functions
+  --> $DIR/address_of.rs:5:13
+   |
+LL |     let b = &raw mut a;
+   |             ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0658]: `&raw mut` is not allowed in constant functions
+  --> $DIR/address_of.rs:13:17
+   |
+LL |         let b = &raw mut a;
+   |                 ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/57349
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/address_of_const.rs b/src/test/ui/consts/min_const_fn/address_of_const.rs
new file mode 100644
index 00000000000..3db19e9cde8
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/address_of_const.rs
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(raw_ref_op)]
+
+const fn const_address_of_in_const() {
+    let mut a = 0;
+    let b = &raw const a;
+}
+
+struct X;
+
+impl X {
+    const fn inherent_const_address_of_in_const() {
+        let mut a = 0;
+        let b = &raw const a;
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
index 3992607c387..937aae1a8e3 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
@@ -1,10 +1,12 @@
 #![feature(rustc_attrs, staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allow_const_fn_ptr]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 const fn compiles(_: fn()) {}
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
index 6228b012dde..0ede4229ade 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
@@ -1,5 +1,5 @@
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/allow_const_fn_ptr.rs:4:16
+  --> $DIR/allow_const_fn_ptr.rs:5:16
    |
 LL | const fn error(_: fn()) {}
    |                ^
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
index 1d8b95ab1a2..7aa9bd7e2dc 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
@@ -5,6 +5,7 @@
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allow_const_fn_ptr]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 const fn takes_fn_ptr(_: fn()) {}
 
 const FN: fn() = || ();
diff --git a/src/test/ui/consts/min_const_fn/loop_ice.stderr b/src/test/ui/consts/min_const_fn/loop_ice.stderr
index 87db65fbb7d..58d1d421133 100644
--- a/src/test/ui/consts/min_const_fn/loop_ice.stderr
+++ b/src/test/ui/consts/min_const_fn/loop_ice.stderr
@@ -1,9 +1,12 @@
-error[E0744]: `loop` is not allowed in a `const fn`
+error[E0658]: `loop` is not allowed in a `const fn`
   --> $DIR/loop_ice.rs:2:5
    |
 LL |     loop {}
    |     ^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0744`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index 759d9ab6a40..97e467aece2 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -3,14 +3,15 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(const_fn, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 
@@ -18,10 +19,12 @@ const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
 const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
 
@@ -30,6 +33,7 @@ const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `
 const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index 0af5bdca815..1da9b41aa59 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,5 +1,5 @@
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:15:25
+  --> $DIR/min_const_fn_libstd_stability.rs:16:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
@@ -8,7 +8,7 @@ LL | const fn bar() -> u32 { foo() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:22:26
+  --> $DIR/min_const_fn_libstd_stability.rs:24:26
    |
 LL | const fn bar2() -> u32 { foo2() }
    |                          ^^^^^^
@@ -17,7 +17,7 @@ LL | const fn bar2() -> u32 { foo2() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: only int, `bool` and `char` operations are stable in const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:26:26
+  --> $DIR/min_const_fn_libstd_stability.rs:29:26
    |
 LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                          ^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:34:32
+  --> $DIR/min_const_fn_libstd_stability.rs:38:32
    |
 LL | const fn bar2_gated() -> u32 { foo2_gated() }
    |                                ^^^^^^^^^^^^
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 64057b012b8..102b3801441 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -3,14 +3,15 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(const_fn, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const unsafe fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn`
 
@@ -18,10 +19,12 @@ const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other
 const unsafe fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn`
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
 const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
 
@@ -30,6 +33,7 @@ const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool
 const unsafe fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
 //~^ ERROR can only call other `const fn`
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index bc6f8c59606..ae92602d45f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,5 +1,5 @@
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:15:41
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
    |
 LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    |                                         ^^^^^
@@ -8,7 +8,7 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:22:42
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
    |
 LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    |                                          ^^^^^^
@@ -17,7 +17,7 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: only int, `bool` and `char` operations are stable in const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:33
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33
    |
 LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                                 ^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:34:48
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48
    |
 LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
    |                                                ^^^^^^^^^^^^
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index deb2cb6b619..121177f8366 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -3,14 +3,15 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(const_fn, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 
@@ -18,6 +19,7 @@ const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
 
@@ -26,6 +28,7 @@ const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn
 const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index a14fd740c67..a0db74cfad6 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,5 +1,5 @@
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:15:32
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
    |
 LL | const unsafe fn bar() -> u32 { foo() }
    |                                ^^^^^
@@ -8,7 +8,7 @@ LL | const unsafe fn bar() -> u32 { foo() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:22:33
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
    |
 LL | const unsafe fn bar2() -> u32 { foo2() }
    |                                 ^^^^^^
@@ -17,7 +17,7 @@ LL | const unsafe fn bar2() -> u32 { foo2() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:30:39
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
    |
 LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
    |                                       ^^^^^^^^^^^^
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
index cad1516fc78..655ad7b548a 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
@@ -14,7 +14,7 @@ enum Opt<T> {
 }
 
 impl<T> Opt<T> {
-    #[rustc_const_unstable(feature = "foo")]
+    #[rustc_const_unstable(feature = "foo", issue = "0")]
     #[stable(feature = "rust1", since = "1.0.0")]
     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
     //~^ ERROR destructors cannot be evaluated at compile-time
diff --git a/src/test/ui/consts/validate_never_arrays.rs b/src/test/ui/consts/validate_never_arrays.rs
index 1270dc4ee30..9610b7b22f1 100644
--- a/src/test/ui/consts/validate_never_arrays.rs
+++ b/src/test/ui/consts/validate_never_arrays.rs
@@ -1,4 +1,4 @@
-#![feature(const_raw_ptr_deref)]
+#![feature(const_raw_ptr_deref, never_type)]
 
 const FOO: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
 
diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs
index b3c1f60b7eb..ea21592997b 100644
--- a/src/test/ui/did_you_mean/issue-40006.rs
+++ b/src/test/ui/did_you_mean/issue-40006.rs
@@ -18,10 +18,10 @@ trait A { //~ ERROR missing
 trait B {
     fn xxx() { ### } //~ ERROR expected
 }
-trait C { //~ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+trait C { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration
     L = M;
 }
-trait D { //~ ERROR missing `fn`, `type`, or `const` for trait-item declaration
+trait D { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration
     Z = { 2 + 3 };
 }
 trait E {
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
index 30ae6ed4c6d..d1e995013cb 100644
--- a/src/test/ui/did_you_mean/issue-40006.stderr
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -1,4 +1,4 @@
-error: missing `fn`, `type`, or `const` for impl-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:1:13
    |
 LL |   impl dyn A {
@@ -6,7 +6,7 @@ LL |   impl dyn A {
 LL | |     Y
    | |____^ missing `fn`, `type`, or `const`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:7:10
    |
 LL |   trait X {
@@ -14,7 +14,7 @@ LL |   trait X {
 LL | |     X() {}
    | |____^ missing `fn`, `type`, or `const`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:15:10
    |
 LL |   trait A {
@@ -28,7 +28,7 @@ error: expected `[`, found `#`
 LL |     fn xxx() { ### }
    |                 ^ expected `[`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:21:10
    |
 LL |   trait C {
@@ -36,7 +36,7 @@ LL |   trait C {
 LL | |     L = M;
    | |____^ missing `fn`, `type`, or `const`
 
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:24:10
    |
 LL |   trait D {
@@ -50,7 +50,7 @@ error: expected one of `!` or `::`, found `(`
 LL |     ::Y ();
    |         ^ expected one of `!` or `::`
 
-error: missing `fn`, `type`, or `const` for impl-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-40006.rs:32:8
    |
 LL |     pub hello_method(&self) {
diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs
index 38702f8d28f..f0ecea42f39 100644
--- a/src/test/ui/empty/empty-never-array.rs
+++ b/src/test/ui/empty/empty-never-array.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 enum Helper<T, U> {
     T(T, [!; 0]),
     #[allow(dead_code)]
diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr
index defcd256f7d..d865b59f0b9 100644
--- a/src/test/ui/empty/empty-never-array.stderr
+++ b/src/test/ui/empty/empty-never-array.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
-  --> $DIR/empty-never-array.rs:8:9
+  --> $DIR/empty-never-array.rs:10:9
    |
 LL | / enum Helper<T, U> {
 LL | |     T(T, [!; 0]),
@@ -20,7 +20,7 @@ LL |     if let Helper::U(u) = Helper::T(t, []) { /* */ }
    |
 
 error[E0381]: use of possibly-uninitialized variable: `u`
-  --> $DIR/empty-never-array.rs:10:5
+  --> $DIR/empty-never-array.rs:12:5
    |
 LL |     u
    |     ^ use of possibly-uninitialized `u`
diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr
index db0a2b5a085..f5b41cd1cc0 100644
--- a/src/test/ui/error-codes/E0004-2.stderr
+++ b/src/test/ui/error-codes/E0004-2.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: multiple patterns of type `std::option::Option<i32>` are not handled
+error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
   --> $DIR/E0004-2.rs:4:11
    |
 LL |     match x { }
-   |           ^
+   |           ^ patterns `None` and `Some(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr
index a58d16bfafb..6db2ef5051d 100644
--- a/src/test/ui/error-codes/E0034.stderr
+++ b/src/test/ui/error-codes/E0034.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Tes
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
-   = help: to disambiguate the method call, write `Trait1::foo(...)` instead
 note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Test`
   --> $DIR/E0034.rs:16:5
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
-   = help: to disambiguate the method call, write `Trait2::foo(...)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     Trait1::foo()
+   |     ^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     Trait2::foo()
+   |     ^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr
index aba649d83ec..ae5b7c3ae8f 100644
--- a/src/test/ui/error-codes/E0283.stderr
+++ b/src/test/ui/error-codes/E0283.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `_: Generator`
+error[E0283]: type annotations needed
   --> $DIR/E0283.rs:18:21
    |
 LL |     fn create() -> u32;
    |     ------------------- required by `Generator::create`
 ...
 LL |     let cont: u32 = Generator::create();
-   |                     ^^^^^^^^^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^^^^ cannot infer type
+   |
+   = note: cannot resolve `_: Generator`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr
index 485b76a09a3..8b1d4e6c07c 100644
--- a/src/test/ui/error-codes/E0401.stderr
+++ b/src/test/ui/error-codes/E0401.stderr
@@ -36,7 +36,7 @@ error[E0282]: type annotations needed
   --> $DIR/E0401.rs:11:5
    |
 LL |     bfnr(x);
-   |     ^^^^ cannot infer type for `U`
+   |     ^^^^ cannot infer type for type parameter `U` declared on the function `bfnr`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs
index 641e4b852e7..88a60934927 100644
--- a/src/test/ui/feature-gate/allow-features-empty.rs
+++ b/src/test/ui/feature-gate/allow-features-empty.rs
@@ -1,8 +1,6 @@
 // compile-flags: -Z allow_features=
 // Note: This test uses rustc internal flags because they will never stabilize.
 
-#![feature(rustc_const_unstable)] //~ ERROR
-
 #![feature(lang_items)] //~ ERROR
 
 #![feature(unknown_stdlib_feature)] //~ ERROR
diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr
index a87d1058503..f88b3ea0a60 100644
--- a/src/test/ui/feature-gate/allow-features-empty.stderr
+++ b/src/test/ui/feature-gate/allow-features-empty.stderr
@@ -1,21 +1,15 @@
-error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
-  --> $DIR/allow-features-empty.rs:4:12
-   |
-LL | #![feature(rustc_const_unstable)]
-   |            ^^^^^^^^^^^^^^^^^^^^
-
 error[E0725]: the feature `lang_items` is not in the list of allowed features
-  --> $DIR/allow-features-empty.rs:6:12
+  --> $DIR/allow-features-empty.rs:4:12
    |
 LL | #![feature(lang_items)]
    |            ^^^^^^^^^^
 
 error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features
-  --> $DIR/allow-features-empty.rs:8:12
+  --> $DIR/allow-features-empty.rs:6:12
    |
 LL | #![feature(unknown_stdlib_feature)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0725`.
diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs
index de69e48a65f..2ce4701a818 100644
--- a/src/test/ui/feature-gate/allow-features.rs
+++ b/src/test/ui/feature-gate/allow-features.rs
@@ -1,8 +1,6 @@
 // compile-flags: -Z allow_features=lang_items
 // Note: This test uses rustc internal flags because they will never stabilize.
 
-#![feature(rustc_const_unstable)] //~ ERROR
-
 #![feature(lang_items)]
 
 #![feature(unknown_stdlib_feature)] //~ ERROR
diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr
index 157dddf06ad..9caf48dd138 100644
--- a/src/test/ui/feature-gate/allow-features.stderr
+++ b/src/test/ui/feature-gate/allow-features.stderr
@@ -1,15 +1,9 @@
-error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
-  --> $DIR/allow-features.rs:4:12
-   |
-LL | #![feature(rustc_const_unstable)]
-   |            ^^^^^^^^^^^^^^^^^^^^
-
 error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features
-  --> $DIR/allow-features.rs:8:12
+  --> $DIR/allow-features.rs:6:12
    |
 LL | #![feature(unknown_stdlib_feature)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0725`.
diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs
index c27089d2a05..f0cc9ea7055 100644
--- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs
+++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 fn foo() -> Result<u32, !> {
     Ok(123)
 }
diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
index e599a9ee150..08c36cece4c 100644
--- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
+++ b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding: `Err(_)` not covered
-  --> $DIR/feature-gate-exhaustive-patterns.rs:6:9
+  --> $DIR/feature-gate-exhaustive-patterns.rs:8:9
    |
 LL |     let Ok(_x) = foo();
    |         ^^^^^^ pattern `Err(_)` not covered
diff --git a/src/test/ui/feature-gates/feature-gate-never_type.rs b/src/test/ui/feature-gates/feature-gate-never_type.rs
new file mode 100644
index 00000000000..be8c27dbb1b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-never_type.rs
@@ -0,0 +1,17 @@
+// Test that ! errors when used in illegal positions with feature(never_type) disabled
+
+trait Foo {
+    type Wub;
+}
+
+type Ma = (u32, !, i32); //~ ERROR type is experimental
+type Meeshka = Vec<!>; //~ ERROR type is experimental
+type Mow = &'static fn(!) -> !; //~ ERROR type is experimental
+type Skwoz = &'static mut !; //~ ERROR type is experimental
+
+impl Foo for Meeshka {
+    type Wub = !; //~ ERROR type is experimental
+}
+
+fn main() {
+}
diff --git a/src/test/ui/feature-gates/feature-gate-never_type.stderr b/src/test/ui/feature-gates/feature-gate-never_type.stderr
new file mode 100644
index 00000000000..d86ab99b82b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-never_type.stderr
@@ -0,0 +1,48 @@
+error[E0658]: The `!` type is experimental
+  --> $DIR/feature-gate-never_type.rs:7:17
+   |
+LL | type Ma = (u32, !, i32);
+   |                 ^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/35121
+   = help: add `#![feature(never_type)]` to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental
+  --> $DIR/feature-gate-never_type.rs:8:20
+   |
+LL | type Meeshka = Vec<!>;
+   |                    ^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/35121
+   = help: add `#![feature(never_type)]` to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental
+  --> $DIR/feature-gate-never_type.rs:9:24
+   |
+LL | type Mow = &'static fn(!) -> !;
+   |                        ^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/35121
+   = help: add `#![feature(never_type)]` to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental
+  --> $DIR/feature-gate-never_type.rs:10:27
+   |
+LL | type Skwoz = &'static mut !;
+   |                           ^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/35121
+   = help: add `#![feature(never_type)]` to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental
+  --> $DIR/feature-gate-never_type.rs:13:16
+   |
+LL |     type Wub = !;
+   |                ^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/35121
+   = help: add `#![feature(never_type)]` to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs
index 6961e68744f..3296a17a0b7 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs
+++ b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs
@@ -1,11 +1,8 @@
 // Test internal const fn feature gate.
 
-#![feature(staged_api)]
 #![feature(const_fn)]
-//#![feature(rustc_const_unstable)]
 
-#[stable(feature="zing", since="1.0.0")]
-#[rustc_const_unstable(feature="fzzzzzt")] //~ERROR internal feature
+#[rustc_const_unstable(feature="fzzzzzt")] //~ stability attributes may not be used outside
 pub const fn bazinga() {}
 
 fn main() {
diff --git a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr
index d7b7cf72a26..9df926dcf90 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr
@@ -1,11 +1,9 @@
-error[E0658]: the `#[rustc_const_unstable]` attribute is an internal feature
-  --> $DIR/feature-gate-rustc_const_unstable.rs:8:1
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/feature-gate-rustc_const_unstable.rs:5:1
    |
 LL | #[rustc_const_unstable(feature="fzzzzzt")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(rustc_const_unstable)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0734`.
diff --git a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
index d9ebcdecb9b..1f61473c9d2 100644
--- a/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
+++ b/src/test/ui/feature-gates/feature-gate-type_alias_impl_trait.stderr
@@ -16,15 +16,6 @@ LL |     type Baa = impl Debug;
    = note: for more information, see https://github.com/rust-lang/rust/issues/63063
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
-error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/feature-gate-type_alias_impl_trait.rs:18:18
-   |
-LL |     type Assoc = impl Debug;
-   |                  ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/63063
-   = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
-
 error[E0658]: associated type defaults are unstable
   --> $DIR/feature-gate-type_alias_impl_trait.rs:18:5
    |
@@ -35,6 +26,15 @@ LL |     type Assoc = impl Debug;
    = help: add `#![feature(associated_type_defaults)]` to the crate attributes to enable
 
 error[E0658]: `impl Trait` in type aliases is unstable
+  --> $DIR/feature-gate-type_alias_impl_trait.rs:18:18
+   |
+LL |     type Assoc = impl Debug;
+   |                  ^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/63063
+   = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
+
+error[E0658]: `impl Trait` in type aliases is unstable
   --> $DIR/feature-gate-type_alias_impl_trait.rs:24:24
    |
 LL | type NestedFree = (Vec<impl Debug>, impl Debug, impl Iterator<Item = impl Debug>);
diff --git a/src/test/ui/for-loop-while/loop-break-value.rs b/src/test/ui/for-loop-while/loop-break-value.rs
index 29848bb0ced..d7209fc4de8 100644
--- a/src/test/ui/for-loop-while/loop-break-value.rs
+++ b/src/test/ui/for-loop-while/loop-break-value.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![allow(unreachable_code)]
+#![feature(never_type)]
 
 #[allow(unused)]
 fn never_returns() {
diff --git a/src/test/ui/for/for-loop-type-error.rs b/src/test/ui/for/for-loop-type-error.rs
index 879fa47549e..8d9fc20f0d0 100644
--- a/src/test/ui/for/for-loop-type-error.rs
+++ b/src/test/ui/for/for-loop-type-error.rs
@@ -1,5 +1,5 @@
 pub fn main() {
-    let x = () + (); //~ ERROR binary operation
+    let x = () + (); //~ ERROR cannot add `()` to `()`
 
     // this shouldn't have a flow-on error:
     for _ in x {}
diff --git a/src/test/ui/for/for-loop-type-error.stderr b/src/test/ui/for/for-loop-type-error.stderr
index 588e7a0ed33..0ed26384f40 100644
--- a/src/test/ui/for/for-loop-type-error.stderr
+++ b/src/test/ui/for/for-loop-type-error.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `()`
+error[E0369]: cannot add `()` to `()`
   --> $DIR/for-loop-type-error.rs:2:16
    |
 LL |     let x = () + ();
diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr
index b06a6298a57..fa908440e41 100644
--- a/src/test/ui/inference/inference_unstable_featured.stderr
+++ b/src/test/ui/inference/inference_unstable_featured.stderr
@@ -5,9 +5,15 @@ LL |     assert_eq!('x'.ipu_flatten(), 0);
    |                    ^^^^^^^^^^^ multiple `ipu_flatten` found
    |
    = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char`
-   = help: to disambiguate the method call, write `inference_unstable_iterator::IpuIterator::ipu_flatten('x')` instead
    = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char`
-   = help: to disambiguate the method call, write `inference_unstable_itertools::IpuItertools::ipu_flatten('x')` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     assert_eq!(inference_unstable_iterator::IpuIterator::ipu_flatten(&'x'), 0);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     assert_eq!(inference_unstable_itertools::IpuItertools::ipu_flatten(&'x'), 0);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/invalid/invalid-variadic-function.rs b/src/test/ui/invalid/invalid-variadic-function.rs
deleted file mode 100644
index 8d23f0e4770..00000000000
--- a/src/test/ui/invalid/invalid-variadic-function.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-extern "C" fn foo(x: u8, ...);
-//~^ ERROR only foreign functions are allowed to be C-variadic
-//~| ERROR expected one of `->`, `where`, or `{`, found `;`
diff --git a/src/test/ui/invalid/invalid-variadic-function.stderr b/src/test/ui/invalid/invalid-variadic-function.stderr
deleted file mode 100644
index 7e58b17e7db..00000000000
--- a/src/test/ui/invalid/invalid-variadic-function.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0743]: only foreign functions are allowed to be C-variadic
-  --> $DIR/invalid-variadic-function.rs:1:26
-   |
-LL | extern "C" fn foo(x: u8, ...);
-   |                          ^^^
-
-error: expected one of `->`, `where`, or `{`, found `;`
-  --> $DIR/invalid-variadic-function.rs:1:30
-   |
-LL | extern "C" fn foo(x: u8, ...);
-   |                              ^ expected one of `->`, `where`, or `{`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0743`.
diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs
index 91115ef74b8..5d7664cefb3 100644
--- a/src/test/ui/invalid_const_promotion.rs
+++ b/src/test/ui/invalid_const_promotion.rs
@@ -22,6 +22,7 @@ use std::process::{Command, Stdio};
 // of the const fn kicks in, causing a different code path in the
 // compiler to be executed (see PR #66294).
 #[stable(feature = "rustc", since = "1.0.0")]
+#[rustc_const_stable(feature = "rustc", since = "1.0.0")]
 #[rustc_promotable]
 const fn bar(_: bool) -> usize { 0 - 1 }
 
diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr
index ff92d01a69e..fe7e8f89f7f 100644
--- a/src/test/ui/issues/issue-12028.stderr
+++ b/src/test/ui/issues/issue-12028.stderr
@@ -1,8 +1,10 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
+error[E0284]: type annotations needed
   --> $DIR/issue-12028.rs:27:14
    |
 LL |         self.input_stream(&mut stream);
-   |              ^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^ cannot infer type for type parameter `H` declared on the trait `StreamHash`
+   |
+   = note: cannot resolve `<_ as StreamHasher>::S == <H as StreamHasher>::S`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-14915.rs b/src/test/ui/issues/issue-14915.rs
index 294533f0cbb..4acb51a4e50 100644
--- a/src/test/ui/issues/issue-14915.rs
+++ b/src/test/ui/issues/issue-14915.rs
@@ -4,5 +4,5 @@ fn main() {
     let x: Box<isize> = box 0;
 
     println!("{}", x + 1);
-    //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box<isize>`
+    //~^ ERROR cannot add `{integer}` to `std::boxed::Box<isize>`
 }
diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr
index e8de44320da..00b9909af59 100644
--- a/src/test/ui/issues/issue-14915.stderr
+++ b/src/test/ui/issues/issue-14915.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `std::boxed::Box<isize>`
+error[E0369]: cannot add `{integer}` to `std::boxed::Box<isize>`
   --> $DIR/issue-14915.rs:6:22
    |
 LL |     println!("{}", x + 1);
diff --git a/src/test/ui/issues/issue-16966.stderr b/src/test/ui/issues/issue-16966.stderr
index 13e77fe3073..49a12cc2009 100644
--- a/src/test/ui/issues/issue-16966.stderr
+++ b/src/test/ui/issues/issue-16966.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-16966.rs:2:5
    |
 LL |     panic!(std::default::Default::default());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `M`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic`
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr
index ce16f0f58ea..48405a292f3 100644
--- a/src/test/ui/issues/issue-17551.stderr
+++ b/src/test/ui/issues/issue-17551.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `B<T>`
   --> $DIR/issue-17551.rs:6:15
    |
 LL |     let foo = B(marker::PhantomData);
-   |         ---   ^ cannot infer type for `T`
+   |         ---   ^ cannot infer type for type parameter `T` declared on the struct `B`
    |         |
    |         consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
 
diff --git a/src/test/ui/issues/issue-18446.stderr b/src/test/ui/issues/issue-18446.stderr
index e6afc4c13a9..3422add9dd9 100644
--- a/src/test/ui/issues/issue-18446.stderr
+++ b/src/test/ui/issues/issue-18446.stderr
@@ -2,7 +2,10 @@ error[E0034]: multiple applicable items in scope
   --> $DIR/issue-18446.rs:18:7
    |
 LL |     x.foo();
-   |       ^^^ multiple `foo` found
+   |     --^^^--
+   |     | |
+   |     | multiple `foo` found
+   |     help: disambiguate the method call for candidate #2: `T::foo(&x)`
    |
 note: candidate #1 is defined in an impl for the type `dyn T`
   --> $DIR/issue-18446.rs:9:5
@@ -14,7 +17,6 @@ note: candidate #2 is defined in the trait `T`
    |
 LL |     fn foo(&self);
    |     ^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `T::foo(&x)` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr
index 7ceb2bd23f6..b1536bd8ddb 100644
--- a/src/test/ui/issues/issue-21974.stderr
+++ b/src/test/ui/issues/issue-21974.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed: cannot resolve `&'a T: Foo`
+error[E0283]: type annotations needed
   --> $DIR/issue-21974.rs:10:1
    |
 LL |   trait Foo {
@@ -11,7 +11,9 @@ LL | | {
 LL | |     x.foo();
 LL | |     y.foo();
 LL | | }
-   | |_^
+   | |_^ cannot infer type for reference `&'a T`
+   |
+   = note: cannot resolve `&'a T: Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-24363.rs b/src/test/ui/issues/issue-24363.rs
index a5b45f13e74..34726fba9c6 100644
--- a/src/test/ui/issues/issue-24363.rs
+++ b/src/test/ui/issues/issue-24363.rs
@@ -1,6 +1,6 @@
 fn main() {
     1.create_a_type_error[ //~ `{integer}` is a primitive type and therefore doesn't have fields
-        ()+() //~ ERROR binary operation `+` cannot be applied
+        ()+() //~ ERROR cannot add
               //   ^ ensure that we typeck the inner expression ^
     ];
 }
diff --git a/src/test/ui/issues/issue-24363.stderr b/src/test/ui/issues/issue-24363.stderr
index 50d65e09bb1..a60fb24ec12 100644
--- a/src/test/ui/issues/issue-24363.stderr
+++ b/src/test/ui/issues/issue-24363.stderr
@@ -4,7 +4,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
 LL |     1.create_a_type_error[
    |       ^^^^^^^^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `()`
+error[E0369]: cannot add `()` to `()`
   --> $DIR/issue-24363.rs:3:11
    |
 LL |         ()+()
diff --git a/src/test/ui/issues/issue-24424.rs b/src/test/ui/issues/issue-24424.rs
index 9b74cd1230e..22bf513afe8 100644
--- a/src/test/ui/issues/issue-24424.rs
+++ b/src/test/ui/issues/issue-24424.rs
@@ -2,6 +2,6 @@ trait Trait1<'l0, T0> {}
 trait Trait0<'l0>  {}
 
 impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
-//~^ ERROR type annotations needed: cannot resolve `T0: Trait0<'l0>`
+//~^ ERROR type annotations needed
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr
index 8c539f7cedd..8f0850328b4 100644
--- a/src/test/ui/issues/issue-24424.stderr
+++ b/src/test/ui/issues/issue-24424.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `T0: Trait0<'l0>`
+error[E0283]: type annotations needed
   --> $DIR/issue-24424.rs:4:1
    |
 LL | trait Trait0<'l0>  {}
    | ----------------- required by `Trait0`
 LL | 
 LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T0`
+   |
+   = note: cannot resolve `T0: Trait0<'l0>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr
index 0b890b573da..a09de86a708 100644
--- a/src/test/ui/issues/issue-25368.stderr
+++ b/src/test/ui/issues/issue-25368.stderr
@@ -5,7 +5,7 @@ LL |     let (tx, rx) = channel();
    |         -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
 ...
 LL |         tx.send(Foo{ foo: PhantomData });
-   |                 ^^^ cannot infer type for `T`
+   |                 ^^^ cannot infer type for type parameter `T` declared on the struct `Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-28837.rs b/src/test/ui/issues/issue-28837.rs
index 114473f3acf..438a4c521b1 100644
--- a/src/test/ui/issues/issue-28837.rs
+++ b/src/test/ui/issues/issue-28837.rs
@@ -3,23 +3,23 @@ struct A;
 fn main() {
     let a = A;
 
-    a + a; //~ ERROR binary operation `+` cannot be applied to type `A`
+    a + a; //~ ERROR cannot add `A` to `A`
 
-    a - a; //~ ERROR binary operation `-` cannot be applied to type `A`
+    a - a; //~ ERROR cannot substract `A` from `A`
 
-    a * a; //~ ERROR binary operation `*` cannot be applied to type `A`
+    a * a; //~ ERROR cannot multiply `A` to `A`
 
-    a / a; //~ ERROR binary operation `/` cannot be applied to type `A`
+    a / a; //~ ERROR cannot divide `A` by `A`
 
-    a % a; //~ ERROR binary operation `%` cannot be applied to type `A`
+    a % a; //~ ERROR cannot mod `A` by `A`
 
-    a & a; //~ ERROR binary operation `&` cannot be applied to type `A`
+    a & a; //~ ERROR no implementation for `A & A`
 
-    a | a; //~ ERROR binary operation `|` cannot be applied to type `A`
+    a | a; //~ ERROR no implementation for `A | A`
 
-    a << a; //~ ERROR binary operation `<<` cannot be applied to type `A`
+    a << a; //~ ERROR no implementation for `A << A`
 
-    a >> a; //~ ERROR binary operation `>>` cannot be applied to type `A`
+    a >> a; //~ ERROR no implementation for `A >> A`
 
     a == a; //~ ERROR binary operation `==` cannot be applied to type `A`
 
diff --git a/src/test/ui/issues/issue-28837.stderr b/src/test/ui/issues/issue-28837.stderr
index ac2a9f2203d..2ef571b576f 100644
--- a/src/test/ui/issues/issue-28837.stderr
+++ b/src/test/ui/issues/issue-28837.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `A`
+error[E0369]: cannot add `A` to `A`
   --> $DIR/issue-28837.rs:6:7
    |
 LL |     a + a;
@@ -8,7 +8,7 @@ LL |     a + a;
    |
    = note: an implementation of `std::ops::Add` might be missing for `A`
 
-error[E0369]: binary operation `-` cannot be applied to type `A`
+error[E0369]: cannot substract `A` from `A`
   --> $DIR/issue-28837.rs:8:7
    |
 LL |     a - a;
@@ -18,7 +18,7 @@ LL |     a - a;
    |
    = note: an implementation of `std::ops::Sub` might be missing for `A`
 
-error[E0369]: binary operation `*` cannot be applied to type `A`
+error[E0369]: cannot multiply `A` to `A`
   --> $DIR/issue-28837.rs:10:7
    |
 LL |     a * a;
@@ -28,7 +28,7 @@ LL |     a * a;
    |
    = note: an implementation of `std::ops::Mul` might be missing for `A`
 
-error[E0369]: binary operation `/` cannot be applied to type `A`
+error[E0369]: cannot divide `A` by `A`
   --> $DIR/issue-28837.rs:12:7
    |
 LL |     a / a;
@@ -38,7 +38,7 @@ LL |     a / a;
    |
    = note: an implementation of `std::ops::Div` might be missing for `A`
 
-error[E0369]: binary operation `%` cannot be applied to type `A`
+error[E0369]: cannot mod `A` by `A`
   --> $DIR/issue-28837.rs:14:7
    |
 LL |     a % a;
@@ -48,7 +48,7 @@ LL |     a % a;
    |
    = note: an implementation of `std::ops::Rem` might be missing for `A`
 
-error[E0369]: binary operation `&` cannot be applied to type `A`
+error[E0369]: no implementation for `A & A`
   --> $DIR/issue-28837.rs:16:7
    |
 LL |     a & a;
@@ -58,7 +58,7 @@ LL |     a & a;
    |
    = note: an implementation of `std::ops::BitAnd` might be missing for `A`
 
-error[E0369]: binary operation `|` cannot be applied to type `A`
+error[E0369]: no implementation for `A | A`
   --> $DIR/issue-28837.rs:18:7
    |
 LL |     a | a;
@@ -68,7 +68,7 @@ LL |     a | a;
    |
    = note: an implementation of `std::ops::BitOr` might be missing for `A`
 
-error[E0369]: binary operation `<<` cannot be applied to type `A`
+error[E0369]: no implementation for `A << A`
   --> $DIR/issue-28837.rs:20:7
    |
 LL |     a << a;
@@ -78,7 +78,7 @@ LL |     a << a;
    |
    = note: an implementation of `std::ops::Shl` might be missing for `A`
 
-error[E0369]: binary operation `>>` cannot be applied to type `A`
+error[E0369]: no implementation for `A >> A`
   --> $DIR/issue-28837.rs:22:7
    |
 LL |     a >> a;
diff --git a/src/test/ui/issues/issue-29147.rs b/src/test/ui/issues/issue-29147.rs
index 7ec96b97eef..271bc526033 100644
--- a/src/test/ui/issues/issue-29147.rs
+++ b/src/test/ui/issues/issue-29147.rs
@@ -18,5 +18,5 @@ impl Foo for S5<u32> { fn xxx(&self) {} }
 impl Foo for S5<u64> { fn xxx(&self) {} }
 
 fn main() {
-    let _ = <S5<_>>::xxx; //~ ERROR cannot resolve `S5<_>: Foo`
+    let _ = <S5<_>>::xxx; //~ ERROR type annotations needed
 }
diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr
index c9dd92fca7d..1efedb45cac 100644
--- a/src/test/ui/issues/issue-29147.stderr
+++ b/src/test/ui/issues/issue-29147.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `S5<_>: Foo`
+error[E0283]: type annotations needed
   --> $DIR/issue-29147.rs:21:13
    |
 LL | trait Foo { fn xxx(&self); }
    |             -------------- required by `Foo::xxx`
 ...
 LL |     let _ = <S5<_>>::xxx;
-   |             ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
+   |
+   = note: cannot resolve `S5<_>: Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-31076.rs b/src/test/ui/issues/issue-31076.rs
index e4531072e9b..f9c35526ec3 100644
--- a/src/test/ui/issues/issue-31076.rs
+++ b/src/test/ui/issues/issue-31076.rs
@@ -11,7 +11,7 @@ impl Add<i32> for i32 {}
 
 fn main() {
     let x = 5 + 6;
-    //~^ ERROR binary operation `+` cannot be applied to type `{integer}`
+    //~^ ERROR cannot add `{integer}` to `{integer}`
     let y = 5i32 + 6i32;
-    //~^ ERROR binary operation `+` cannot be applied to type `i32`
+    //~^ ERROR cannot add `i32` to `i32`
 }
diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr
index 60a3be1c36b..5d65734cd23 100644
--- a/src/test/ui/issues/issue-31076.stderr
+++ b/src/test/ui/issues/issue-31076.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `{integer}`
+error[E0369]: cannot add `{integer}` to `{integer}`
   --> $DIR/issue-31076.rs:13:15
    |
 LL |     let x = 5 + 6;
@@ -8,7 +8,7 @@ LL |     let x = 5 + 6;
    |
    = note: an implementation of `std::ops::Add` might be missing for `{integer}`
 
-error[E0369]: binary operation `+` cannot be applied to type `i32`
+error[E0369]: cannot add `i32` to `i32`
   --> $DIR/issue-31076.rs:15:18
    |
 LL |     let y = 5i32 + 6i32;
diff --git a/src/test/ui/issues/issue-35668.rs b/src/test/ui/issues/issue-35668.rs
index 1b8ada57ed6..6f6dfb00f86 100644
--- a/src/test/ui/issues/issue-35668.rs
+++ b/src/test/ui/issues/issue-35668.rs
@@ -1,6 +1,6 @@
 fn func<'a, T>(a: &'a [T]) -> impl Iterator<Item=&'a T> {
     a.iter().map(|a| a*a)
-    //~^ ERROR binary operation `*` cannot be applied to type `&T`
+    //~^ ERROR cannot multiply `&T` to `&T`
 }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr
index 59ca874bd20..9d5796a5eef 100644
--- a/src/test/ui/issues/issue-35668.stderr
+++ b/src/test/ui/issues/issue-35668.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `*` cannot be applied to type `&T`
+error[E0369]: cannot multiply `&T` to `&T`
   --> $DIR/issue-35668.rs:2:23
    |
 LL |     a.iter().map(|a| a*a)
diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr
index fa0fa3345f5..445eb4107d1 100644
--- a/src/test/ui/issues/issue-3601.stderr
+++ b/src/test/ui/issues/issue-3601.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `_` not covered
+error[E0004]: non-exhaustive patterns: `Box(_)` not covered
   --> $DIR/issue-3601.rs:30:44
    |
 LL |         box NodeKind::Element(ed) => match ed.kind {
-   |                                            ^^^^^^^ pattern `_` not covered
+   |                                            ^^^^^^^ pattern `Box(_)` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr
index 4d0ff750c25..b18e407c3d4 100644
--- a/src/test/ui/issues/issue-3702-2.stderr
+++ b/src/test/ui/issues/issue-3702-2.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type
    |
 LL |     fn to_int(&self) -> isize { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `ToPrimitive::to_int(&self)` instead
 note: candidate #2 is defined in an impl of the trait `Add` for the type `isize`
   --> $DIR/issue-3702-2.rs:14:5
    |
 LL |     fn to_int(&self) -> isize { *self }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `Add::to_int(&self)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |         ToPrimitive::to_int(&self) + other.to_int()
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |         Add::to_int(&self) + other.to_int()
+   |         ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3820.rs b/src/test/ui/issues/issue-3820.rs
index fbf60ce278d..c0906546232 100644
--- a/src/test/ui/issues/issue-3820.rs
+++ b/src/test/ui/issues/issue-3820.rs
@@ -11,5 +11,5 @@ impl Thing {
 fn main() {
     let u = Thing {x: 2};
     let _v = u.mul(&3); // This is ok
-    let w = u * 3; //~ ERROR binary operation `*` cannot be applied to type `Thing`
+    let w = u * 3; //~ ERROR cannot multiply `{integer}` to `Thing`
 }
diff --git a/src/test/ui/issues/issue-3820.stderr b/src/test/ui/issues/issue-3820.stderr
index 35eceb3b3c6..8cc768237a9 100644
--- a/src/test/ui/issues/issue-3820.stderr
+++ b/src/test/ui/issues/issue-3820.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `*` cannot be applied to type `Thing`
+error[E0369]: cannot multiply `{integer}` to `Thing`
   --> $DIR/issue-3820.rs:14:15
    |
 LL |     let w = u * 3;
diff --git a/src/test/ui/issues/issue-40610.rs b/src/test/ui/issues/issue-40610.rs
index 104cf7f54e5..c01233605b5 100644
--- a/src/test/ui/issues/issue-40610.rs
+++ b/src/test/ui/issues/issue-40610.rs
@@ -2,5 +2,5 @@ fn f(_: &[f32]) {}
 
 fn main() {
     () + f(&[1.0]);
-    //~^ ERROR binary operation `+` cannot be applied to type `()`
+    //~^ ERROR cannot add `()` to `()`
 }
diff --git a/src/test/ui/issues/issue-40610.stderr b/src/test/ui/issues/issue-40610.stderr
index 9d577591929..95f45c168e1 100644
--- a/src/test/ui/issues/issue-40610.stderr
+++ b/src/test/ui/issues/issue-40610.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `()`
+error[E0369]: cannot add `()` to `()`
   --> $DIR/issue-40610.rs:4:8
    |
 LL |     () + f(&[1.0]);
diff --git a/src/test/ui/issues/issue-41394.rs b/src/test/ui/issues/issue-41394.rs
index 45318f6efb8..64873ac35a0 100644
--- a/src/test/ui/issues/issue-41394.rs
+++ b/src/test/ui/issues/issue-41394.rs
@@ -1,6 +1,6 @@
 enum Foo {
     A = "" + 1
-    //~^ ERROR binary operation `+` cannot be applied to type `&str`
+    //~^ ERROR cannot add `{integer}` to `&str`
 }
 
 enum Bar {
diff --git a/src/test/ui/issues/issue-41394.stderr b/src/test/ui/issues/issue-41394.stderr
index c8437ab189d..3f60ea4bbf7 100644
--- a/src/test/ui/issues/issue-41394.stderr
+++ b/src/test/ui/issues/issue-41394.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `{integer}` to `&str`
   --> $DIR/issue-41394.rs:2:12
    |
 LL |     A = "" + 1
diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr
index 3460c1dae22..5f785679c55 100644
--- a/src/test/ui/issues/issue-47377.stderr
+++ b/src/test/ui/issues/issue-47377.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `&str` to `&str`
   --> $DIR/issue-47377.rs:4:14
    |
 LL |      let _a = b + ", World!";
diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr
index f334dcbd916..216e32ddae4 100644
--- a/src/test/ui/issues/issue-47380.stderr
+++ b/src/test/ui/issues/issue-47380.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `&str` to `&str`
   --> $DIR/issue-47380.rs:3:35
    |
 LL |     println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!";
diff --git a/src/test/ui/issues/issue-5062.stderr b/src/test/ui/issues/issue-5062.stderr
index 0f5c6d8d4bf..9fa15dc9679 100644
--- a/src/test/ui/issues/issue-5062.stderr
+++ b/src/test/ui/issues/issue-5062.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-5062.rs:1:29
    |
 LL | fn main() { format!("{:?}", None); }
-   |                             ^^^^ cannot infer type for `T`
+   |                             ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr
index 001928c3b2f..c3b880200f8 100644
--- a/src/test/ui/issues/issue-51714.stderr
+++ b/src/test/ui/issues/issue-51714.stderr
@@ -1,8 +1,12 @@
-error[E0744]: `while` is not allowed in a `const`
+error[E0658]: `while` is not allowed in a `const`
   --> $DIR/issue-51714.rs:11:17
    |
 LL |     [(); return while let Some(n) = Some(0) {}];
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/52000
+   = help: add `#![feature(const_loop)]` to the crate attributes to enable
+   = help: add `#![feature(const_if_match)]` to the crate attributes to enable
 
 error[E0572]: return statement outside of function body
   --> $DIR/issue-51714.rs:2:14
@@ -30,5 +34,5 @@ LL |     [(); return while let Some(n) = Some(0) {}];
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0572, E0744.
+Some errors have detailed explanations: E0572, E0658.
 For more information about an error, try `rustc --explain E0572`.
diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr
index 56ccdaf7aac..d99a5772e8a 100644
--- a/src/test/ui/issues/issue-54954.stderr
+++ b/src/test/ui/issues/issue-54954.stderr
@@ -4,14 +4,16 @@ error[E0379]: trait fns cannot be declared const
 LL |     const fn const_val<T: Sized>() -> usize {
    |     ^^^^^ trait fns cannot be const
 
-error[E0283]: type annotations needed: cannot resolve `_: Tt`
+error[E0283]: type annotations needed
   --> $DIR/issue-54954.rs:3:24
    |
 LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
 ...
 LL |     const fn const_val<T: Sized>() -> usize {
    |              --------- - required by this bound in `Tt::const_val`
+   |
+   = note: cannot resolve `_: Tt`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-54954.rs:13:15
diff --git a/src/test/ui/issues/issue-58022.rs b/src/test/ui/issues/issue-58022.rs
index 30527903ed0..e4b9b3b53a6 100644
--- a/src/test/ui/issues/issue-58022.rs
+++ b/src/test/ui/issues/issue-58022.rs
@@ -2,7 +2,7 @@ pub trait Foo: Sized {
     const SIZE: usize;
 
     fn new(slice: &[u8; Foo::SIZE]) -> Self;
-    //~^ ERROR: type annotations needed: cannot resolve `_: Foo`
+    //~^ ERROR: type annotations needed
 }
 
 pub struct Bar<T: ?Sized>(T);
diff --git a/src/test/ui/issues/issue-58022.stderr b/src/test/ui/issues/issue-58022.stderr
index a3e4cb63202..ef0d66d7ad6 100644
--- a/src/test/ui/issues/issue-58022.stderr
+++ b/src/test/ui/issues/issue-58022.stderr
@@ -4,14 +4,16 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Foo
 LL |         Foo(Box::new(*slice))
    |         ^^^ not a function, tuple struct or tuple variant
 
-error[E0283]: type annotations needed: cannot resolve `_: Foo`
+error[E0283]: type annotations needed
   --> $DIR/issue-58022.rs:4:25
    |
 LL |     const SIZE: usize;
    |     ------------------ required by `Foo::SIZE`
 LL | 
 LL |     fn new(slice: &[u8; Foo::SIZE]) -> Self;
-   |                         ^^^^^^^^^
+   |                         ^^^^^^^^^ cannot infer type
+   |
+   = note: cannot resolve `_: Foo`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs
index db3984cd189..8b1a39a94e6 100644
--- a/src/test/ui/issues/issue-58856-1.rs
+++ b/src/test/ui/issues/issue-58856-1.rs
@@ -1,6 +1,8 @@
 impl A {
+    //~^ ERROR cannot find type `A` in this scope
     fn b(self>
     //~^ ERROR expected one of `)`, `,`, or `:`, found `>`
+    //~| ERROR expected `;` or `{`, found `>`
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr
index 58ab0a142d6..0ea6b017548 100644
--- a/src/test/ui/issues/issue-58856-1.stderr
+++ b/src/test/ui/issues/issue-58856-1.stderr
@@ -1,10 +1,23 @@
 error: expected one of `)`, `,`, or `:`, found `>`
-  --> $DIR/issue-58856-1.rs:2:14
+  --> $DIR/issue-58856-1.rs:3:14
    |
 LL |     fn b(self>
    |         -    ^ help: `)` may belong here
    |         |
    |         unclosed delimiter
 
-error: aborting due to previous error
+error: expected `;` or `{`, found `>`
+  --> $DIR/issue-58856-1.rs:3:14
+   |
+LL |     fn b(self>
+   |              ^ expected `;` or `{`
+
+error[E0412]: cannot find type `A` in this scope
+  --> $DIR/issue-58856-1.rs:1:6
+   |
+LL | impl A {
+   |      ^ not found in this scope
+
+error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index e0b15130c33..e8ef981f515 100644
--- a/src/test/ui/issues/issue-60075.stderr
+++ b/src/test/ui/issues/issue-60075.stderr
@@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
 LL |         });
    |          ^ expected one of `.`, `;`, `?`, `else`, or an operator
 
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;`
   --> $DIR/issue-60075.rs:6:11
    |
 LL |     fn qux() -> Option<usize> {
diff --git a/src/test/ui/issues/issue-6458-2.stderr b/src/test/ui/issues/issue-6458-2.stderr
index b5da2bf096c..da16f95dc3d 100644
--- a/src/test/ui/issues/issue-6458-2.stderr
+++ b/src/test/ui/issues/issue-6458-2.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-2.rs:3:21
    |
 LL |     format!("{:?}", None);
-   |                     ^^^^ cannot infer type for `T`
+   |                     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr
index 784497c959d..a71c159db0b 100644
--- a/src/test/ui/issues/issue-6458-3.stderr
+++ b/src/test/ui/issues/issue-6458-3.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458-3.rs:4:5
    |
 LL |     mem::transmute(0);
-   |     ^^^^^^^^^^^^^^ cannot infer type for `U`
+   |     ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-6458.stderr b/src/test/ui/issues/issue-6458.stderr
index d59d872ba93..f1a982616a4 100644
--- a/src/test/ui/issues/issue-6458.stderr
+++ b/src/test/ui/issues/issue-6458.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-6458.rs:9:4
    |
 LL |    foo(TypeWithState(marker::PhantomData));
-   |    ^^^ cannot infer type for `State`
+   |    ^^^ cannot infer type for type parameter `State` declared on the function `foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-65611.stderr b/src/test/ui/issues/issue-65611.stderr
index cb441c13c6b..20e2ba144d9 100644
--- a/src/test/ui/issues/issue-65611.stderr
+++ b/src/test/ui/issues/issue-65611.stderr
@@ -2,7 +2,10 @@ error[E0282]: type annotations needed
   --> $DIR/issue-65611.rs:59:20
    |
 LL |     let x = buffer.last().unwrap().0.clone();
-   |                    ^^^^ cannot infer type for `T`
+   |             -------^^^^--
+   |             |      |
+   |             |      cannot infer type for type parameter `T`
+   |             this method call resolves to `std::option::Option<&T>`
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr
index c7bb653dc1f..feaf3dc753f 100644
--- a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr
+++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn
    |
 LL |     fn r#struct(&self) {
    |     ^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `async::r#struct(r#fn {})` instead
 note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn`
   --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5
    |
 LL |     fn r#struct(&self) {
    |     ^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `await::r#struct(r#fn {})` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     async::r#struct(&r#fn {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     await::r#struct(&r#fn {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-66923-show-error-for-correct-call.rs b/src/test/ui/issues/issue-66923-show-error-for-correct-call.rs
new file mode 100644
index 00000000000..83328073972
--- /dev/null
+++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.rs
@@ -0,0 +1,15 @@
+// This test checks that errors are showed for lines with `collect` rather than `push` method.
+
+fn main() {
+    let v = vec![1_f64, 2.2_f64];
+    let mut fft: Vec<Vec<f64>> = vec![];
+
+    let x1: &[f64] = &v;
+    let x2: Vec<f64> = x1.into_iter().collect();
+    //~^ ERROR a value of type
+    fft.push(x2);
+
+    let x3 = x1.into_iter().collect::<Vec<f64>>();
+    //~^ ERROR a value of type
+    fft.push(x3);
+}
diff --git a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr
new file mode 100644
index 00000000000..8e7ee97e0b9
--- /dev/null
+++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr
@@ -0,0 +1,19 @@
+error[E0277]: a value of type `std::vec::Vec<f64>` cannot be built from an iterator over elements of type `&f64`
+  --> $DIR/issue-66923-show-error-for-correct-call.rs:8:39
+   |
+LL |     let x2: Vec<f64> = x1.into_iter().collect();
+   |                                       ^^^^^^^ value of type `std::vec::Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
+   |
+   = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec<f64>`
+
+error[E0277]: a value of type `std::vec::Vec<f64>` cannot be built from an iterator over elements of type `&f64`
+  --> $DIR/issue-66923-show-error-for-correct-call.rs:12:29
+   |
+LL |     let x3 = x1.into_iter().collect::<Vec<f64>>();
+   |                             ^^^^^^^ value of type `std::vec::Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
+   |
+   = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec<f64>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs
index 1af44ecf362..dd8dbda6d43 100644
--- a/src/test/ui/lint/lint-unused-mut-variables.rs
+++ b/src/test/ui/lint/lint-unused-mut-variables.rs
@@ -3,7 +3,7 @@
 // Exercise the unused_mut attribute in some positive and negative cases
 
 #![deny(unused_mut)]
-#![feature(async_closure)]
+#![feature(async_closure, raw_ref_op)]
 
 async fn baz_async(
     mut a: i32,
@@ -177,6 +177,12 @@ fn main() {
     // leading underscore should avoid the warning, just like the
     // unused variable lint.
     let mut _allowed = 1;
+
+    let mut raw_address_of_mut = 1; // OK
+    let mut_ptr = &raw mut raw_address_of_mut;
+
+    let mut raw_address_of_const = 1; //~ ERROR: variable does not need to be mutable
+    let const_ptr = &raw const raw_address_of_const;
 }
 
 fn callback<F>(f: F) where F: FnOnce() {}
diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr
index 92c2b68652d..c1ab0ab33d4 100644
--- a/src/test/ui/lint/lint-unused-mut-variables.stderr
+++ b/src/test/ui/lint/lint-unused-mut-variables.stderr
@@ -181,6 +181,14 @@ LL |     let mut v : &mut Vec<()> = &mut vec![];
    |         help: remove this `mut`
 
 error: variable does not need to be mutable
+  --> $DIR/lint-unused-mut-variables.rs:184:9
+   |
+LL |     let mut raw_address_of_const = 1;
+   |         ----^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         help: remove this `mut`
+
+error: variable does not need to be mutable
   --> $DIR/lint-unused-mut-variables.rs:106:13
    |
 LL |     fn what(mut foo: isize) {}
@@ -197,7 +205,7 @@ LL |     fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
    |                    help: remove this `mut`
 
 error: variable does not need to be mutable
-  --> $DIR/lint-unused-mut-variables.rs:196:9
+  --> $DIR/lint-unused-mut-variables.rs:202:9
    |
 LL |     let mut b = vec![2];
    |         ----^
@@ -205,10 +213,10 @@ LL |     let mut b = vec![2];
    |         help: remove this `mut`
    |
 note: lint level defined here
-  --> $DIR/lint-unused-mut-variables.rs:192:8
+  --> $DIR/lint-unused-mut-variables.rs:198:8
    |
 LL | #[deny(unused_mut)]
    |        ^^^^^^^^^^
 
-error: aborting due to 25 previous errors
+error: aborting due to 26 previous errors
 
diff --git a/src/test/ui/lint/must_use-unit.rs b/src/test/ui/lint/must_use-unit.rs
index 8f59bab26d3..4dd4798abb7 100644
--- a/src/test/ui/lint/must_use-unit.rs
+++ b/src/test/ui/lint/must_use-unit.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![deny(unused_must_use)]
 
 #[must_use]
diff --git a/src/test/ui/lint/must_use-unit.stderr b/src/test/ui/lint/must_use-unit.stderr
index a6d0259a081..0a9939b2015 100644
--- a/src/test/ui/lint/must_use-unit.stderr
+++ b/src/test/ui/lint/must_use-unit.stderr
@@ -1,17 +1,17 @@
 error: unused return value of `foo` that must be used
-  --> $DIR/must_use-unit.rs:12:5
+  --> $DIR/must_use-unit.rs:13:5
    |
 LL |     foo();
    |     ^^^^^^
    |
 note: lint level defined here
-  --> $DIR/must_use-unit.rs:1:9
+  --> $DIR/must_use-unit.rs:2:9
    |
 LL | #![deny(unused_must_use)]
    |         ^^^^^^^^^^^^^^^
 
 error: unused return value of `bar` that must be used
-  --> $DIR/must_use-unit.rs:14:5
+  --> $DIR/must_use-unit.rs:15:5
    |
 LL |     bar();
    |     ^^^^^^
diff --git a/src/test/ui/lint/uninitialized-zeroed.rs b/src/test/ui/lint/uninitialized-zeroed.rs
index ed2369fd650..473be434a75 100644
--- a/src/test/ui/lint/uninitialized-zeroed.rs
+++ b/src/test/ui/lint/uninitialized-zeroed.rs
@@ -2,7 +2,7 @@
 // This test checks that calling `mem::{uninitialized,zeroed}` with certain types results
 // in a lint.
 
-#![feature(rustc_attrs)]
+#![feature(never_type, rustc_attrs)]
 #![allow(deprecated)]
 #![deny(invalid_value)]
 
diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs
index c4fb68c0278..6c4160c36aa 100644
--- a/src/test/ui/loops/loop-break-value.rs
+++ b/src/test/ui/loops/loop-break-value.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 fn main() {
     let val: ! = loop { break break; };
     //~^ ERROR mismatched types
diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr
index 1f2d81ff03f..3bb0cd50d63 100644
--- a/src/test/ui/loops/loop-break-value.stderr
+++ b/src/test/ui/loops/loop-break-value.stderr
@@ -1,5 +1,5 @@
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/loop-break-value.rs:24:5
+  --> $DIR/loop-break-value.rs:26:5
    |
 LL |     'while_loop: while true {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
@@ -7,7 +7,7 @@ LL |     'while_loop: while true {
    = note: `#[warn(while_true)]` on by default
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:26:9
+  --> $DIR/loop-break-value.rs:28:9
    |
 LL |         break ();
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -18,7 +18,7 @@ LL |         break;
    |         ^^^^^
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:28:13
+  --> $DIR/loop-break-value.rs:30:13
    |
 LL |             break 'while_loop 123;
    |             ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -29,7 +29,7 @@ LL |             break;
    |             ^^^^^
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:36:12
+  --> $DIR/loop-break-value.rs:38:12
    |
 LL |         if break () {
    |            ^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -40,7 +40,7 @@ LL |         if break {
    |            ^^^^^
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:41:9
+  --> $DIR/loop-break-value.rs:43:9
    |
 LL |         break None;
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -51,7 +51,7 @@ LL |         break;
    |         ^^^^^
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:47:13
+  --> $DIR/loop-break-value.rs:49:13
    |
 LL |             break 'while_let_loop "nope";
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -62,7 +62,7 @@ LL |             break;
    |             ^^^^^
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:54:9
+  --> $DIR/loop-break-value.rs:56:9
    |
 LL |         break ();
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -73,7 +73,7 @@ LL |         break;
    |         ^^^^^
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:55:9
+  --> $DIR/loop-break-value.rs:57:9
    |
 LL |         break [()];
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -84,7 +84,7 @@ LL |         break;
    |         ^^^^^
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:62:13
+  --> $DIR/loop-break-value.rs:64:13
    |
 LL |             break 'for_loop Some(17);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
@@ -95,7 +95,7 @@ LL |             break;
    |             ^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:2:31
+  --> $DIR/loop-break-value.rs:4:31
    |
 LL |     let val: ! = loop { break break; };
    |                               ^^^^^ expected `!`, found `()`
@@ -104,31 +104,31 @@ LL |     let val: ! = loop { break break; };
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:9:19
+  --> $DIR/loop-break-value.rs:11:19
    |
 LL |             break 123;
    |                   ^^^ expected `&str`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:14:15
+  --> $DIR/loop-break-value.rs:16:15
    |
 LL |         break "asdf";
    |               ^^^^^^ expected `i32`, found `&str`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:19:31
+  --> $DIR/loop-break-value.rs:21:31
    |
 LL |             break 'outer_loop "nope";
    |                               ^^^^^^ expected `i32`, found `&str`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:71:26
+  --> $DIR/loop-break-value.rs:73:26
    |
 LL |                 break 'c 123;
    |                          ^^^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:78:15
+  --> $DIR/loop-break-value.rs:80:15
    |
 LL |         break (break, break);
    |               ^^^^^^^^^^^^^^ expected `()`, found tuple
@@ -137,13 +137,13 @@ LL |         break (break, break);
                   found tuple `(!, !)`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:83:15
+  --> $DIR/loop-break-value.rs:85:15
    |
 LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:88:9
+  --> $DIR/loop-break-value.rs:90:9
    |
 LL |         break;
    |         ^^^^^
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index fcd97647568..f3f3c476809 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `std::vec::Vec<T>`
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
    |
 LL |     let mut x = Vec::new();
-   |         -----   ^^^^^^^^ cannot infer type for `T`
+   |         -----   ^^^^^^^^ cannot infer type for type parameter `T`
    |         |
    |         consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
 
diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
index 9f46a722a50..fa3add81a28 100644
--- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr
@@ -9,9 +9,15 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize`
    |
 LL | impl Me2 for usize { fn me(&self) -> usize { *self } }
    |                      ^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `Me2::me(1_usize)` instead
    = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize`
-   = help: to disambiguate the method call, write `ambig_impl_2_lib::Me::me(1_usize)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL | fn main() { Me2::me(&1_usize); }
+   |             ^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL | fn main() { ambig_impl_2_lib::Me::me(&1_usize); }
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr
index 6c493c67e29..b6c81c2377e 100644
--- a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A`
    |
 LL | trait A { fn foo(&self); }
    |           ^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `A::foo(t)` instead
 note: candidate #2 is defined in the trait `B`
   --> $DIR/method-ambig-two-traits-from-bounds.rs:2:11
    |
 LL | trait B { fn foo(&self); }
    |           ^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `B::foo(t)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     A::foo(t);
+   |     ^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     B::foo(t);
+   |     ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr
index 0b3724e030f..71c65f7ccc6 100644
--- a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB`
    |
 LL |     fn foo(self) {}
    |     ^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `A::foo(AB {})` instead
 note: candidate #2 is defined in an impl of the trait `B` for the type `AB`
   --> $DIR/method-ambig-two-traits-from-impls.rs:11:5
    |
 LL |     fn foo(self) {}
    |     ^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `B::foo(AB {})` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     A::foo(AB {});
+   |     ^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     B::foo(AB {});
+   |     ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr
index 81c99b33c81..44f85071505 100644
--- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB`
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
-   = help: to disambiguate the method call, write `A::foo(...)` instead
 note: candidate #2 is defined in an impl of the trait `B` for the type `AB`
   --> $DIR/method-ambig-two-traits-from-impls2.rs:11:5
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
-   = help: to disambiguate the method call, write `B::foo(...)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     A::foo();
+   |     ^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     B::foo();
+   |     ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr
index dc8aef25037..3dbb1737100 100644
--- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr
+++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize`
    |
 LL | trait Foo { fn method(&self) {} }
    |             ^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `Foo::method(1_usize)` instead
 note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize`
   --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13
    |
 LL | trait Bar { fn method(&self) {} }
    |             ^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `Bar::method(1_usize)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     Foo::method(&1_usize);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     Bar::method(&1_usize);
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
index c9d7da84e09..e7f295df8c4 100644
--- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
+++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
@@ -25,19 +25,28 @@ note: candidate #1 is defined in an impl of the trait `internal::X` for the type
    |
 LL |         fn foo(self: Smaht<Self, u64>) -> u64 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `internal::X::foo(x)` instead
 note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_`
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9
    |
 LL |         fn foo(self) {}
    |         ^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `nuisance_foo::NuisanceFoo::foo(x)` instead
 note: candidate #3 is defined in the trait `FinalFoo`
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5
    |
 LL |     fn foo(&self) -> u8;
    |     ^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `FinalFoo::foo(x)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     let z = internal::X::foo(x);
+   |             ^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     let z = nuisance_foo::NuisanceFoo::foo(x);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #3
+   |
+LL |     let z = FinalFoo::foo(x);
+   |             ^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24
diff --git a/src/test/ui/mir/mir_calls_to_shims.rs b/src/test/ui/mir/mir_calls_to_shims.rs
index df7c45ad1d1..6f13d5612ce 100644
--- a/src/test/ui/mir/mir_calls_to_shims.rs
+++ b/src/test/ui/mir/mir_calls_to_shims.rs
@@ -2,6 +2,7 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(fn_traits)]
+#![feature(never_type)]
 
 use std::panic;
 
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter.stderr b/src/test/ui/missing/missing-items/missing-type-parameter.stderr
index dbb467d60f9..1219badc5b3 100644
--- a/src/test/ui/missing/missing-items/missing-type-parameter.stderr
+++ b/src/test/ui/missing/missing-items/missing-type-parameter.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/missing-type-parameter.rs:4:5
    |
 LL |     foo();
-   |     ^^^ cannot infer type for `X`
+   |     ^^^ cannot infer type for type parameter `X` declared on the function `foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/never_type/adjust_never.rs b/src/test/ui/never_type/adjust_never.rs
index e4d15c8a17d..0d7d2c0ed3f 100644
--- a/src/test/ui/never_type/adjust_never.rs
+++ b/src/test/ui/never_type/adjust_never.rs
@@ -2,6 +2,8 @@
 
 // check-pass
 
+#![feature(never_type)]
+
 fn main() {
     let x: ! = panic!();
     let y: u32 = x;
diff --git a/src/test/ui/never_type/auto-traits.rs b/src/test/ui/never_type/auto-traits.rs
index 8a02720ab27..2d9689888cb 100644
--- a/src/test/ui/never_type/auto-traits.rs
+++ b/src/test/ui/never_type/auto-traits.rs
@@ -1,6 +1,7 @@
 // check-pass
 
 #![feature(optin_builtin_traits)]
+#![feature(never_type)]
 
 fn main() {
     enum Void {}
diff --git a/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs
index a2b44e91f11..d06637e74a2 100644
--- a/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs
+++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.rs
@@ -1,5 +1,7 @@
 // Test that we can't pass other types for !
 
+#![feature(never_type)]
+
 fn foo(x: !) -> ! {
     x
 }
diff --git a/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr
index 69049fc8db6..eacef1dc330 100644
--- a/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr
+++ b/src/test/ui/never_type/call-fn-never-arg-wrong-type.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/call-fn-never-arg-wrong-type.rs:8:9
+  --> $DIR/call-fn-never-arg-wrong-type.rs:10:9
    |
 LL |     foo("wow");
    |         ^^^^^ expected `!`, found `&str`
diff --git a/src/test/ui/never_type/call-fn-never-arg.rs b/src/test/ui/never_type/call-fn-never-arg.rs
index 55a7b79157a..9d355817ee8 100644
--- a/src/test/ui/never_type/call-fn-never-arg.rs
+++ b/src/test/ui/never_type/call-fn-never-arg.rs
@@ -2,6 +2,7 @@
 
 // check-pass
 
+#![feature(never_type)]
 #![allow(unreachable_code)]
 
 fn foo(x: !) -> ! {
diff --git a/src/test/ui/never_type/cast-never.rs b/src/test/ui/never_type/cast-never.rs
index fbba114ab32..0139ebe4640 100644
--- a/src/test/ui/never_type/cast-never.rs
+++ b/src/test/ui/never_type/cast-never.rs
@@ -2,6 +2,8 @@
 
 // check-pass
 
+#![feature(never_type)]
+
 fn main() {
     let x: ! = panic!();
     let y: u32 = x as u32;
diff --git a/src/test/ui/never_type/defaulted-never-note.rs b/src/test/ui/never_type/defaulted-never-note.rs
index c58b6117484..1780cb6535d 100644
--- a/src/test/ui/never_type/defaulted-never-note.rs
+++ b/src/test/ui/never_type/defaulted-never-note.rs
@@ -1,6 +1,6 @@
 // We need to opt into the `never_type_fallback` feature
 // to trigger the requirement that this is testing.
-#![feature(never_type_fallback)]
+#![feature(never_type, never_type_fallback)]
 
 #![allow(unused)]
 
diff --git a/src/test/ui/never_type/dispatch_from_dyn_zst.rs b/src/test/ui/never_type/dispatch_from_dyn_zst.rs
index 342d5e47915..764f58ce9e8 100644
--- a/src/test/ui/never_type/dispatch_from_dyn_zst.rs
+++ b/src/test/ui/never_type/dispatch_from_dyn_zst.rs
@@ -1,6 +1,6 @@
 // run-pass
 
-#![feature(unsize, dispatch_from_dyn)]
+#![feature(unsize, dispatch_from_dyn, never_type)]
 
 #![allow(dead_code)]
 
diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs
index df04437b1ae..ea4881049d7 100644
--- a/src/test/ui/never_type/diverging-fallback-control-flow.rs
+++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs
@@ -11,7 +11,7 @@
 // These represent current behavior, but are pretty dubious.  I would
 // like to revisit these and potentially change them. --nmatsakis
 
-#![feature(never_type_fallback)]
+#![feature(never_type, never_type_fallback)]
 
 trait BadDefault {
     fn default() -> Self;
diff --git a/src/test/ui/never_type/impl-for-never.rs b/src/test/ui/never_type/impl-for-never.rs
index cbfda9a2cc0..9423f08858b 100644
--- a/src/test/ui/never_type/impl-for-never.rs
+++ b/src/test/ui/never_type/impl-for-never.rs
@@ -1,5 +1,7 @@
 // run-pass
 
+#![feature(never_type)]
+
 // Test that we can call static methods on ! both directly and when it appears in a generic
 
 trait StringifyType {
diff --git a/src/test/ui/never_type/issue-44402.rs b/src/test/ui/never_type/issue-44402.rs
index 0e6588bbe78..699e480dfe7 100644
--- a/src/test/ui/never_type/issue-44402.rs
+++ b/src/test/ui/never_type/issue-44402.rs
@@ -1,6 +1,7 @@
 // check-pass
 
 #![allow(dead_code)]
+#![feature(never_type)]
 #![feature(exhaustive_patterns)]
 
 // Regression test for inhabitedness check. The old
diff --git a/src/test/ui/never_type/never-assign-dead-code.rs b/src/test/ui/never_type/never-assign-dead-code.rs
index 5c1300c7151..7bb7c87097c 100644
--- a/src/test/ui/never_type/never-assign-dead-code.rs
+++ b/src/test/ui/never_type/never-assign-dead-code.rs
@@ -2,6 +2,7 @@
 
 // check-pass
 
+#![feature(never_type)]
 #![warn(unused)]
 
 fn main() {
diff --git a/src/test/ui/never_type/never-assign-dead-code.stderr b/src/test/ui/never_type/never-assign-dead-code.stderr
index 1dc15251d1a..1860150fa8b 100644
--- a/src/test/ui/never_type/never-assign-dead-code.stderr
+++ b/src/test/ui/never_type/never-assign-dead-code.stderr
@@ -1,5 +1,5 @@
 warning: unreachable statement
-  --> $DIR/never-assign-dead-code.rs:9:5
+  --> $DIR/never-assign-dead-code.rs:10:5
    |
 LL |     let x: ! = panic!("aah");
    |                ------------- any code following this expression is unreachable
@@ -7,7 +7,7 @@ LL |     drop(x);
    |     ^^^^^^^^ unreachable statement
    |
 note: lint level defined here
-  --> $DIR/never-assign-dead-code.rs:5:9
+  --> $DIR/never-assign-dead-code.rs:6:9
    |
 LL | #![warn(unused)]
    |         ^^^^^^
@@ -15,7 +15,7 @@ LL | #![warn(unused)]
    = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 warning: unreachable call
-  --> $DIR/never-assign-dead-code.rs:9:5
+  --> $DIR/never-assign-dead-code.rs:10:5
    |
 LL |     drop(x);
    |     ^^^^ - any code following this expression is unreachable
@@ -23,13 +23,13 @@ LL |     drop(x);
    |     unreachable call
 
 warning: unused variable: `x`
-  --> $DIR/never-assign-dead-code.rs:8:9
+  --> $DIR/never-assign-dead-code.rs:9:9
    |
 LL |     let x: ! = panic!("aah");
    |         ^ help: consider prefixing with an underscore: `_x`
    |
 note: lint level defined here
-  --> $DIR/never-assign-dead-code.rs:5:9
+  --> $DIR/never-assign-dead-code.rs:6:9
    |
 LL | #![warn(unused)]
    |         ^^^^^^
diff --git a/src/test/ui/never_type/never-assign-wrong-type.rs b/src/test/ui/never_type/never-assign-wrong-type.rs
index 9ca1ac7462d..67e26f5663f 100644
--- a/src/test/ui/never_type/never-assign-wrong-type.rs
+++ b/src/test/ui/never_type/never-assign-wrong-type.rs
@@ -1,5 +1,6 @@
 // Test that we can't use another type in place of !
 
+#![feature(never_type)]
 #![deny(warnings)]
 
 fn main() {
diff --git a/src/test/ui/never_type/never-assign-wrong-type.stderr b/src/test/ui/never_type/never-assign-wrong-type.stderr
index 4349d98029e..ce34d948324 100644
--- a/src/test/ui/never_type/never-assign-wrong-type.stderr
+++ b/src/test/ui/never_type/never-assign-wrong-type.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/never-assign-wrong-type.rs:6:16
+  --> $DIR/never-assign-wrong-type.rs:7:16
    |
 LL |     let x: ! = "hello";
    |            -   ^^^^^^^ expected `!`, found `&str`
diff --git a/src/test/ui/never_type/never-associated-type.rs b/src/test/ui/never_type/never-associated-type.rs
index 45e54b9bf7c..3bb917c9316 100644
--- a/src/test/ui/never_type/never-associated-type.rs
+++ b/src/test/ui/never_type/never-associated-type.rs
@@ -2,6 +2,8 @@
 
 // check-pass
 
+#![feature(never_type)]
+
 trait Foo {
     type Wow;
 
diff --git a/src/test/ui/never_type/never-from-impl-is-reserved.rs b/src/test/ui/never_type/never-from-impl-is-reserved.rs
index df74b6a53f8..9d16015bdc1 100644
--- a/src/test/ui/never_type/never-from-impl-is-reserved.rs
+++ b/src/test/ui/never_type/never-from-impl-is-reserved.rs
@@ -1,5 +1,7 @@
 // check that the `for<T> T: From<!>` impl is reserved
 
+#![feature(never_type)]
+
 pub struct MyFoo;
 pub trait MyTrait {}
 
diff --git a/src/test/ui/never_type/never-from-impl-is-reserved.stderr b/src/test/ui/never_type/never-from-impl-is-reserved.stderr
index 8b3155988ea..8b8d0f4ea73 100644
--- a/src/test/ui/never_type/never-from-impl-is-reserved.stderr
+++ b/src/test/ui/never_type/never-from-impl-is-reserved.stderr
@@ -1,5 +1,5 @@
 error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`:
-  --> $DIR/never-from-impl-is-reserved.rs:8:1
+  --> $DIR/never-from-impl-is-reserved.rs:10:1
    |
 LL | impl MyTrait for MyFoo {}
    | ---------------------- first implementation here
diff --git a/src/test/ui/never_type/never-result.rs b/src/test/ui/never_type/never-result.rs
index 800553fce87..35af37910ef 100644
--- a/src/test/ui/never_type/never-result.rs
+++ b/src/test/ui/never_type/never-result.rs
@@ -5,6 +5,8 @@
 
 // Test that we can extract a ! through pattern matching then use it as several different types.
 
+#![feature(never_type)]
+
 fn main() {
     let x: Result<u32, !> = Ok(123);
     match x {
diff --git a/src/test/ui/never_type/never-type-arg.rs b/src/test/ui/never_type/never-type-arg.rs
index 3cbb114f43b..13cd59e6aa9 100644
--- a/src/test/ui/never_type/never-type-arg.rs
+++ b/src/test/ui/never_type/never-type-arg.rs
@@ -2,6 +2,8 @@
 
 // check-pass
 
+#![feature(never_type)]
+
 struct Wub;
 
 impl PartialEq<!> for Wub {
diff --git a/src/test/ui/never_type/never-type-rvalues.rs b/src/test/ui/never_type/never-type-rvalues.rs
index 9bfc5572b9e..9ccc73dbf92 100644
--- a/src/test/ui/never_type/never-type-rvalues.rs
+++ b/src/test/ui/never_type/never-type-rvalues.rs
@@ -1,5 +1,6 @@
 // run-pass
 
+#![feature(never_type)]
 #![allow(dead_code)]
 #![allow(path_statements)]
 #![allow(unreachable_patterns)]
diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.rs b/src/test/ui/never_type/never-value-fallback-issue-66757.rs
new file mode 100644
index 00000000000..f2e9e087307
--- /dev/null
+++ b/src/test/ui/never_type/never-value-fallback-issue-66757.rs
@@ -0,0 +1,29 @@
+// Regression test for #66757
+//
+// Test than when you have a `!` value (e.g., the local variable
+// never) and an uninferred variable (here the argument to `From`) it
+// doesn't fallback to `()` but rather `!`.
+//
+// run-pass
+
+#![feature(never_type)]
+
+// FIXME(#67225) -- this should be true even without the fallback gate.
+#![feature(never_type_fallback)]
+
+struct E;
+
+impl From<!> for E {
+    fn from(_: !) -> E {
+        E
+    }
+}
+
+#[allow(unreachable_code)]
+#[allow(dead_code)]
+fn foo(never: !) {
+    <E as From<!>>::from(never);  // Ok
+    <E as From<_>>::from(never);  // Inference fails here
+}
+
+fn main() { }
diff --git a/src/test/ui/never_type/never_transmute_never.rs b/src/test/ui/never_type/never_transmute_never.rs
index cdf04de19e5..fce3ced9aac 100644
--- a/src/test/ui/never_type/never_transmute_never.rs
+++ b/src/test/ui/never_type/never_transmute_never.rs
@@ -2,6 +2,7 @@
 
 #![crate_type="lib"]
 
+#![feature(never_type)]
 #![allow(dead_code)]
 #![allow(unreachable_code)]
 #![allow(unused_variables)]
diff --git a/src/test/ui/never_type/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs
index e5e0e188de6..e0c30160b9e 100644
--- a/src/test/ui/never_type/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/never_type/panic-uninitialized-zeroed.rs
@@ -3,6 +3,7 @@
 // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
 // in a runtime panic.
 
+#![feature(never_type)]
 #![allow(deprecated, invalid_value)]
 
 use std::{mem, panic};
diff --git a/src/test/ui/never_type/try_from.rs b/src/test/ui/never_type/try_from.rs
index 977ea3656b3..50451576f9c 100644
--- a/src/test/ui/never_type/try_from.rs
+++ b/src/test/ui/never_type/try_from.rs
@@ -5,6 +5,8 @@
 // This test was added to show the motivation for doing this
 // over `TryFrom` being blanket impl for all `T: From`
 
+#![feature(never_type)]
+
 use std::convert::{TryInto, Infallible};
 
 struct Foo<T> {
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
index b676ea851a3..ce6836f30f9 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs
@@ -21,7 +21,7 @@ use E::*;
 
 fn no_top_level_or_patterns() {
     // We do *not* allow or-patterns at the top level of lambdas...
-    let _ = |A | B: E| (); //~ ERROR binary operation `|` cannot be applied to type `E`
+    let _ = |A | B: E| (); //~ ERROR no implementation for `E | ()`
     //           -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`.
 
     // ...and for now neither do we allow or-patterns at the top level of functions.
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
index b6ff39d64d6..e77d92e8b07 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -104,7 +104,7 @@ LL | #![feature(or_patterns)]
    |
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0369]: binary operation `|` cannot be applied to type `E`
+error[E0369]: no implementation for `E | ()`
   --> $DIR/or-patterns-syntactic-fail.rs:24:22
    |
 LL |     let _ = |A | B: E| ();
diff --git a/src/test/ui/packed/packed-struct-address-of-element.rs b/src/test/ui/packed/packed-struct-address-of-element.rs
new file mode 100644
index 00000000000..812d23fb580
--- /dev/null
+++ b/src/test/ui/packed/packed-struct-address-of-element.rs
@@ -0,0 +1,37 @@
+// run-pass
+#![allow(dead_code)]
+#![deny(safe_packed_borrows)]
+#![feature(raw_ref_op)]
+// ignore-emscripten weird assertion?
+
+#[repr(packed)]
+struct Foo1 {
+    bar: u8,
+    baz: usize
+}
+
+#[repr(packed(2))]
+struct Foo2 {
+    bar: u8,
+    baz: usize
+}
+
+#[repr(C, packed(4))]
+struct Foo4C {
+    bar: u8,
+    baz: usize
+}
+
+pub fn main() {
+    let foo = Foo1 { bar: 1, baz: 2 };
+    let brw = &raw const foo.baz;
+    unsafe { assert_eq!(brw.read_unaligned(), 2); }
+
+    let foo = Foo2 { bar: 1, baz: 2 };
+    let brw = &raw const foo.baz;
+    unsafe { assert_eq!(brw.read_unaligned(), 2); }
+
+    let mut foo = Foo4C { bar: 1, baz: 2 };
+    let brw = &raw mut foo.baz;
+    unsafe { assert_eq!(brw.read_unaligned(), 2); }
+}
diff --git a/src/test/ui/packed/packed-struct-borrow-element.rs b/src/test/ui/packed/packed-struct-borrow-element.rs
index 6ac42ed0d47..0072b6191eb 100644
--- a/src/test/ui/packed/packed-struct-borrow-element.rs
+++ b/src/test/ui/packed/packed-struct-borrow-element.rs
@@ -1,4 +1,4 @@
-// run-pass
+// run-pass (note: this is spec-UB, but it works for now)
 #![allow(dead_code)]
 // ignore-emscripten weird assertion?
 
diff --git a/src/test/ui/parser/impl-item-const-pass.rs b/src/test/ui/parser/impl-item-const-pass.rs
new file mode 100644
index 00000000000..d1124561374
--- /dev/null
+++ b/src/test/ui/parser/impl-item-const-pass.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl X {
+    const Y: u8;
+}
diff --git a/src/test/ui/parser/impl-item-const-semantic-fail.rs b/src/test/ui/parser/impl-item-const-semantic-fail.rs
new file mode 100644
index 00000000000..5d4692f9f14
--- /dev/null
+++ b/src/test/ui/parser/impl-item-const-semantic-fail.rs
@@ -0,0 +1,7 @@
+fn main() {}
+
+struct X;
+
+impl X {
+    const Y: u8; //~ ERROR associated constant in `impl` without body
+}
diff --git a/src/test/ui/parser/impl-item-const-semantic-fail.stderr b/src/test/ui/parser/impl-item-const-semantic-fail.stderr
new file mode 100644
index 00000000000..ec3bee0ce68
--- /dev/null
+++ b/src/test/ui/parser/impl-item-const-semantic-fail.stderr
@@ -0,0 +1,10 @@
+error: associated constant in `impl` without body
+  --> $DIR/impl-item-const-semantic-fail.rs:6:5
+   |
+LL |     const Y: u8;
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the constant: `= <expr>;`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/impl-item-fn-no-body-pass.rs b/src/test/ui/parser/impl-item-fn-no-body-pass.rs
new file mode 100644
index 00000000000..16b09d64e8c
--- /dev/null
+++ b/src/test/ui/parser/impl-item-fn-no-body-pass.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl X {
+    fn f();
+}
diff --git a/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs
new file mode 100644
index 00000000000..cb183db5964
--- /dev/null
+++ b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.rs
@@ -0,0 +1,7 @@
+fn main() {}
+
+struct X;
+
+impl X {
+    fn f(); //~ ERROR associated function in `impl` without body
+}
diff --git a/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr
new file mode 100644
index 00000000000..1acb727368b
--- /dev/null
+++ b/src/test/ui/parser/impl-item-fn-no-body-semantic-fail.stderr
@@ -0,0 +1,10 @@
+error: associated function in `impl` without body
+  --> $DIR/impl-item-fn-no-body-semantic-fail.rs:6:5
+   |
+LL |     fn f();
+   |     ^^^^^^-
+   |           |
+   |           help: provide a definition for the function: `{ <body> }`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/impl-item-type-no-body-pass.rs b/src/test/ui/parser/impl-item-type-no-body-pass.rs
new file mode 100644
index 00000000000..74a9c6ab7e8
--- /dev/null
+++ b/src/test/ui/parser/impl-item-type-no-body-pass.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl X {
+    type Y;
+    type Z: Ord;
+    type W: Ord where Self: Eq;
+    type W where Self: Eq;
+}
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
new file mode 100644
index 00000000000..71c7d4ba21d
--- /dev/null
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
@@ -0,0 +1,22 @@
+#![feature(generic_associated_types)]
+//~^ WARN the feature `generic_associated_types` is incomplete
+
+fn main() {}
+
+struct X;
+
+impl X {
+    type Y;
+    //~^ ERROR associated type in `impl` without body
+    //~| ERROR associated types are not yet supported in inherent impls
+    type Z: Ord;
+    //~^ ERROR associated type in `impl` without body
+    //~| ERROR bounds on associated `type`s in `impl`s have no effect
+    //~| ERROR associated types are not yet supported in inherent impls
+    type W: Ord where Self: Eq;
+    //~^ ERROR associated type in `impl` without body
+    //~| ERROR bounds on associated `type`s in `impl`s have no effect
+    //~| ERROR associated types are not yet supported in inherent impls
+    type W where Self: Eq;
+    //~^ ERROR associated type in `impl` without body
+}
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
new file mode 100644
index 00000000000..6f1439c8f0b
--- /dev/null
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
@@ -0,0 +1,73 @@
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5
+   |
+LL |     type Y;
+   |     ^^^^^^-
+   |           |
+   |           help: provide a definition for the type: `= <type>;`
+
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:5
+   |
+LL |     type Z: Ord;
+   |     ^^^^^^^^^^^-
+   |                |
+   |                help: provide a definition for the type: `= <type>;`
+
+error: bounds on associated `type`s in `impl`s have no effect
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13
+   |
+LL |     type Z: Ord;
+   |             ^^^
+
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:5
+   |
+LL |     type W: Ord where Self: Eq;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                               |
+   |                               help: provide a definition for the type: `= <type>;`
+
+error: bounds on associated `type`s in `impl`s have no effect
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13
+   |
+LL |     type W: Ord where Self: Eq;
+   |             ^^^
+
+error: associated type in `impl` without body
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:20:5
+   |
+LL |     type W where Self: Eq;
+   |     ^^^^^^^^^^^^^^^^^^^^^-
+   |                          |
+   |                          help: provide a definition for the type: `= <type>;`
+
+warning: the feature `generic_associated_types` is incomplete and may cause the compiler to crash
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:1:12
+   |
+LL | #![feature(generic_associated_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0202]: associated types are not yet supported in inherent impls (see #8995)
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5
+   |
+LL |     type Y;
+   |     ^^^^^^^
+
+error[E0202]: associated types are not yet supported in inherent impls (see #8995)
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:5
+   |
+LL |     type Z: Ord;
+   |     ^^^^^^^^^^^^
+
+error[E0202]: associated types are not yet supported in inherent impls (see #8995)
+  --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:5
+   |
+LL |     type W: Ord where Self: Eq;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0202`.
diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr
index 70f55f0aeb9..6e20a9ce3c4 100644
--- a/src/test/ui/parser/issue-21153.stderr
+++ b/src/test/ui/parser/issue-21153.stderr
@@ -1,4 +1,4 @@
-error: missing `fn`, `type`, or `const` for trait-item declaration
+error: missing `fn`, `type`, or `const` for associated-item declaration
   --> $DIR/issue-21153.rs:1:29
    |
 LL |   trait MyTrait<T>: Iterator {
diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr
index 70256a59231..1a97f54160b 100644
--- a/src/test/ui/parser/issue-32446.stderr
+++ b/src/test/ui/parser/issue-32446.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...`
   --> $DIR/issue-32446.rs:4:11
    |
 LL | trait T { ... }
-   |           ^^^ expected one of 9 possible tokens
+   |           ^^^ expected one of 10 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.rs b/src/test/ui/parser/lifetime-in-pattern-recover.rs
new file mode 100644
index 00000000000..7fb14b80076
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.rs
@@ -0,0 +1,6 @@
+fn main() {
+    let &'a x = &0; //~ ERROR unexpected lifetime `'a` in pattern
+    let &'a mut y = &mut 0; //~ ERROR unexpected lifetime `'a` in pattern
+
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/lifetime-in-pattern-recover.stderr b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
new file mode 100644
index 00000000000..4bf7f57bfb5
--- /dev/null
+++ b/src/test/ui/parser/lifetime-in-pattern-recover.stderr
@@ -0,0 +1,23 @@
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:2:10
+   |
+LL |     let &'a x = &0;
+   |          ^^ help: remove the lifetime
+
+error: unexpected lifetime `'a` in pattern
+  --> $DIR/lifetime-in-pattern-recover.rs:3:10
+   |
+LL |     let &'a mut y = &mut 0;
+   |          ^^ help: remove the lifetime
+
+error[E0308]: mismatched types
+  --> $DIR/lifetime-in-pattern-recover.rs:5:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/lifetime-in-pattern.rs b/src/test/ui/parser/lifetime-in-pattern.rs
index afee685cd05..d3c638d0cd7 100644
--- a/src/test/ui/parser/lifetime-in-pattern.rs
+++ b/src/test/ui/parser/lifetime-in-pattern.rs
@@ -1,5 +1,6 @@
 fn test(&'a str) {
     //~^ ERROR unexpected lifetime `'a` in pattern
+    //~| ERROR expected one of `:`, `@`, or `|`, found `)`
 }
 
 fn main() {
diff --git a/src/test/ui/parser/lifetime-in-pattern.stderr b/src/test/ui/parser/lifetime-in-pattern.stderr
index e525c7b6d68..71fd3cdf723 100644
--- a/src/test/ui/parser/lifetime-in-pattern.stderr
+++ b/src/test/ui/parser/lifetime-in-pattern.stderr
@@ -2,7 +2,13 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/lifetime-in-pattern.rs:1:10
    |
 LL | fn test(&'a str) {
-   |          ^^ unexpected lifetime
+   |          ^^ help: remove the lifetime
 
-error: aborting due to previous error
+error: expected one of `:`, `@`, or `|`, found `)`
+  --> $DIR/lifetime-in-pattern.rs:1:16
+   |
+LL | fn test(&'a str) {
+   |                ^ expected one of `:`, `@`, or `|`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr
index 0a433ab278e..7647ba500e0 100644
--- a/src/test/ui/parser/macro/trait-non-item-macros.stderr
+++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2`
   --> $DIR/trait-non-item-macros.rs:2:19
    |
 LL |     ($a:expr) => ($a)
-   |                   ^^ expected one of 8 possible tokens
+   |                   ^^ expected one of 9 possible tokens
 ...
 LL |     bah!(2);
    |     -------- in this macro invocation
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
index cbaf9315e85..7e8abf22d55 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
@@ -7,11 +7,11 @@ LL | trait T {
 LL | fn main() {}
    |                                                                  ^
 
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
+error: expected one of `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
   --> $DIR/missing-close-brace-in-trait.rs:5:12
    |
 LL | pub(crate) struct Bar<T>();
-   |            ^^^^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+   |            ^^^^^^ expected one of 7 possible tokens
 
 error[E0601]: `main` function not found in crate `missing_close_brace_in_trait`
   --> $DIR/missing-close-brace-in-trait.rs:1:1
diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs
new file mode 100644
index 00000000000..09f967f161e
--- /dev/null
+++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs
@@ -0,0 +1,12 @@
+#![feature(specialization)]
+
+fn main() {}
+
+trait X {
+    default const A: u8; //~ ERROR `default` is only allowed on items in `impl` definitions
+    default const B: u8 = 0;  //~ ERROR `default` is only allowed on items in `impl` definitions
+    default type D; //~ ERROR `default` is only allowed on items in `impl` definitions
+    default type C: Ord; //~ ERROR `default` is only allowed on items in `impl` definitions
+    default fn f1(); //~ ERROR `default` is only allowed on items in `impl` definitions
+    default fn f2() {} //~ ERROR `default` is only allowed on items in `impl` definitions
+}
diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
new file mode 100644
index 00000000000..54111df3423
--- /dev/null
+++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr
@@ -0,0 +1,38 @@
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:6:5
+   |
+LL |     default const A: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:7:5
+   |
+LL |     default const B: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:8:5
+   |
+LL |     default type D;
+   |     ^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:9:5
+   |
+LL |     default type C: Ord;
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:10:5
+   |
+LL |     default fn f1();
+   |     ^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/trait-item-with-defaultness-fail-semantic.rs:11:5
+   |
+LL |     default fn f2() {}
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/parser/trait-item-with-defaultness-pass.rs b/src/test/ui/parser/trait-item-with-defaultness-pass.rs
new file mode 100644
index 00000000000..a6318bd99e2
--- /dev/null
+++ b/src/test/ui/parser/trait-item-with-defaultness-pass.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+trait X {
+    default const A: u8;
+    default const B: u8 = 0;
+    default type D;
+    default type C: Ord;
+    default fn f1();
+    default fn f2() {}
+}
diff --git a/src/test/ui/parser/variadic-ffi-3.rs b/src/test/ui/parser/variadic-ffi-3.rs
deleted file mode 100644
index ce83cc87abe..00000000000
--- a/src/test/ui/parser/variadic-ffi-3.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn foo(x: isize, ...) {
-    //~^ ERROR: only foreign functions are allowed to be C-variadic
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/variadic-ffi-3.stderr b/src/test/ui/parser/variadic-ffi-3.stderr
deleted file mode 100644
index aeeebdb9914..00000000000
--- a/src/test/ui/parser/variadic-ffi-3.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0743]: only foreign functions are allowed to be C-variadic
-  --> $DIR/variadic-ffi-3.rs:1:18
-   |
-LL | fn foo(x: isize, ...) {
-   |                  ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0743`.
diff --git a/src/test/ui/parser/variadic-ffi-4.rs b/src/test/ui/parser/variadic-ffi-4.rs
deleted file mode 100644
index 5f8b3f8f539..00000000000
--- a/src/test/ui/parser/variadic-ffi-4.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-extern "C" fn foo(x: isize, ...) {
-    //~^ ERROR: only foreign functions are allowed to be C-variadic
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/variadic-ffi-4.stderr b/src/test/ui/parser/variadic-ffi-4.stderr
deleted file mode 100644
index da83276c72d..00000000000
--- a/src/test/ui/parser/variadic-ffi-4.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0743]: only foreign functions are allowed to be C-variadic
-  --> $DIR/variadic-ffi-4.rs:1:29
-   |
-LL | extern "C" fn foo(x: isize, ...) {
-   |                             ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0743`.
diff --git a/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs
new file mode 100644
index 00000000000..9eeee195e56
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.rs
@@ -0,0 +1,9 @@
+fn f1<'a>(x: u8, y: &'a ...) {}
+//~^ ERROR C-variadic type `...` may not be nested inside another type
+
+fn f2<'a>(x: u8, y: Vec<&'a ...>) {}
+//~^ ERROR C-variadic type `...` may not be nested inside another type
+
+fn main() {
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr
new file mode 100644
index 00000000000..8b9d676a45d
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-nested-syntactic-fail.stderr
@@ -0,0 +1,24 @@
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/variadic-ffi-nested-syntactic-fail.rs:1:25
+   |
+LL | fn f1<'a>(x: u8, y: &'a ...) {}
+   |                         ^^^
+
+error[E0743]: C-variadic type `...` may not be nested inside another type
+  --> $DIR/variadic-ffi-nested-syntactic-fail.rs:4:29
+   |
+LL | fn f2<'a>(x: u8, y: Vec<&'a ...>) {}
+   |                             ^^^
+
+error[E0308]: mismatched types
+  --> $DIR/variadic-ffi-nested-syntactic-fail.rs:8:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0743.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.rs b/src/test/ui/parser/variadic-ffi-semantic-restrictions.rs
new file mode 100644
index 00000000000..aa85f6d6b52
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.rs
@@ -0,0 +1,76 @@
+#![feature(c_variadic)]
+
+fn main() {}
+
+fn f1_1(x: isize, ...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+
+fn f1_2(...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR C-variadic function must be declared with at least one named argument
+
+extern "C" fn f2_1(x: isize, ...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+
+extern "C" fn f2_2(...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR C-variadic function must be declared with at least one named argument
+
+extern "C" fn f2_3(..., x: isize) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR `...` must be the last argument of a C-variadic function
+
+extern fn f3_1(x: isize, ...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+
+extern fn f3_2(...) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR C-variadic function must be declared with at least one named argument
+
+extern fn f3_3(..., x: isize) {}
+//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~| ERROR `...` must be the last argument of a C-variadic function
+
+extern {
+    fn e_f1(...);
+    //~^ ERROR C-variadic function must be declared with at least one named argument
+    fn e_f2(..., x: isize);
+    //~^ ERROR `...` must be the last argument of a C-variadic function
+}
+
+struct X;
+
+impl X {
+    fn i_f1(x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    fn i_f2(...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR C-variadic function must be declared with at least one named argument
+    fn i_f3(..., x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+    fn i_f4(..., x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+}
+
+trait T {
+    fn t_f1(x: isize, ...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    fn t_f2(x: isize, ...);
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    fn t_f3(...) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR C-variadic function must be declared with at least one named argument
+    fn t_f4(...);
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR C-variadic function must be declared with at least one named argument
+    fn t_f5(..., x: isize) {}
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+    fn t_f6(..., x: isize);
+    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~| ERROR `...` must be the last argument of a C-variadic function
+}
diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
new file mode 100644
index 00000000000..21992a29670
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -0,0 +1,206 @@
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19
+   |
+LL | fn f1_1(x: isize, ...) {}
+   |                   ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
+   |
+LL | fn f1_2(...) {}
+   |         ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
+   |
+LL | fn f1_2(...) {}
+   |         ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
+   |
+LL | extern "C" fn f2_1(x: isize, ...) {}
+   |                              ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
+   |
+LL | extern "C" fn f2_2(...) {}
+   |                    ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
+   |
+LL | extern "C" fn f2_2(...) {}
+   |                    ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
+   |
+LL | extern "C" fn f2_3(..., x: isize) {}
+   |                    ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
+   |
+LL | extern "C" fn f2_3(..., x: isize) {}
+   |                    ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26
+   |
+LL | extern fn f3_1(x: isize, ...) {}
+   |                          ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
+   |
+LL | extern fn f3_2(...) {}
+   |                ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
+   |
+LL | extern fn f3_2(...) {}
+   |                ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
+   |
+LL | extern fn f3_3(..., x: isize) {}
+   |                ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
+   |
+LL | extern fn f3_3(..., x: isize) {}
+   |                ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13
+   |
+LL |     fn e_f1(...);
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13
+   |
+LL |     fn e_f2(..., x: isize);
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23
+   |
+LL |     fn i_f1(x: isize, ...) {}
+   |                       ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
+   |
+LL |     fn i_f2(...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
+   |
+LL |     fn i_f2(...) {}
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
+   |
+LL |     fn i_f3(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
+   |
+LL |     fn i_f3(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28
+   |
+LL |     fn i_f3(..., x: isize, ...) {}
+   |                            ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
+   |
+LL |     fn i_f4(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
+   |
+LL |     fn i_f4(..., x: isize, ...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28
+   |
+LL |     fn i_f4(..., x: isize, ...) {}
+   |                            ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23
+   |
+LL |     fn t_f1(x: isize, ...) {}
+   |                       ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23
+   |
+LL |     fn t_f2(x: isize, ...);
+   |                       ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
+   |
+LL |     fn t_f3(...) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
+   |
+LL |     fn t_f3(...) {}
+   |             ^^^^
+
+error: C-variadic function must be declared with at least one named argument
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
+   |
+LL |     fn t_f4(...);
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
+   |
+LL |     fn t_f4(...);
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
+   |
+LL |     fn t_f5(..., x: isize) {}
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
+   |
+LL |     fn t_f5(..., x: isize) {}
+   |             ^^^^
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
+   |
+LL |     fn t_f6(..., x: isize);
+   |             ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+  --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
+   |
+LL |     fn t_f6(..., x: isize);
+   |             ^^^^
+
+error: aborting due to 34 previous errors
+
diff --git a/src/test/ui/parser/variadic-ffi-syntactic-pass.rs b/src/test/ui/parser/variadic-ffi-syntactic-pass.rs
new file mode 100644
index 00000000000..3875d6af137
--- /dev/null
+++ b/src/test/ui/parser/variadic-ffi-syntactic-pass.rs
@@ -0,0 +1,53 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn f1_1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+fn f1_2(...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2_1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2_2(...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2_3(..., x: isize) {}
+
+#[cfg(FALSE)]
+extern fn f3_1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+extern fn f3_2(...) {}
+
+#[cfg(FALSE)]
+extern fn f3_3(..., x: isize) {}
+
+#[cfg(FALSE)]
+extern {
+    fn e_f1(...);
+    fn e_f2(..., x: isize);
+}
+
+struct X;
+
+#[cfg(FALSE)]
+impl X {
+    fn i_f1(x: isize, ...) {}
+    fn i_f2(...) {}
+    fn i_f3(..., x: isize, ...) {}
+    fn i_f4(..., x: isize, ...) {}
+}
+
+#[cfg(FALSE)]
+trait T {
+    fn t_f1(x: isize, ...) {}
+    fn t_f2(x: isize, ...);
+    fn t_f3(...) {}
+    fn t_f4(...);
+    fn t_f5(..., x: isize) {}
+    fn t_f6(..., x: isize);
+}
diff --git a/src/test/ui/pattern/pattern-tyvar-2.rs b/src/test/ui/pattern/pattern-tyvar-2.rs
index 9fba9cb876a..4c6d515b86a 100644
--- a/src/test/ui/pattern/pattern-tyvar-2.rs
+++ b/src/test/ui/pattern/pattern-tyvar-2.rs
@@ -1,6 +1,6 @@
 enum Bar { T1((), Option<Vec<isize>>), T2, }
 
 fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } }
-//~^ ERROR binary operation `*` cannot be applied to
+//~^ ERROR cannot multiply `{integer}` to `std::vec::Vec<isize>`
 
 fn main() { }
diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr
index 7c6ae499cbb..bb3e61017d4 100644
--- a/src/test/ui/pattern/pattern-tyvar-2.stderr
+++ b/src/test/ui/pattern/pattern-tyvar-2.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `*` cannot be applied to type `std::vec::Vec<isize>`
+error[E0369]: cannot multiply `{integer}` to `std::vec::Vec<isize>`
   --> $DIR/pattern-tyvar-2.rs:3:71
    |
 LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } }
diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
index 792ab6f59a4..1b1096c977a 100644
--- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
+++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
@@ -9,8 +9,13 @@ LL |     match uninhab_ref() {
 error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
   --> $DIR/always-inhabited-union-ref.rs:27:11
    |
-LL |     match uninhab_union() {
-   |           ^^^^^^^^^^^^^^^
+LL | / pub union Foo {
+LL | |     foo: !,
+LL | | }
+   | |_- `Foo` defined here
+...
+LL |       match uninhab_union() {
+   |             ^^^^^^^^^^^^^^^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
new file mode 100644
index 00000000000..57b6b910ca1
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs
@@ -0,0 +1,93 @@
+#![feature(never_type)]
+#![feature(exhaustive_patterns)]
+#![deny(unreachable_patterns)]
+enum Foo {}
+
+struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
+union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
+    foo: (),
+}
+union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
+    foo: (),
+    bar: (),
+}
+enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+    Bar,
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
+    V1, V2, V3, V4, V5,
+}
+
+macro_rules! match_empty {
+    ($e:expr) => {
+        match $e {}
+    };
+}
+macro_rules! match_false {
+    ($e:expr) => {
+        match $e {
+            _ if false => {}
+        }
+    };
+}
+
+fn foo(x: Foo) {
+    match_empty!(x); // ok
+    match x {
+        _ => {}, //~ ERROR unreachable pattern
+    }
+    match x {
+        _ if false => {}, //~ ERROR unreachable pattern
+    }
+}
+
+fn main() {
+    match None::<!> {
+        None => {}
+        Some(_) => {} //~ ERROR unreachable pattern
+    }
+    match None::<Foo> {
+        None => {}
+        Some(_) => {} //~ ERROR unreachable pattern
+    }
+
+    match_empty!(0u8);
+    //~^ ERROR type `u8` is non-empty
+    match_empty!(NonEmptyStruct(true));
+    //~^ ERROR type `NonEmptyStruct` is non-empty
+    match_empty!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion1` is non-empty
+    match_empty!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion2` is non-empty
+    match_empty!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_empty!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_empty!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+    match_false!(0u8);
+    //~^ ERROR `_` not covered
+    match_false!(NonEmptyStruct(true));
+    //~^ ERROR `NonEmptyStruct(_)` not covered
+    match_false!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
+    match_false!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
+    match_false!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_false!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_false!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
new file mode 100644
index 00000000000..f242ecf2dae
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr
@@ -0,0 +1,223 @@
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:47:9
+   |
+LL |         _ => {},
+   |         ^
+   |
+note: lint level defined here
+  --> $DIR/match-empty-exhaustive_patterns.rs:3:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:50:9
+   |
+LL |         _ if false => {},
+   |         ^
+
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:57:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/match-empty-exhaustive_patterns.rs:61:9
+   |
+LL |         Some(_) => {}
+   |         ^^^^^^^
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:64:18
+   |
+LL |     match_empty!(0u8);
+   |                  ^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:66:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_empty!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:68:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_empty!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+  --> $DIR/match-empty-exhaustive_patterns.rs:70:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_empty!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:72:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_empty!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:74:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_empty!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:76:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_empty!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:79:18
+   |
+LL |     match_false!(0u8);
+   |                  ^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:81:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_false!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:83:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_false!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:85:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_false!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:87:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_false!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:89:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_false!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty-exhaustive_patterns.rs:91:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_false!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs
new file mode 100644
index 00000000000..f7577125d8a
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty.rs
@@ -0,0 +1,92 @@
+#![feature(never_type)]
+#![deny(unreachable_patterns)]
+enum Foo {}
+
+struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
+union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
+    foo: (),
+}
+union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
+    foo: (),
+    bar: (),
+}
+enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
+    Foo(bool),
+    //~^ not covered
+    //~| not covered
+    Bar,
+    //~^ not covered
+    //~| not covered
+}
+enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
+    V1, V2, V3, V4, V5,
+}
+
+macro_rules! match_empty {
+    ($e:expr) => {
+        match $e {}
+    };
+}
+macro_rules! match_false {
+    ($e:expr) => {
+        match $e {
+            _ if false => {}
+        }
+    };
+}
+
+fn foo(x: Foo) {
+    match_empty!(x); // ok
+    match_false!(x); // Not detected as unreachable nor exhaustive.
+    //~^ ERROR non-exhaustive patterns: `_` not covered
+    match x {
+        _ => {}, // Not detected as unreachable, see #55123.
+    }
+}
+
+fn main() {
+    // `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
+    match None::<!> {
+        None => {}
+        Some(_) => {}
+    }
+    match None::<Foo> {
+        None => {}
+        Some(_) => {}
+    }
+
+    match_empty!(0u8);
+    //~^ ERROR type `u8` is non-empty
+    match_empty!(NonEmptyStruct(true));
+    //~^ ERROR type `NonEmptyStruct` is non-empty
+    match_empty!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion1` is non-empty
+    match_empty!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR type `NonEmptyUnion2` is non-empty
+    match_empty!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_empty!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_empty!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+
+    match_false!(0u8);
+    //~^ ERROR `_` not covered
+    match_false!(NonEmptyStruct(true));
+    //~^ ERROR `NonEmptyStruct(_)` not covered
+    match_false!((NonEmptyUnion1 { foo: () }));
+    //~^ ERROR `NonEmptyUnion1 { .. }` not covered
+    match_false!((NonEmptyUnion2 { foo: () }));
+    //~^ ERROR `NonEmptyUnion2 { .. }` not covered
+    match_false!(NonEmptyEnum1::Foo(true));
+    //~^ ERROR `Foo(_)` not covered
+    match_false!(NonEmptyEnum2::Foo(true));
+    //~^ ERROR `Foo(_)` and `Bar` not covered
+    match_false!(NonEmptyEnum5::V1);
+    //~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
+}
diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/match-empty.stderr
new file mode 100644
index 00000000000..72e3fc0a167
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/match-empty.stderr
@@ -0,0 +1,204 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/match-empty.rs:45:18
+   |
+LL | enum Foo {}
+   | ----------- `Foo` defined here
+...
+LL |     match_false!(x); // Not detected as unreachable nor exhaustive.
+   |                  ^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `u8` is non-empty
+  --> $DIR/match-empty.rs:63:18
+   |
+LL |     match_empty!(0u8);
+   |                  ^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
+  --> $DIR/match-empty.rs:65:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_empty!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
+  --> $DIR/match-empty.rs:67:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_empty!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
+  --> $DIR/match-empty.rs:69:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_empty!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty.rs:71:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_empty!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty.rs:73:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_empty!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty.rs:75:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_empty!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/match-empty.rs:78:18
+   |
+LL |     match_false!(0u8);
+   |                  ^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
+  --> $DIR/match-empty.rs:80:18
+   |
+LL | struct NonEmptyStruct(bool);
+   | ---------------------------- `NonEmptyStruct` defined here
+...
+LL |     match_false!(NonEmptyStruct(true));
+   |                  ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
+  --> $DIR/match-empty.rs:82:18
+   |
+LL | / union NonEmptyUnion1 {
+LL | |     foo: (),
+LL | | }
+   | |_- `NonEmptyUnion1` defined here
+...
+LL |       match_false!((NonEmptyUnion1 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
+  --> $DIR/match-empty.rs:84:18
+   |
+LL | / union NonEmptyUnion2 {
+LL | |     foo: (),
+LL | |     bar: (),
+LL | | }
+   | |_- `NonEmptyUnion2` defined here
+...
+LL |       match_false!((NonEmptyUnion2 { foo: () }));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+  --> $DIR/match-empty.rs:86:18
+   |
+LL | / enum NonEmptyEnum1 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum1` defined here
+...
+LL |       match_false!(NonEmptyEnum1::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+  --> $DIR/match-empty.rs:88:18
+   |
+LL | / enum NonEmptyEnum2 {
+LL | |     Foo(bool),
+   | |     --- not covered
+LL | |
+LL | |
+LL | |     Bar,
+   | |     --- not covered
+LL | |
+LL | |
+LL | | }
+   | |_- `NonEmptyEnum2` defined here
+...
+LL |       match_false!(NonEmptyEnum2::Foo(true));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+  --> $DIR/match-empty.rs:90:18
+   |
+LL | / enum NonEmptyEnum5 {
+LL | |     V1, V2, V3, V4, V5,
+LL | | }
+   | |_- `NonEmptyEnum5` defined here
+...
+LL |       match_false!(NonEmptyEnum5::V1);
+   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.rs b/src/test/ui/pattern/usefulness/match-privately-empty.rs
index ea608651387..315eb03d165 100644
--- a/src/test/ui/pattern/usefulness/match-privately-empty.rs
+++ b/src/test/ui/pattern/usefulness/match-privately-empty.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![feature(exhaustive_patterns)]
 
 mod private {
diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr
index 66d0d958774..f79d180a1b8 100644
--- a/src/test/ui/pattern/usefulness/match-privately-empty.stderr
+++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
-  --> $DIR/match-privately-empty.rs:12:11
+  --> $DIR/match-privately-empty.rs:13:11
    |
 LL |     match private::DATA {
    |           ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs
index 3a2ca19d8e0..ae4e492456a 100644
--- a/src/test/ui/print_type_sizes/uninhabited.rs
+++ b/src/test/ui/print_type_sizes/uninhabited.rs
@@ -4,6 +4,7 @@
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
 
+#![feature(never_type)]
 #![feature(start)]
 
 #[start]
diff --git a/src/test/ui/question-mark-type-infer.rs b/src/test/ui/question-mark-type-infer.rs
index 95ee01a70ce..2ef8618192f 100644
--- a/src/test/ui/question-mark-type-infer.rs
+++ b/src/test/ui/question-mark-type-infer.rs
@@ -9,7 +9,7 @@ fn f(x: &i32) -> Result<i32, ()> {
 
 fn g() -> Result<Vec<i32>, ()> {
     let l = [1, 2, 3, 4];
-    l.iter().map(f).collect()? //~ ERROR type annotations needed: cannot resolve
+    l.iter().map(f).collect()? //~ ERROR type annotations needed
 }
 
 fn main() {
diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr
index 53a170e7d43..7911701946c 100644
--- a/src/test/ui/question-mark-type-infer.stderr
+++ b/src/test/ui/question-mark-type-infer.stderr
@@ -1,8 +1,13 @@
-error[E0284]: type annotations needed: cannot resolve `<_ as std::ops::Try>::Ok == _`
-  --> $DIR/question-mark-type-infer.rs:12:5
+error[E0284]: type annotations needed
+  --> $DIR/question-mark-type-infer.rs:12:21
    |
 LL |     l.iter().map(f).collect()?
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     ^^^^^^^
+   |                     |
+   |                     cannot infer type
+   |                     help: consider specifying the type argument in the method call: `collect::<B>`
+   |
+   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/raw-ref-op/raw-ref-op.rs b/src/test/ui/raw-ref-op/raw-ref-op.rs
index de847909eb3..0c6e23a00d5 100644
--- a/src/test/ui/raw-ref-op/raw-ref-op.rs
+++ b/src/test/ui/raw-ref-op/raw-ref-op.rs
@@ -1,11 +1,11 @@
-// FIXME(#64490): make this run-pass
+// run-pass
 
 #![feature(raw_ref_op)]
 
 fn main() {
     let mut x = 123;
-    let c_p = &raw const x;                     //~ ERROR not yet implemented
-    let m_p = &raw mut x;                       //~ ERROR not yet implemented
+    let c_p = &raw const x;
+    let m_p = &raw mut x;
     let i_r = &x;
     assert!(c_p == i_r);
     assert!(c_p == m_p);
diff --git a/src/test/ui/raw-ref-op/raw-ref-op.stderr b/src/test/ui/raw-ref-op/raw-ref-op.stderr
deleted file mode 100644
index 04c59c95fca..00000000000
--- a/src/test/ui/raw-ref-op/raw-ref-op.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-op.rs:7:15
-   |
-LL |     let c_p = &raw const x;
-   |               ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-op.rs:8:15
-   |
-LL |     let m_p = &raw mut x;
-   |               ^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs b/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
index d251586de55..a814003aebf 100644
--- a/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
+++ b/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
@@ -1,4 +1,4 @@
-// FIXME(#64490) This should be check-pass
+// check-pass
 // Check that taking the address of a place that contains a dereference is
 // allowed.
 #![feature(raw_ref_op, type_ascription)]
@@ -10,15 +10,15 @@ const SLICE_REF: &[i32] = &[5, 6];
 
 fn main() {
     // These are all OK, we're not taking the address of the temporary
-    let deref_ref = &raw const *PAIR_REF;                       //~ ERROR not yet implemented
-    let field_deref_ref = &raw const PAIR_REF.0;                //~ ERROR not yet implemented
-    let deref_ref = &raw const *ARRAY_REF;                      //~ ERROR not yet implemented
-    let index_deref_ref = &raw const ARRAY_REF[0];              //~ ERROR not yet implemented
-    let deref_ref = &raw const *SLICE_REF;                      //~ ERROR not yet implemented
-    let index_deref_ref = &raw const SLICE_REF[1];              //~ ERROR not yet implemented
+    let deref_ref = &raw const *PAIR_REF;
+    let field_deref_ref = &raw const PAIR_REF.0;
+    let deref_ref = &raw const *ARRAY_REF;
+    let index_deref_ref = &raw const ARRAY_REF[0];
+    let deref_ref = &raw const *SLICE_REF;
+    let index_deref_ref = &raw const SLICE_REF[1];
 
     let x = 0;
-    let ascribe_ref = &raw const (x: i32);                      //~ ERROR not yet implemented
-    let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]);      //~ ERROR not yet implemented
-    let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32);   //~ ERROR not yet implemented
+    let ascribe_ref = &raw const (x: i32);
+    let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]);
+    let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32);
 }
diff --git a/src/test/ui/raw-ref-op/raw-ref-temp-deref.stderr b/src/test/ui/raw-ref-op/raw-ref-temp-deref.stderr
deleted file mode 100644
index b0bfc74903b..00000000000
--- a/src/test/ui/raw-ref-op/raw-ref-temp-deref.stderr
+++ /dev/null
@@ -1,74 +0,0 @@
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:13:21
-   |
-LL |     let deref_ref = &raw const *PAIR_REF;
-   |                     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:14:27
-   |
-LL |     let field_deref_ref = &raw const PAIR_REF.0;
-   |                           ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:15:21
-   |
-LL |     let deref_ref = &raw const *ARRAY_REF;
-   |                     ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:16:27
-   |
-LL |     let index_deref_ref = &raw const ARRAY_REF[0];
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:17:21
-   |
-LL |     let deref_ref = &raw const *SLICE_REF;
-   |                     ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:18:27
-   |
-LL |     let index_deref_ref = &raw const SLICE_REF[1];
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:21:23
-   |
-LL |     let ascribe_ref = &raw const (x: i32);
-   |                       ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:22:25
-   |
-LL |     let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]);
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/raw-ref-temp-deref.rs:23:31
-   |
-LL |     let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: aborting due to 9 previous errors
-
diff --git a/src/test/ui/raw-ref-op/raw-ref-temp.rs b/src/test/ui/raw-ref-op/raw-ref-temp.rs
index ac2445f049c..32df56468da 100644
--- a/src/test/ui/raw-ref-op/raw-ref-temp.rs
+++ b/src/test/ui/raw-ref-op/raw-ref-temp.rs
@@ -1,6 +1,8 @@
 // Ensure that we don't allow taking the address of temporary values
 #![feature(raw_ref_op, type_ascription)]
 
+const FOUR: u64 = 4;
+
 const PAIR: (i32, i64) = (1, 2);
 
 const ARRAY: [i32; 2] = [1, 2];
@@ -8,8 +10,8 @@ const ARRAY: [i32; 2] = [1, 2];
 fn main() {
     let ref_expr = &raw const 2;                        //~ ERROR cannot take address
     let mut_ref_expr = &raw mut 3;                      //~ ERROR cannot take address
-    let ref_const = &raw const 4;                       //~ ERROR cannot take address
-    let mut_ref_const = &raw mut 5;                     //~ ERROR cannot take address
+    let ref_const = &raw const FOUR;                    //~ ERROR cannot take address
+    let mut_ref_const = &raw mut FOUR;                  //~ ERROR cannot take address
 
     let field_ref_expr = &raw const (1, 2).0;           //~ ERROR cannot take address
     let mut_field_ref_expr = &raw mut (1, 2).0;         //~ ERROR cannot take address
diff --git a/src/test/ui/raw-ref-op/raw-ref-temp.stderr b/src/test/ui/raw-ref-op/raw-ref-temp.stderr
index de070733735..80dea76d595 100644
--- a/src/test/ui/raw-ref-op/raw-ref-temp.stderr
+++ b/src/test/ui/raw-ref-op/raw-ref-temp.stderr
@@ -1,95 +1,95 @@
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:9:31
+  --> $DIR/raw-ref-temp.rs:11:31
    |
 LL |     let ref_expr = &raw const 2;
    |                               ^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:10:33
+  --> $DIR/raw-ref-temp.rs:12:33
    |
 LL |     let mut_ref_expr = &raw mut 3;
    |                                 ^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:11:32
+  --> $DIR/raw-ref-temp.rs:13:32
    |
-LL |     let ref_const = &raw const 4;
-   |                                ^ temporary value
+LL |     let ref_const = &raw const FOUR;
+   |                                ^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:12:34
+  --> $DIR/raw-ref-temp.rs:14:34
    |
-LL |     let mut_ref_const = &raw mut 5;
-   |                                  ^ temporary value
+LL |     let mut_ref_const = &raw mut FOUR;
+   |                                  ^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:14:37
+  --> $DIR/raw-ref-temp.rs:16:37
    |
 LL |     let field_ref_expr = &raw const (1, 2).0;
    |                                     ^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:15:39
+  --> $DIR/raw-ref-temp.rs:17:39
    |
 LL |     let mut_field_ref_expr = &raw mut (1, 2).0;
    |                                       ^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:16:32
+  --> $DIR/raw-ref-temp.rs:18:32
    |
 LL |     let field_ref = &raw const PAIR.0;
    |                                ^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:17:34
+  --> $DIR/raw-ref-temp.rs:19:34
    |
 LL |     let mut_field_ref = &raw mut PAIR.0;
    |                                  ^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:19:37
+  --> $DIR/raw-ref-temp.rs:21:37
    |
 LL |     let index_ref_expr = &raw const [1, 2][0];
    |                                     ^^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:20:39
+  --> $DIR/raw-ref-temp.rs:22:39
    |
 LL |     let mut_index_ref_expr = &raw mut [1, 2][0];
    |                                       ^^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:21:32
+  --> $DIR/raw-ref-temp.rs:23:32
    |
 LL |     let index_ref = &raw const ARRAY[0];
    |                                ^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:22:34
+  --> $DIR/raw-ref-temp.rs:24:34
    |
 LL |     let mut_index_ref = &raw mut ARRAY[1];
    |                                  ^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:24:34
+  --> $DIR/raw-ref-temp.rs:26:34
    |
 LL |     let ref_ascribe = &raw const (2: i32);
    |                                  ^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:25:36
+  --> $DIR/raw-ref-temp.rs:27:36
    |
 LL |     let mut_ref_ascribe = &raw mut (3: i32);
    |                                    ^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:27:40
+  --> $DIR/raw-ref-temp.rs:29:40
    |
 LL |     let ascribe_field_ref = &raw const (PAIR.0: i32);
    |                                        ^^^^^^^^^^^^^ temporary value
 
 error[E0745]: cannot take address of a temporary
-  --> $DIR/raw-ref-temp.rs:28:38
+  --> $DIR/raw-ref-temp.rs:30:38
    |
 LL |     let ascribe_index_ref = &raw mut (ARRAY[0]: i32);
    |                                      ^^^^^^^^^^^^^^^ temporary value
diff --git a/src/test/ui/raw-ref-op/unusual_locations.rs b/src/test/ui/raw-ref-op/unusual_locations.rs
index f0a6bcce2ac..6bf37408a8b 100644
--- a/src/test/ui/raw-ref-op/unusual_locations.rs
+++ b/src/test/ui/raw-ref-op/unusual_locations.rs
@@ -1,25 +1,22 @@
-// FIXME(#64490): make this check-pass
+// check-pass
 
 #![feature(raw_ref_op)]
 
-const USES_PTR: () = { let u = (); &raw const u; };         //~ ERROR not yet implemented
-static ALSO_USES_PTR: () = { let u = (); &raw const u; };   //~ ERROR not yet implemented
+const USES_PTR: () = { let u = (); &raw const u; };
+static ALSO_USES_PTR: () = { let u = (); &raw const u; };
 
 fn main() {
-    #[cfg(FALSE)]
-    {
-        let x: [i32; { let u = 2; let x = &raw const u; 4 }]
-            = [2; { let v = 3; let y = &raw const v; 4 }];
-        let mut one = 1;
-        let two = 2;
-        if &raw const one == &raw mut one {
-            match &raw const two {
-                _ => {}
-            }
+    let x: [i32; { let u = 2; let x = &raw const u; 4 }]
+        = [2; { let v = 3; let y = &raw const v; 4 }];
+    let mut one = 1;
+    let two = 2;
+    if &raw const one == &raw mut one {
+        match &raw const two {
+            _ => {}
         }
-        let three = 3;
-        let mut four = 4;
-        println!("{:p}", &raw const three);
-        unsafe { &raw mut four; }
     }
+    let three = 3;
+    let mut four = 4;
+    println!("{:p}", &raw const three);
+    unsafe { &raw mut four; }
 }
diff --git a/src/test/ui/raw-ref-op/unusual_locations.stderr b/src/test/ui/raw-ref-op/unusual_locations.stderr
deleted file mode 100644
index 3fae5db3d51..00000000000
--- a/src/test/ui/raw-ref-op/unusual_locations.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: raw borrows are not yet implemented
-  --> $DIR/unusual_locations.rs:5:36
-   |
-LL | const USES_PTR: () = { let u = (); &raw const u; };
-   |                                    ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: raw borrows are not yet implemented
-  --> $DIR/unusual_locations.rs:6:42
-   |
-LL | static ALSO_USES_PTR: () = { let u = (); &raw const u; };
-   |                                          ^^^^^^^^^^^^
-   |
-   = note: for more information, see https://github.com/rust-lang/rust/issues/64490
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs
index 640c2a2cf8f..b45e5daf42c 100644
--- a/src/test/ui/reachable/expr_add.rs
+++ b/src/test/ui/reachable/expr_add.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![allow(unused_variables)]
 #![deny(unreachable_code)]
 
diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr
index 11c41fdc394..880dea1cc35 100644
--- a/src/test/ui/reachable/expr_add.stderr
+++ b/src/test/ui/reachable/expr_add.stderr
@@ -1,5 +1,5 @@
 error: unreachable expression
-  --> $DIR/expr_add.rs:16:13
+  --> $DIR/expr_add.rs:17:13
    |
 LL |     let x = Foo + return;
    |             ^^^^^^------
@@ -8,7 +8,7 @@ LL |     let x = Foo + return;
    |             unreachable expression
    |
 note: lint level defined here
-  --> $DIR/expr_add.rs:2:9
+  --> $DIR/expr_add.rs:3:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs
index 3914fb32432..e547f75e269 100644
--- a/src/test/ui/reachable/expr_assign.rs
+++ b/src/test/ui/reachable/expr_assign.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
 #![allow(dead_code)]
diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr
index 90aec15e3be..3004da04063 100644
--- a/src/test/ui/reachable/expr_assign.stderr
+++ b/src/test/ui/reachable/expr_assign.stderr
@@ -1,5 +1,5 @@
 error: unreachable expression
-  --> $DIR/expr_assign.rs:9:5
+  --> $DIR/expr_assign.rs:10:5
    |
 LL |     x = return;
    |     ^^^^------
@@ -8,13 +8,13 @@ LL |     x = return;
    |     unreachable expression
    |
 note: lint level defined here
-  --> $DIR/expr_assign.rs:4:9
+  --> $DIR/expr_assign.rs:5:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unreachable expression
-  --> $DIR/expr_assign.rs:19:14
+  --> $DIR/expr_assign.rs:20:14
    |
 LL |         *p = return;
    |         --   ^^^^^^ unreachable expression
@@ -22,7 +22,7 @@ LL |         *p = return;
    |         any code following this expression is unreachable
 
 error: unreachable expression
-  --> $DIR/expr_assign.rs:25:15
+  --> $DIR/expr_assign.rs:26:15
    |
 LL |     *{return; &mut i} = 22;
    |       ------  ^^^^^^ unreachable expression
diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs
index ce1a94e3c4a..1eaa96c3ce7 100644
--- a/src/test/ui/reachable/expr_call.rs
+++ b/src/test/ui/reachable/expr_call.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
 #![allow(dead_code)]
diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr
index 613fc31b861..ae8b4dd87b5 100644
--- a/src/test/ui/reachable/expr_call.stderr
+++ b/src/test/ui/reachable/expr_call.stderr
@@ -1,5 +1,5 @@
 error: unreachable expression
-  --> $DIR/expr_call.rs:12:17
+  --> $DIR/expr_call.rs:13:17
    |
 LL |     foo(return, 22);
    |         ------  ^^ unreachable expression
@@ -7,13 +7,13 @@ LL |     foo(return, 22);
    |         any code following this expression is unreachable
    |
 note: lint level defined here
-  --> $DIR/expr_call.rs:4:9
+  --> $DIR/expr_call.rs:5:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unreachable call
-  --> $DIR/expr_call.rs:17:5
+  --> $DIR/expr_call.rs:18:5
    |
 LL |     bar(return);
    |     ^^^ ------ any code following this expression is unreachable
diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs
index 76a7306b9d9..f53bcb97e69 100644
--- a/src/test/ui/reachable/expr_cast.rs
+++ b/src/test/ui/reachable/expr_cast.rs
@@ -2,7 +2,7 @@
 #![allow(unused_assignments)]
 #![allow(dead_code)]
 #![deny(unreachable_code)]
-#![feature(type_ascription)]
+#![feature(never_type, type_ascription)]
 
 fn a() {
     // the cast is unreachable:
diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs
index e74a7daec88..d917df05b3c 100644
--- a/src/test/ui/reachable/expr_method.rs
+++ b/src/test/ui/reachable/expr_method.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
 #![allow(dead_code)]
diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr
index 7475cf7a365..82a0745f062 100644
--- a/src/test/ui/reachable/expr_method.stderr
+++ b/src/test/ui/reachable/expr_method.stderr
@@ -1,5 +1,5 @@
 error: unreachable expression
-  --> $DIR/expr_method.rs:15:21
+  --> $DIR/expr_method.rs:16:21
    |
 LL |     Foo.foo(return, 22);
    |             ------  ^^ unreachable expression
@@ -7,13 +7,13 @@ LL |     Foo.foo(return, 22);
    |             any code following this expression is unreachable
    |
 note: lint level defined here
-  --> $DIR/expr_method.rs:4:9
+  --> $DIR/expr_method.rs:5:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unreachable call
-  --> $DIR/expr_method.rs:20:9
+  --> $DIR/expr_method.rs:21:9
    |
 LL |     Foo.bar(return);
    |         ^^^ ------ any code following this expression is unreachable
diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs
index ff647bda0e8..8d32397b542 100644
--- a/src/test/ui/reachable/expr_type.rs
+++ b/src/test/ui/reachable/expr_type.rs
@@ -2,7 +2,7 @@
 #![allow(unused_assignments)]
 #![allow(dead_code)]
 #![deny(unreachable_code)]
-#![feature(type_ascription)]
+#![feature(never_type, type_ascription)]
 
 fn a() {
     // the cast is unreachable:
diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs
index 6f221c360cb..e229d22ebc7 100644
--- a/src/test/ui/reachable/expr_unary.rs
+++ b/src/test/ui/reachable/expr_unary.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
 #![allow(dead_code)]
diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr
index a576f920923..f5c3564217b 100644
--- a/src/test/ui/reachable/expr_unary.stderr
+++ b/src/test/ui/reachable/expr_unary.stderr
@@ -1,11 +1,11 @@
 error[E0600]: cannot apply unary operator `!` to type `!`
-  --> $DIR/expr_unary.rs:7:16
+  --> $DIR/expr_unary.rs:8:16
    |
 LL |     let x: ! = ! { return; };
    |                ^^^^^^^^^^^^^ cannot apply unary operator `!`
 
 error: unreachable expression
-  --> $DIR/expr_unary.rs:7:16
+  --> $DIR/expr_unary.rs:8:16
    |
 LL |     let x: ! = ! { return; };
    |                ^^^^------^^^
@@ -14,7 +14,7 @@ LL |     let x: ! = ! { return; };
    |                unreachable expression
    |
 note: lint level defined here
-  --> $DIR/expr_unary.rs:4:9
+  --> $DIR/expr_unary.rs:5:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/reachable/unreachable-loop-patterns.rs b/src/test/ui/reachable/unreachable-loop-patterns.rs
index c8ff5653911..4de29c3c3d7 100644
--- a/src/test/ui/reachable/unreachable-loop-patterns.rs
+++ b/src/test/ui/reachable/unreachable-loop-patterns.rs
@@ -1,4 +1,4 @@
-#![feature(never_type_fallback)]
+#![feature(never_type, never_type_fallback)]
 #![feature(exhaustive_patterns)]
 
 #![allow(unreachable_code)]
diff --git a/src/test/ui/reachable/unreachable-try-pattern.rs b/src/test/ui/reachable/unreachable-try-pattern.rs
index e2d89e93a2a..23360e73f4a 100644
--- a/src/test/ui/reachable/unreachable-try-pattern.rs
+++ b/src/test/ui/reachable/unreachable-try-pattern.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(exhaustive_patterns)]
+#![feature(never_type, exhaustive_patterns)]
 #![warn(unreachable_code)]
 #![warn(unreachable_patterns)]
 
diff --git a/src/test/ui/reachable/unwarned-match-on-never.rs b/src/test/ui/reachable/unwarned-match-on-never.rs
index c38ea6ab9ad..71f8fe3a783 100644
--- a/src/test/ui/reachable/unwarned-match-on-never.rs
+++ b/src/test/ui/reachable/unwarned-match-on-never.rs
@@ -1,6 +1,8 @@
 #![deny(unreachable_code)]
 #![allow(dead_code)]
 
+#![feature(never_type)]
+
 fn foo(x: !) -> bool {
     // Explicit matches on the never type are unwarned.
     match x {}
diff --git a/src/test/ui/reachable/unwarned-match-on-never.stderr b/src/test/ui/reachable/unwarned-match-on-never.stderr
index 6710fcb777f..6b2fb4a33c1 100644
--- a/src/test/ui/reachable/unwarned-match-on-never.stderr
+++ b/src/test/ui/reachable/unwarned-match-on-never.stderr
@@ -1,5 +1,5 @@
 error: unreachable expression
-  --> $DIR/unwarned-match-on-never.rs:8:5
+  --> $DIR/unwarned-match-on-never.rs:10:5
    |
 LL |     match x {}
    |           - any code following this expression is unreachable
@@ -14,7 +14,7 @@ LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unreachable arm
-  --> $DIR/unwarned-match-on-never.rs:13:15
+  --> $DIR/unwarned-match-on-never.rs:15:15
    |
 LL |     match (return) {
    |           -------- any code following this expression is unreachable
@@ -22,7 +22,7 @@ LL |         () => ()
    |               ^^ unreachable arm
 
 error: unreachable expression
-  --> $DIR/unwarned-match-on-never.rs:19:5
+  --> $DIR/unwarned-match-on-never.rs:21:5
    |
 LL |       return;
    |       ------ any code following this expression is unreachable
diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
index bbc25d40256..8516bafef9b 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/enums.rs
@@ -6,3 +6,6 @@ pub enum NonExhaustiveEnum {
     Tuple(u32),
     Struct { field: u32 }
 }
+
+#[non_exhaustive]
+pub enum EmptyNonExhaustiveEnum {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
index 7423a970e2e..802f20b4bed 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs
@@ -1,7 +1,14 @@
 // aux-build:enums.rs
 extern crate enums;
 
-use enums::NonExhaustiveEnum;
+use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum};
+
+fn empty(x: EmptyNonExhaustiveEnum) {
+    match x {} //~ ERROR type `enums::EmptyNonExhaustiveEnum` is non-empty
+    match x {
+        _ => {}, // ok
+    }
+}
 
 fn main() {
     let enum_unit = NonExhaustiveEnum::Unit;
@@ -13,6 +20,9 @@ fn main() {
         NonExhaustiveEnum::Struct { .. } => "third"
     };
 
+    match enum_unit {};
+    //~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
+
     // Everything below this is expected to compile successfully.
 
     let enum_unit = NonExhaustiveEnum::Unit;
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
index b5c1a4ebba4..a2bdcbaa447 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr
@@ -1,11 +1,27 @@
+error[E0004]: non-exhaustive patterns: type `enums::EmptyNonExhaustiveEnum` is non-empty
+  --> $DIR/enum.rs:7:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
 error[E0004]: non-exhaustive patterns: `_` not covered
-  --> $DIR/enum.rs:9:11
+  --> $DIR/enum.rs:16:11
    |
 LL |     match enum_unit {
    |           ^^^^^^^^^ pattern `_` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error: aborting due to previous error
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/enum.rs:23:11
+   |
+LL |     match enum_unit {};
+   |           ^^^^^^^^^ pattern `_` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
new file mode 100644
index 00000000000..afd6d996c15
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
@@ -0,0 +1,37 @@
+#![deny(unreachable_patterns)]
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {
+    Unit,
+    //~^ not covered
+    Tuple(u32),
+    //~^ not covered
+    Struct { field: u32 }
+    //~^ not covered
+}
+
+pub enum NormalEnum {
+    Unit,
+    //~^ not covered
+    Tuple(u32),
+    //~^ not covered
+    Struct { field: u32 }
+    //~^ not covered
+}
+
+#[non_exhaustive]
+pub enum EmptyNonExhaustiveEnum {}
+
+fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) {
+    match x {}
+    match x {
+        _ => {} // not detected as unreachable
+    }
+}
+
+fn main() {
+    match NonExhaustiveEnum::Unit {}
+    //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+    match NormalEnum::Unit {}
+    //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
new file mode 100644
index 00000000000..a99a690bc9e
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
@@ -0,0 +1,45 @@
+error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/enum_same_crate_empty_match.rs:33:11
+   |
+LL | / pub enum NonExhaustiveEnum {
+LL | |     Unit,
+   | |     ---- not covered
+LL | |
+LL | |     Tuple(u32),
+   | |     ----- not covered
+LL | |
+LL | |     Struct { field: u32 }
+   | |     ------ not covered
+LL | |
+LL | | }
+   | |_- `NonExhaustiveEnum` defined here
+...
+LL |       match NonExhaustiveEnum::Unit {}
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/enum_same_crate_empty_match.rs:35:11
+   |
+LL | / pub enum NormalEnum {
+LL | |     Unit,
+   | |     ---- not covered
+LL | |
+LL | |     Tuple(u32),
+   | |     ----- not covered
+LL | |
+LL | |     Struct { field: u32 }
+   | |     ------ not covered
+LL | |
+LL | | }
+   | |_- `NormalEnum` defined here
+...
+LL |       match NormalEnum::Unit {}
+   |             ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
index e074183a049..a2735d4cbfb 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
@@ -1,4 +1,5 @@
 #![crate_type = "rlib"]
+#![feature(never_type)]
 
 #[non_exhaustive]
 pub enum UninhabitedEnum {
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
index 5684ee6b7bf..80b9dc4c1c3 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
@@ -1,4 +1,5 @@
 // aux-build:uninhabited.rs
+#![feature(never_type)]
 
 extern crate uninhabited;
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
index d50e5f6b795..d2d319f50c7 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/coercions.rs:22:5
+  --> $DIR/coercions.rs:23:5
    |
 LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
    |                                                                - expected `A` because of return type
@@ -7,7 +7,7 @@ LL |     x
    |     ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum`
 
 error[E0308]: mismatched types
-  --> $DIR/coercions.rs:26:5
+  --> $DIR/coercions.rs:27:5
    |
 LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
    |                                                                               - expected `A` because of return type
@@ -15,7 +15,7 @@ LL |     x
    |     ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct`
 
 error[E0308]: mismatched types
-  --> $DIR/coercions.rs:30:5
+  --> $DIR/coercions.rs:31:5
    |
 LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
    |                                                                    - expected `A` because of return type
@@ -23,7 +23,7 @@ LL |     x
    |     ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct`
 
 error[E0308]: mismatched types
-  --> $DIR/coercions.rs:34:5
+  --> $DIR/coercions.rs:35:5
    |
 LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
    |                                                                                  - expected `A` because of return type
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs
index c3c0ce650d7..6b911dd989c 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 #[non_exhaustive]
 pub enum UninhabitedEnum {
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr
index 16a62a99249..fd2c56974bd 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/coercions_same_crate.rs:28:5
+  --> $DIR/coercions_same_crate.rs:30:5
    |
 LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
    |                                                                - expected `A` because of return type
@@ -7,7 +7,7 @@ LL |     x
    |     ^ expected struct `A`, found enum `UninhabitedEnum`
 
 error[E0308]: mismatched types
-  --> $DIR/coercions_same_crate.rs:32:5
+  --> $DIR/coercions_same_crate.rs:34:5
    |
 LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
    |                                                                               - expected `A` because of return type
@@ -15,7 +15,7 @@ LL |     x
    |     ^ expected struct `A`, found struct `UninhabitedTupleStruct`
 
 error[E0308]: mismatched types
-  --> $DIR/coercions_same_crate.rs:36:5
+  --> $DIR/coercions_same_crate.rs:38:5
    |
 LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
    |                                                                    - expected `A` because of return type
@@ -23,7 +23,7 @@ LL |     x
    |     ^ expected struct `A`, found struct `UninhabitedStruct`
 
 error[E0308]: mismatched types
-  --> $DIR/coercions_same_crate.rs:40:5
+  --> $DIR/coercions_same_crate.rs:42:5
    |
 LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
    |                                                                                  - expected `A` because of return type
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs
index 511b6b1bf8f..98a7fdbc504 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs
@@ -1,4 +1,5 @@
 // aux-build:uninhabited.rs
+#![feature(never_type)]
 
 extern crate uninhabited;
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
index b903e9b288e..abca542373f 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -1,29 +1,29 @@
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled
-  --> $DIR/indirect_match.rs:18:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty
+  --> $DIR/indirect_match.rs:19:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled
-  --> $DIR/indirect_match.rs:22:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty
+  --> $DIR/indirect_match.rs:23:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled
-  --> $DIR/indirect_match.rs:26:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty
+  --> $DIR/indirect_match.rs:27:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled
-  --> $DIR/indirect_match.rs:32:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty
+  --> $DIR/indirect_match.rs:33:11
    |
 LL |     match x {}
    |           ^
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
index 9c3ec4240a5..8f090fe886a 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 #[non_exhaustive]
 pub enum UninhabitedEnum {
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
index f94616dc64b..989cb791a41 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
@@ -1,53 +1,41 @@
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled
-  --> $DIR/indirect_match_same_crate.rs:32:11
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
+  --> $DIR/indirect_match_same_crate.rs:34:11
    |
 LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
-   | ----------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedEnum` defined here
+   | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled
-  --> $DIR/indirect_match_same_crate.rs:36:11
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
+  --> $DIR/indirect_match_same_crate.rs:38:11
    |
 LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
-   | --------------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedStruct` defined here
+   | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled
-  --> $DIR/indirect_match_same_crate.rs:40:11
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
+  --> $DIR/indirect_match_same_crate.rs:42:11
    |
 LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
-   | ------------------------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedTupleStruct` defined here
+   | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled
-  --> $DIR/indirect_match_same_crate.rs:46:11
+error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
+  --> $DIR/indirect_match_same_crate.rs:48:11
    |
 LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
-   | ------------------------------------------------------------
-   | |          |
-   | |          variant not covered
-   | `IndirectUninhabitedVariants` defined here
+   | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
 ...
 LL |     match x {}
    |           ^
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
index 68ac42ef587..be86519ecb1 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
@@ -1,6 +1,7 @@
 // aux-build:uninhabited.rs
 #![deny(unreachable_patterns)]
 #![feature(exhaustive_patterns)]
+#![feature(never_type)]
 
 extern crate uninhabited;
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
index 2c2e5429341..17a8d010072 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:22:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11
    |
 LL |     match x {}
    |           ^
@@ -7,7 +7,7 @@ LL |     match x {}
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:26:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
    |
 LL |     match x {}
    |           ^
@@ -15,7 +15,7 @@ LL |     match x {}
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:30:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
    |
 LL |     match x {}
    |           ^
@@ -23,7 +23,7 @@ LL |     match x {}
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty
-  --> $DIR/indirect_match_with_exhaustive_patterns.rs:36:11
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
    |
 LL |     match x {}
    |           ^
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
index 06c318414f0..60289aa7803 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
@@ -2,6 +2,7 @@
 
 #![deny(unreachable_patterns)]
 #![feature(exhaustive_patterns)]
+#![feature(never_type)]
 
 #[non_exhaustive]
 pub enum UninhabitedEnum {
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
index fd3dbca04c0..e54098d4d48 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
@@ -1,4 +1,5 @@
 // aux-build:uninhabited.rs
+#![feature(never_type)]
 
 extern crate uninhabited;
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
index de3fa900cd6..ccc25a184e9 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -1,32 +1,32 @@
 error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
-  --> $DIR/match.rs:18:11
+  --> $DIR/match.rs:19:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled
-  --> $DIR/match.rs:22:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty
+  --> $DIR/match.rs:23:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled
-  --> $DIR/match.rs:26:11
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty
+  --> $DIR/match.rs:27:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled
-  --> $DIR/match.rs:30:11
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/match.rs:31:11
    |
 LL |     match x {}
-   |           ^
+   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
index c31688add91..ebbdfba15f3 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
@@ -1,3 +1,5 @@
+#![feature(never_type)]
+
 #[non_exhaustive]
 pub enum UninhabitedEnum {
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
index 3dd1a914d55..858aae58576 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -1,10 +1,7 @@
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled
-  --> $DIR/match_same_crate.rs:28:11
+error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
+  --> $DIR/match_same_crate.rs:30:11
    |
-LL |   pub struct UninhabitedStruct {
-   |   -          ----------------- variant not covered
-   |  _|
-   | |
+LL | / pub struct UninhabitedStruct {
 LL | |     _priv: !,
 LL | | }
    | |_- `UninhabitedStruct` defined here
@@ -14,33 +11,30 @@ LL |       match x {}
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled
-  --> $DIR/match_same_crate.rs:32:11
+error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
+  --> $DIR/match_same_crate.rs:34:11
    |
 LL | pub struct UninhabitedTupleStruct(!);
-   | -------------------------------------
-   | |          |
-   | |          variant not covered
-   | `UninhabitedTupleStruct` defined here
+   | ------------------------------------- `UninhabitedTupleStruct` defined here
 ...
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled
-  --> $DIR/match_same_crate.rs:36:11
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/match_same_crate.rs:38:11
    |
 LL | / pub enum UninhabitedVariants {
 LL | |     #[non_exhaustive] Tuple(!),
-   | |                       ----- variant not covered
+   | |                       ----- not covered
 LL | |     #[non_exhaustive] Struct { x: ! }
-   | |                       ------ variant not covered
+   | |                       ------ not covered
 LL | | }
    | |_- `UninhabitedVariants` defined here
 ...
 LL |       match x {}
-   |             ^
+   |             ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
index 37d739834d2..900dfff652e 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
@@ -1,6 +1,7 @@
 // aux-build:uninhabited.rs
 #![deny(unreachable_patterns)]
 #![feature(exhaustive_patterns)]
+#![feature(never_type)]
 
 extern crate uninhabited;
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index 3b56c689071..a54885c96e5 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:21:11
+  --> $DIR/match_with_exhaustive_patterns.rs:22:11
    |
 LL |     match x {}
    |           ^
@@ -7,7 +7,7 @@ LL |     match x {}
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:25:11
+  --> $DIR/match_with_exhaustive_patterns.rs:26:11
    |
 LL |     match x {}
    |           ^
@@ -15,18 +15,18 @@ LL |     match x {}
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
 error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:29:11
+  --> $DIR/match_with_exhaustive_patterns.rs:30:11
    |
 LL |     match x {}
    |           ^
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
-error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty
-  --> $DIR/match_with_exhaustive_patterns.rs:33:11
+error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
+  --> $DIR/match_with_exhaustive_patterns.rs:34:11
    |
 LL |     match x {}
-   |           ^
+   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
    |
    = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
index 2b2e4b6e77d..de5530485f3 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -2,6 +2,7 @@
 
 #![deny(unreachable_patterns)]
 #![feature(exhaustive_patterns)]
+#![feature(never_type)]
 
 #[non_exhaustive]
 pub enum UninhabitedEnum {
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
index 3d4cca4505e..ffc496a975e 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
@@ -1,5 +1,6 @@
 #![deny(unreachable_patterns)]
 #![feature(exhaustive_patterns)]
+#![feature(never_type)]
 
 #[non_exhaustive]
 pub enum UninhabitedEnum {
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
index fea883f8912..e3de94be128 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
@@ -1,5 +1,5 @@
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:51:9
+  --> $DIR/patterns_same_crate.rs:52:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^
@@ -11,25 +11,25 @@ LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:56:9
+  --> $DIR/patterns_same_crate.rs:57:9
    |
 LL |         Some(_x) => (),
    |         ^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:60:15
+  --> $DIR/patterns_same_crate.rs:61:15
    |
 LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:64:15
+  --> $DIR/patterns_same_crate.rs:65:15
    |
 LL |     while let Some(_x) = uninhabited_struct() {
    |               ^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/patterns_same_crate.rs:67:15
+  --> $DIR/patterns_same_crate.rs:68:15
    |
 LL |     while let Some(_x) = uninhabited_tuple_struct() {
    |               ^^^^^^^^
diff --git a/src/test/ui/self/self-vs-path-ambiguity.stderr b/src/test/ui/self/self-vs-path-ambiguity.stderr
index 5ce6a81bfcf..2beef50cdb5 100644
--- a/src/test/ui/self/self-vs-path-ambiguity.stderr
+++ b/src/test/ui/self/self-vs-path-ambiguity.stderr
@@ -2,7 +2,7 @@ error: unexpected lifetime `'a` in pattern
   --> $DIR/self-vs-path-ambiguity.rs:9:11
    |
 LL |     fn i(&'a self::S: &S) {}
-   |           ^^ unexpected lifetime
+   |           ^^ help: remove the lifetime
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/issue-37767.stderr b/src/test/ui/span/issue-37767.stderr
index 0bbff45436c..9ed6c8b826f 100644
--- a/src/test/ui/span/issue-37767.stderr
+++ b/src/test/ui/span/issue-37767.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A`
    |
 LL |     fn foo(&mut self) {}
    |     ^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `A::foo(&a)` instead
 note: candidate #2 is defined in the trait `B`
   --> $DIR/issue-37767.rs:6:5
    |
 LL |     fn foo(&mut self) {}
    |     ^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `B::foo(&a)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     A::foo(&a)
+   |     ^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     B::foo(&a)
+   |     ^^^^^^^^^^
 
 error[E0034]: multiple applicable items in scope
   --> $DIR/issue-37767.rs:22:7
@@ -28,13 +34,19 @@ note: candidate #1 is defined in the trait `C`
    |
 LL |     fn foo(&self) {}
    |     ^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `C::foo(&a)` instead
 note: candidate #2 is defined in the trait `D`
   --> $DIR/issue-37767.rs:18:5
    |
 LL |     fn foo(&self) {}
    |     ^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `D::foo(&a)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     C::foo(&a)
+   |     ^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     D::foo(&a)
+   |     ^^^^^^^^^^
 
 error[E0034]: multiple applicable items in scope
   --> $DIR/issue-37767.rs:34:7
@@ -47,13 +59,19 @@ note: candidate #1 is defined in the trait `E`
    |
 LL |     fn foo(self) {}
    |     ^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `E::foo(a)` instead
 note: candidate #2 is defined in the trait `F`
   --> $DIR/issue-37767.rs:30:5
    |
 LL |     fn foo(self) {}
    |     ^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `F::foo(a)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     E::foo(a)
+   |     ^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     F::foo(a)
+   |     ^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs
index a3b1d1d8179..b6db4008db0 100644
--- a/src/test/ui/span/issue-39018.rs
+++ b/src/test/ui/span/issue-39018.rs
@@ -1,15 +1,15 @@
 pub fn main() {
     let x = "Hello " + "World!";
-    //~^ ERROR cannot be applied to type
+    //~^ ERROR cannot add
 
     // Make sure that the span outputs a warning
     // for not having an implementation for std::ops::Add
     // that won't output for the above string concatenation
     let y = World::Hello + World::Goodbye;
-    //~^ ERROR cannot be applied to type
+    //~^ ERROR cannot add
 
     let x = "Hello " + "World!".to_owned();
-    //~^ ERROR cannot be applied to type
+    //~^ ERROR cannot add
 }
 
 enum World {
@@ -23,16 +23,16 @@ fn foo() {
     let c = "";
     let d = "";
     let e = &a;
-    let _ = &a + &b; //~ ERROR binary operation
-    let _ = &a + b; //~ ERROR binary operation
+    let _ = &a + &b; //~ ERROR cannot add
+    let _ = &a + b; //~ ERROR cannot add
     let _ = a + &b; // ok
     let _ = a + b; //~ ERROR mismatched types
-    let _ = e + b; //~ ERROR binary operation
-    let _ = e + &b; //~ ERROR binary operation
-    let _ = e + d; //~ ERROR binary operation
-    let _ = e + &d; //~ ERROR binary operation
-    let _ = &c + &d; //~ ERROR binary operation
-    let _ = &c + d; //~ ERROR binary operation
-    let _ = c + &d; //~ ERROR binary operation
-    let _ = c + d; //~ ERROR binary operation
+    let _ = e + b; //~ ERROR cannot add
+    let _ = e + &b; //~ ERROR cannot add
+    let _ = e + d; //~ ERROR cannot add
+    let _ = e + &d; //~ ERROR cannot add
+    let _ = &c + &d; //~ ERROR cannot add
+    let _ = &c + d; //~ ERROR cannot add
+    let _ = c + &d; //~ ERROR cannot add
+    let _ = c + d; //~ ERROR cannot add
 }
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index 9637d1d82ec..8a32561bd01 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `&str` to `&str`
   --> $DIR/issue-39018.rs:2:22
    |
 LL |     let x = "Hello " + "World!";
@@ -12,7 +12,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let x = "Hello ".to_owned() + "World!";
    |             ^^^^^^^^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `World`
+error[E0369]: cannot add `World` to `World`
   --> $DIR/issue-39018.rs:8:26
    |
 LL |     let y = World::Hello + World::Goodbye;
@@ -22,7 +22,7 @@ LL |     let y = World::Hello + World::Goodbye;
    |
    = note: an implementation of `std::ops::Add` might be missing for `World`
 
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `std::string::String` to `&str`
   --> $DIR/issue-39018.rs:11:22
    |
 LL |     let x = "Hello " + "World!".to_owned();
@@ -36,7 +36,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let x = "Hello ".to_owned() + &"World!".to_owned();
    |             ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `&std::string::String` to `&std::string::String`
   --> $DIR/issue-39018.rs:26:16
    |
 LL |     let _ = &a + &b;
@@ -50,7 +50,7 @@ help: String concatenation appends the string on the right to the string on the
 LL |     let _ = a + &b;
    |             ^
 
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `std::string::String` to `&std::string::String`
   --> $DIR/issue-39018.rs:27:16
    |
 LL |     let _ = &a + b;
@@ -73,7 +73,7 @@ LL |     let _ = a + b;
    |                 expected `&str`, found struct `std::string::String`
    |                 help: consider borrowing here: `&b`
 
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `std::string::String` to `&std::string::String`
   --> $DIR/issue-39018.rs:30:15
    |
 LL |     let _ = e + b;
@@ -87,7 +87,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let _ = e.to_owned() + &b;
    |             ^^^^^^^^^^^^   ^^
 
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `&std::string::String` to `&std::string::String`
   --> $DIR/issue-39018.rs:31:15
    |
 LL |     let _ = e + &b;
@@ -101,7 +101,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let _ = e.to_owned() + &b;
    |             ^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `&str` to `&std::string::String`
   --> $DIR/issue-39018.rs:32:15
    |
 LL |     let _ = e + d;
@@ -115,7 +115,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let _ = e.to_owned() + d;
    |             ^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `&&str` to `&std::string::String`
   --> $DIR/issue-39018.rs:33:15
    |
 LL |     let _ = e + &d;
@@ -129,7 +129,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let _ = e.to_owned() + &d;
    |             ^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `&&str`
+error[E0369]: cannot add `&&str` to `&&str`
   --> $DIR/issue-39018.rs:34:16
    |
 LL |     let _ = &c + &d;
@@ -139,7 +139,7 @@ LL |     let _ = &c + &d;
    |
    = note: an implementation of `std::ops::Add` might be missing for `&&str`
 
-error[E0369]: binary operation `+` cannot be applied to type `&&str`
+error[E0369]: cannot add `&str` to `&&str`
   --> $DIR/issue-39018.rs:35:16
    |
 LL |     let _ = &c + d;
@@ -149,7 +149,7 @@ LL |     let _ = &c + d;
    |
    = note: an implementation of `std::ops::Add` might be missing for `&&str`
 
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `&&str` to `&str`
   --> $DIR/issue-39018.rs:36:15
    |
 LL |     let _ = c + &d;
@@ -163,7 +163,7 @@ help: `to_owned()` can be used to create an owned `String` from a string referen
 LL |     let _ = c.to_owned() + &d;
    |             ^^^^^^^^^^^^
 
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `&str` to `&str`
   --> $DIR/issue-39018.rs:37:15
    |
 LL |     let _ = c + d;
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.rs b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
index 58138e21bc0..d3292bbecba 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.rs
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.rs
@@ -9,8 +9,8 @@ fn shines_a_beacon_through_the_darkness() {
 }
 
 fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
-    data.iter() //~ ERROR type annotations needed
-        .sum::<_>()
+    data.iter()
+        .sum::<_>() //~ ERROR type annotations needed
         .to_string()
 }
 
diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
index 30c9adb1dce..9824d879dbd 100644
--- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
+++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr
@@ -4,16 +4,15 @@ error[E0282]: type annotations needed for `std::option::Option<_>`
 LL |     let x: Option<_> = None;
    |         - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified
 LL |     x.unwrap().method_that_could_exist_on_some_type();
-   |       ^^^^^^ cannot infer type for `T`
+   |       ^^^^^^ cannot infer type for type parameter `T`
    |
    = note: type must be known at this point
 
 error[E0282]: type annotations needed
-  --> $DIR/issue-42234-unknown-receiver-type.rs:12:5
+  --> $DIR/issue-42234-unknown-receiver-type.rs:13:10
    |
-LL | /     data.iter()
-LL | |         .sum::<_>()
-   | |___________________^ cannot infer type
+LL |         .sum::<_>()
+   |          ^^^ cannot infer type
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr
index 36db5bea862..53a6238422b 100644
--- a/src/test/ui/span/issue-7575.stderr
+++ b/src/test/ui/span/issue-7575.stderr
@@ -10,24 +10,33 @@ note: candidate #1 is defined in the trait `CtxtFn`
    |
 LL |     fn f9(_: usize) -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `CtxtFn::f9(u, 342)` instead
 note: candidate #2 is defined in the trait `OtherTrait`
   --> $DIR/issue-7575.rs:8:5
    |
 LL |     fn f9(_: usize) -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `OtherTrait::f9(u, 342)` instead
 note: candidate #3 is defined in the trait `UnusedTrait`
   --> $DIR/issue-7575.rs:17:5
    |
 LL |     fn f9(_: usize) -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `UnusedTrait::f9(u, 342)` instead
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following traits define an item `f9`, perhaps you need to implement one of them:
            candidate #1: `CtxtFn`
            candidate #2: `OtherTrait`
            candidate #3: `UnusedTrait`
+help: disambiguate the method call for candidate #1
+   |
+LL |     u.f8(42) + CtxtFn::f9(u, 342) + m.fff(42)
+   |                ^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     u.f8(42) + OtherTrait::f9(u, 342) + m.fff(42)
+   |                ^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #3
+   |
+LL |     u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42)
+   |                ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0599]: no method named `fff` found for type `Myisize` in the current scope
   --> $DIR/issue-7575.rs:62:30
@@ -60,8 +69,11 @@ note: the candidate is defined in the trait `ManyImplTrait`
    |
 LL |     fn is_str() -> bool {
    |     ^^^^^^^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead
    = help: items from traits can only be used if the type parameter is bounded by the trait
+help: disambiguate the method call for the candidate
+   |
+LL |     ManyImplTrait::is_str(t)
+   |
 help: the following trait defines an item `is_str`, perhaps you need to restrict type parameter `T` with it:
    |
 LL | fn param_bound<T: ManyImplTrait + ManyImplTrait>(t: T) -> bool {
diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr
index e32a542bb7a..2b92f9b93bf 100644
--- a/src/test/ui/span/type-annotations-needed-expr.stderr
+++ b/src/test/ui/span/type-annotations-needed-expr.stderr
@@ -2,7 +2,10 @@ error[E0282]: type annotations needed
   --> $DIR/type-annotations-needed-expr.rs:2:39
    |
 LL |     let _ = (vec![1,2,3]).into_iter().sum() as f64;
-   |                                       ^^^ cannot infer type for `S`
+   |                                       ^^^
+   |                                       |
+   |                                       cannot infer type for type parameter `S` declared on the method `sum`
+   |                                       help: consider specifying the type argument in the method call: `sum::<S>`
    |
    = note: type must be known at this point
 
diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr
index 421af67d19c..c3e95455532 100644
--- a/src/test/ui/span/type-binding.stderr
+++ b/src/test/ui/span/type-binding.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref`
   --> $DIR/type-binding.rs:6:20
    |
 LL | fn homura<T: Deref<Trget = i32>>(_: T) {}
-   |                    ^^^^^^^^^^^ associated type `Trget` not found
+   |                    ^^^^^^^^^^^ help: there is an associated type with a similar name: `Target`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs
index 38421e2e6ef..2e3d790d2d8 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs
@@ -1,6 +1,6 @@
 // Various checks that stability attributes are used correctly, per RFC 507
 
-#![feature(const_fn, staged_api, rustc_const_unstable)]
+#![feature(const_fn, staged_api)]
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -60,11 +60,10 @@ fn multiple3() { }
 #[stable(feature = "a", since = "b")]
 #[rustc_deprecated(since = "b", reason = "text")]
 #[rustc_deprecated(since = "b", reason = "text")]
-#[rustc_const_unstable(feature = "c")]
-#[rustc_const_unstable(feature = "d")]
+#[rustc_const_unstable(feature = "c", issue = "0")]
+#[rustc_const_unstable(feature = "d", issue = "0")] //~ ERROR multiple stability levels
 pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
 //~^ ERROR Invalid stability or deprecation version found
-//~| ERROR multiple rustc_const_unstable attributes
 
 #[rustc_deprecated(since = "a", reason = "text")]
 fn deprecated_without_unstable_or_stable() { }
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index 4b7ec821f45..552e078f45f 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -88,11 +88,11 @@ error[E0540]: multiple rustc_deprecated attributes
 LL | pub const fn multiple4() { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0553]: multiple rustc_const_unstable attributes
-  --> $DIR/stability-attribute-sanity.rs:65:1
+error[E0544]: multiple stability levels
+  --> $DIR/stability-attribute-sanity.rs:64:1
    |
-LL | pub const fn multiple4() { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_const_unstable(feature = "d", issue = "0")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Invalid stability or deprecation version found
   --> $DIR/stability-attribute-sanity.rs:65:1
@@ -101,7 +101,7 @@ LL | pub const fn multiple4() { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute
-  --> $DIR/stability-attribute-sanity.rs:70:1
+  --> $DIR/stability-attribute-sanity.rs:69:1
    |
 LL | fn deprecated_without_unstable_or_stable() { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/str/str-concat-on-double-ref.rs b/src/test/ui/str/str-concat-on-double-ref.rs
index a671b6e191e..23e5f892062 100644
--- a/src/test/ui/str/str-concat-on-double-ref.rs
+++ b/src/test/ui/str/str-concat-on-double-ref.rs
@@ -2,6 +2,6 @@ fn main() {
     let a: &String = &"1".to_owned();
     let b: &str = &"2";
     let c = a + b;
-    //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String`
+    //~^ ERROR cannot add `&str` to `&std::string::String`
     println!("{:?}", c);
 }
diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr
index d193955af4b..d77e0d8f242 100644
--- a/src/test/ui/str/str-concat-on-double-ref.stderr
+++ b/src/test/ui/str/str-concat-on-double-ref.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+error[E0369]: cannot add `&str` to `&std::string::String`
   --> $DIR/str-concat-on-double-ref.rs:4:15
    |
 LL |     let c = a + b;
diff --git a/src/test/ui/suggestions/option-content-move2.rs b/src/test/ui/suggestions/option-content-move2.rs
new file mode 100644
index 00000000000..88e8a5b7aee
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.rs
@@ -0,0 +1,16 @@
+struct NotCopyable;
+
+fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
+
+fn parse() {
+    let mut var = None;
+    func(|| {
+        // Shouldn't suggest `move ||.as_ref()` here
+        move || {
+        //~^ ERROR: cannot move out of `var`
+            var = Some(NotCopyable);
+        }
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
new file mode 100644
index 00000000000..71f745374e5
--- /dev/null
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
+  --> $DIR/option-content-move2.rs:9:9
+   |
+LL |     let mut var = None;
+   |         ------- captured outer variable
+...
+LL |         move || {
+   |         ^^^^^^^ move out of `var` occurs here
+LL |
+LL |             var = Some(NotCopyable);
+   |             ---
+   |             |
+   |             move occurs because `var` has type `std::option::Option<NotCopyable>`, which does not implement the `Copy` trait
+   |             move occurs due to use in closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs
index cc94680530c..1989ea88635 100644
--- a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs
+++ b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs
@@ -3,5 +3,5 @@
 fn main() {
     let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥";
     let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
-    //~^ ERROR binary operation `+` cannot be applied to type `&str`
+    //~^ ERROR cannot add `&str` to `&str`
 }
diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
index 9f0f990670f..69daa93412a 100644
--- a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
+++ b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `&str`
+error[E0369]: cannot add `&str` to `&str`
   --> $DIR/non-1-width-unicode-multiline-label.rs:5:260
    |
 LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇...࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";
diff --git a/src/test/ui/traits/reservation-impls/reservation-impl-non-lattice-ok.rs b/src/test/ui/traits/reservation-impls/reservation-impl-non-lattice-ok.rs
index 0e0197803b7..f14589ccf84 100644
--- a/src/test/ui/traits/reservation-impls/reservation-impl-non-lattice-ok.rs
+++ b/src/test/ui/traits/reservation-impls/reservation-impl-non-lattice-ok.rs
@@ -30,7 +30,7 @@
 //
 // [ii]: http://smallcultfollowing.com/babysteps/blog/2016/09/24/intersection-impls/
 
-#![feature(rustc_attrs)]
+#![feature(rustc_attrs, never_type)]
 
 trait MyTrait {}
 
diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr
index cde7dd08249..48a029104ae 100644
--- a/src/test/ui/traits/trait-alias-ambiguous.stderr
+++ b/src/test/ui/traits/trait-alias-ambiguous.stderr
@@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u
    |
 LL |         fn foo(&self) {}
    |         ^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `inner::A::foo(t)` instead
 note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8`
   --> $DIR/trait-alias-ambiguous.rs:11:9
    |
 LL |         fn foo(&self) {}
    |         ^^^^^^^^^^^^^
-   = help: to disambiguate the method call, write `inner::B::foo(t)` instead
+help: disambiguate the method call for candidate #1
+   |
+LL |     inner::A::foo(&t);
+   |     ^^^^^^^^^^^^^^^^^
+help: disambiguate the method call for candidate #2
+   |
+LL |     inner::B::foo(&t);
+   |     ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.rs b/src/test/ui/traits/trait-resolution-in-overloaded-op.rs
index 96f81a21a3b..28677698516 100644
--- a/src/test/ui/traits/trait-resolution-in-overloaded-op.rs
+++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.rs
@@ -5,7 +5,7 @@ trait MyMul<Rhs, Res> {
 }
 
 fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 {
-    a * b //~ ERROR binary operation `*` cannot be applied to type `&T`
+    a * b //~ ERROR cannot multiply `f64` to `&T`
 }
 
 fn main() {}
diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
index d11562e2a00..8d7ba36c665 100644
--- a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
+++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `*` cannot be applied to type `&T`
+error[E0369]: cannot multiply `f64` to `&T`
   --> $DIR/trait-resolution-in-overloaded-op.rs:8:7
    |
 LL |     a * b
diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr
index 22931c5ba32..f9718dac354 100644
--- a/src/test/ui/traits/trait-static-method-generic-inference.stderr
+++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr
@@ -1,11 +1,13 @@
-error[E0283]: type annotations needed: cannot resolve `_: base::HasNew<base::Foo>`
+error[E0283]: type annotations needed
   --> $DIR/trait-static-method-generic-inference.rs:24:25
    |
 LL |         fn new() -> T;
    |         -------------- required by `base::HasNew::new`
 ...
 LL |     let _f: base::Foo = base::HasNew::new();
-   |                         ^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^^ cannot infer type
+   |
+   = note: cannot resolve `_: base::HasNew<base::Foo>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr
index d7d27049f43..338c8cbf2e4 100644
--- a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr
+++ b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/traits-multidispatch-convert-ambig-dest.rs:26:5
    |
 LL |     test(22, std::default::Default::default());
-   |     ^^^^ cannot infer type for `U`
+   |     ^^^^ cannot infer type for type parameter `U` declared on the function `test`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.rs b/src/test/ui/type-inference/or_else-multiple-type-params.rs
new file mode 100644
index 00000000000..b15de2a4559
--- /dev/null
+++ b/src/test/ui/type-inference/or_else-multiple-type-params.rs
@@ -0,0 +1,10 @@
+use std::process::{Command, Stdio};
+
+fn main() {
+    let process = Command::new("wc")
+        .stdout(Stdio::piped())
+        .spawn()
+        .or_else(|err| { //~ ERROR type annotations needed
+            panic!("oh no: {:?}", err);
+        }).unwrap();
+}
diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr
new file mode 100644
index 00000000000..b9258b20f5a
--- /dev/null
+++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr
@@ -0,0 +1,12 @@
+error[E0282]: type annotations needed
+  --> $DIR/or_else-multiple-type-params.rs:7:10
+   |
+LL |         .or_else(|err| {
+   |          ^^^^^^^
+   |          |
+   |          cannot infer type for type parameter `F` declared on the method `or_else`
+   |          help: consider specifying the type arguments in the method call: `or_else::<F, O>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/sort_by_key.rs b/src/test/ui/type-inference/sort_by_key.rs
new file mode 100644
index 00000000000..afc4d90b865
--- /dev/null
+++ b/src/test/ui/type-inference/sort_by_key.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let mut lst: [([i32; 10], bool); 10] = [([0; 10], false); 10];
+    lst.sort_by_key(|&(v, _)| v.iter().sum()); //~ ERROR type annotations needed
+    println!("{:?}", lst);
+}
diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr
new file mode 100644
index 00000000000..e74c0dfa5e2
--- /dev/null
+++ b/src/test/ui/type-inference/sort_by_key.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/sort_by_key.rs:3:9
+   |
+LL |     lst.sort_by_key(|&(v, _)| v.iter().sum());
+   |         ^^^^^^^^^^^                    --- help: consider specifying the type argument in the method call: `sum::<S>`
+   |         |
+   |         cannot infer type for type parameter `K` declared on the method `sort_by_key`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/unbounded-associated-type.rs b/src/test/ui/type-inference/unbounded-associated-type.rs
new file mode 100644
index 00000000000..0167e943612
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-associated-type.rs
@@ -0,0 +1,16 @@
+trait T {
+    type A;
+    fn foo(&self) -> Self::A {
+        panic!()
+    }
+}
+
+struct S<X>(std::marker::PhantomData<X>);
+
+impl<X> T for S<X> {
+   type A = X;
+}
+
+fn main() {
+    S(std::marker::PhantomData).foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/type-inference/unbounded-associated-type.stderr b/src/test/ui/type-inference/unbounded-associated-type.stderr
new file mode 100644
index 00000000000..19e2bd4513d
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-associated-type.stderr
@@ -0,0 +1,15 @@
+error[E0282]: type annotations needed
+  --> $DIR/unbounded-associated-type.rs:15:5
+   |
+LL |     type A;
+   |     ------- `<Self as T>::A` defined here
+...
+LL |     S(std::marker::PhantomData).foo();
+   |     ^--------------------------------
+   |     |
+   |     this method call resolves to `<Self as T>::A`
+   |     cannot infer type for type parameter `X` declared on the struct `S`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs
new file mode 100644
index 00000000000..81d054b3a1e
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.rs
@@ -0,0 +1,9 @@
+#[allow(invalid_type_param_default)]
+
+fn foo<T, U = u64>() -> (T, U) {
+    panic!()
+}
+
+fn main() {
+    foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
new file mode 100644
index 00000000000..d60ca4a4932
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5
+   |
+LL |     foo();
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.rs b/src/test/ui/type-inference/unbounded-type-param-in-fn.rs
new file mode 100644
index 00000000000..1f336ed59a6
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.rs
@@ -0,0 +1,7 @@
+fn foo<T>() -> T {
+    panic!()
+}
+
+fn main() {
+    foo(); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
new file mode 100644
index 00000000000..45d879d8d56
--- /dev/null
+++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/unbounded-type-param-in-fn.rs:6:5
+   |
+LL |     foo();
+   |     ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/type-sizes.rs b/src/test/ui/type-sizes.rs
index 3dfe0ad7f72..27433fd770b 100644
--- a/src/test/ui/type-sizes.rs
+++ b/src/test/ui/type-sizes.rs
@@ -2,6 +2,7 @@
 
 #![allow(non_camel_case_types)]
 #![allow(dead_code)]
+#![feature(never_type)]
 
 use std::mem::size_of;
 
diff --git a/src/test/ui/type/type-annotation-needed.rs b/src/test/ui/type/type-annotation-needed.rs
index 3b1521d5c02..a420515be49 100644
--- a/src/test/ui/type/type-annotation-needed.rs
+++ b/src/test/ui/type/type-annotation-needed.rs
@@ -5,4 +5,6 @@ fn foo<T: Into<String>>(x: i32) {}
 fn main() {
     foo(42);
     //~^ ERROR type annotations needed
+    //~| NOTE cannot infer type
+    //~| NOTE cannot resolve
 }
diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr
index 460bbe9dbc4..c6a811e8363 100644
--- a/src/test/ui/type/type-annotation-needed.stderr
+++ b/src/test/ui/type/type-annotation-needed.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed: cannot resolve `_: std::convert::Into<std::string::String>`
+error[E0283]: type annotations needed
   --> $DIR/type-annotation-needed.rs:6:5
    |
 LL | fn foo<T: Into<String>>(x: i32) {}
@@ -6,6 +6,11 @@ LL | fn foo<T: Into<String>>(x: i32) {}
 ...
 LL |     foo(42);
    |     ^^^
+   |     |
+   |     cannot infer type for type parameter `T` declared on the function `foo`
+   |     help: consider specifying the type argument in the function call: `foo::<T>`
+   |
+   = note: cannot resolve `_: std::convert::Into<std::string::String>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
index 6524bf5dd2b..53cc769bae3 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `std::vec::Vec<T>`
   --> $DIR/cannot_infer_local_or_vec.rs:2:13
    |
 LL |     let x = vec![];
-   |         -   ^^^^^^ cannot infer type for `T`
+   |         -   ^^^^^^ cannot infer type for type parameter `T`
    |         |
    |         consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
    |
diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
index 6d1ef240da6..df7228ce9f2 100644
--- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
+++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `(std::vec::Vec<T>,)`
   --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
    |
 LL |     let (x, ) = (vec![], );
-   |         -----    ^^^^^^ cannot infer type for `T`
+   |         -----    ^^^^^^ cannot infer type for type parameter `T`
    |         |
    |         consider giving this pattern the explicit type `(std::vec::Vec<T>,)`, where the type parameter `T` is specified
    |
diff --git a/src/test/ui/type/type-check/issue-22897.stderr b/src/test/ui/type/type-check/issue-22897.stderr
index 2b3f0696f3c..fae7b79269b 100644
--- a/src/test/ui/type/type-check/issue-22897.stderr
+++ b/src/test/ui/type/type-check/issue-22897.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/issue-22897.rs:4:5
    |
 LL |     [];
-   |     ^^ cannot infer type for `[_; 0]`
+   |     ^^ cannot infer type for array `[_; 0]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr
index 508783aaf2b..4fc02855091 100644
--- a/src/test/ui/type/type-check/issue-40294.stderr
+++ b/src/test/ui/type/type-check/issue-40294.stderr
@@ -1,4 +1,4 @@
-error[E0283]: type annotations needed: cannot resolve `&'a T: Foo`
+error[E0283]: type annotations needed
   --> $DIR/issue-40294.rs:5:1
    |
 LL |   trait Foo: Sized {
@@ -11,7 +11,9 @@ LL | | {
 LL | |     x.foo();
 LL | |     y.foo();
 LL | | }
-   | |_^
+   | |_^ cannot infer type for reference `&'a T`
+   |
+   = note: cannot resolve `&'a T: Foo`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs
new file mode 100644
index 00000000000..e23c0d0a40a
--- /dev/null
+++ b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs
@@ -0,0 +1,27 @@
+fn main() {
+    let mut i: i64;
+    // Expected type is an inference variable `?T`
+    // because the `match` is used as a statement.
+    // This is the "initial" type of the `coercion`.
+    match i {
+        // Add `bool` to the overall `coercion`.
+        0 => true,
+
+        // Necessary to cause the ICE:
+        1 => true,
+
+        // Suppose that we had `let _: bool = match i { ... }`.
+        // In that case, as the expected type would be `bool`,
+        // we would suggest `i == 1` as a fix.
+        //
+        // However, no type error happens when checking `i = 1` because `expected == ?T`,
+        // which will unify with `typeof(i = 1) == ()`.
+        //
+        // However, in #67273, we would delay the unification of this arm with the above
+        // because we used the hitherto accumulated coercion as opposed to the "initial" type.
+        2 => i = 1,
+        //~^ ERROR match arms have incompatible types
+
+        _ => (),
+    }
+}
diff --git a/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr
new file mode 100644
index 00000000000..3547285542a
--- /dev/null
+++ b/src/test/ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.stderr
@@ -0,0 +1,22 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs:22:14
+   |
+LL | /     match i {
+LL | |         // Add `bool` to the overall `coercion`.
+LL | |         0 => true,
+   | |              ---- this is found to be of type `bool`
+LL | |
+LL | |         // Necessary to cause the ICE:
+LL | |         1 => true,
+   | |              ---- this is found to be of type `bool`
+...  |
+LL | |         2 => i = 1,
+   | |              ^^^^^ expected `bool`, found `()`
+...  |
+LL | |         _ => (),
+LL | |     }
+   | |_____- `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type/type-check/missing_trait_impl.rs b/src/test/ui/type/type-check/missing_trait_impl.rs
index dcca96b509b..f61ada3f63f 100644
--- a/src/test/ui/type/type-check/missing_trait_impl.rs
+++ b/src/test/ui/type/type-check/missing_trait_impl.rs
@@ -2,7 +2,7 @@ fn main() {
 }
 
 fn foo<T>(x: T, y: T) {
-    let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T`
+    let z = x + y; //~ ERROR cannot add `T` to `T`
 }
 
 fn bar<T>(x: T) {
diff --git a/src/test/ui/type/type-check/missing_trait_impl.stderr b/src/test/ui/type/type-check/missing_trait_impl.stderr
index 2a158ab8564..7186d6a542d 100644
--- a/src/test/ui/type/type-check/missing_trait_impl.stderr
+++ b/src/test/ui/type/type-check/missing_trait_impl.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `T`
+error[E0369]: cannot add `T` to `T`
   --> $DIR/missing_trait_impl.rs:5:15
    |
 LL |     let z = x + y;
diff --git a/src/test/ui/unconstrained-none.stderr b/src/test/ui/unconstrained-none.stderr
index eb918b25d2b..fbd71bd091d 100644
--- a/src/test/ui/unconstrained-none.stderr
+++ b/src/test/ui/unconstrained-none.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/unconstrained-none.rs:4:5
    |
 LL |     None;
-   |     ^^^^ cannot infer type for `T`
+   |     ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unconstrained-ref.stderr b/src/test/ui/unconstrained-ref.stderr
index d9a129a2d7b..eb8ebb5165d 100644
--- a/src/test/ui/unconstrained-ref.stderr
+++ b/src/test/ui/unconstrained-ref.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed
   --> $DIR/unconstrained-ref.rs:6:5
    |
 LL |     S { o: &None };
-   |     ^ cannot infer type for `T`
+   |     ^ cannot infer type for type parameter `T` declared on the struct `S`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs
index 84daa35484f..48cd92719b4 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs
@@ -1,3 +1,4 @@
+#![feature(never_type)]
 #![feature(exhaustive_patterns)]
 
 mod foo {
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
index 6ba03ee5083..26e1be34ea7 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding: `A(_)` not covered
-  --> $DIR/uninhabited-irrefutable.rs:26:9
+  --> $DIR/uninhabited-irrefutable.rs:27:9
    |
 LL | / enum Foo {
 LL | |     A(foo::SecretlyEmpty),
diff --git a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index 7af6075262c..18ffdccb9b2 100644
--- a/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/src/test/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -9,6 +9,9 @@ LL |     let _ = match x {
 error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
   --> $DIR/uninhabited-matches-feature-gated.rs:12:19
    |
+LL | enum Void {}
+   | ------------ `Void` defined here
+...
 LL |     let _ = match x {};
    |                   ^
    |
diff --git a/src/test/ui/uninhabited/uninhabited-patterns.rs b/src/test/ui/uninhabited/uninhabited-patterns.rs
index 66a1a7f7735..1bf01184a08 100644
--- a/src/test/ui/uninhabited/uninhabited-patterns.rs
+++ b/src/test/ui/uninhabited/uninhabited-patterns.rs
@@ -1,5 +1,6 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(never_type)]
 #![feature(exhaustive_patterns)]
 #![feature(slice_patterns)]
 #![deny(unreachable_patterns)]
diff --git a/src/test/ui/uninhabited/uninhabited-patterns.stderr b/src/test/ui/uninhabited/uninhabited-patterns.stderr
index 4a793c4510e..3e5329cfb30 100644
--- a/src/test/ui/uninhabited/uninhabited-patterns.stderr
+++ b/src/test/ui/uninhabited/uninhabited-patterns.stderr
@@ -1,35 +1,35 @@
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:26:9
+  --> $DIR/uninhabited-patterns.rs:27:9
    |
 LL |         &[..] => (),
    |         ^^^^^
    |
 note: lint level defined here
-  --> $DIR/uninhabited-patterns.rs:5:9
+  --> $DIR/uninhabited-patterns.rs:6:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:31:9
+  --> $DIR/uninhabited-patterns.rs:32:9
    |
 LL |         Ok(box _) => (),
    |         ^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:33:9
+  --> $DIR/uninhabited-patterns.rs:34:9
    |
 LL |         Err(&[..]) => (),
    |         ^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:40:9
+  --> $DIR/uninhabited-patterns.rs:41:9
    |
 LL |         Err(Ok(_y)) => (),
    |         ^^^^^^^^^^^
 
 error: unreachable pattern
-  --> $DIR/uninhabited-patterns.rs:43:15
+  --> $DIR/uninhabited-patterns.rs:44:15
    |
 LL |     while let Some(_y) = foo() {
    |               ^^^^^^^^
diff --git a/src/test/ui/vec/vec-res-add.rs b/src/test/ui/vec/vec-res-add.rs
index ea2aa6cda24..4785178fb25 100644
--- a/src/test/ui/vec/vec-res-add.rs
+++ b/src/test/ui/vec/vec-res-add.rs
@@ -14,6 +14,6 @@ fn main() {
     let i = vec![r(0)];
     let j = vec![r(1)];
     let k = i + j;
-    //~^ ERROR binary operation `+` cannot be applied to type
+    //~^ ERROR cannot add `std::vec::Vec<R>` to `std::vec::Vec<R>`
     println!("{:?}", j);
 }
diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr
index 78b70f09e90..1cc12a222e5 100644
--- a/src/test/ui/vec/vec-res-add.stderr
+++ b/src/test/ui/vec/vec-res-add.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `+` cannot be applied to type `std::vec::Vec<R>`
+error[E0369]: cannot add `std::vec::Vec<R>` to `std::vec::Vec<R>`
   --> $DIR/vec-res-add.rs:16:15
    |
 LL |     let k = i + j;
diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr
index 28100d7c89e..62fc42fbae4 100644
--- a/src/test/ui/vector-no-ann.stderr
+++ b/src/test/ui/vector-no-ann.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `std::vec::Vec<T>`
   --> $DIR/vector-no-ann.rs:2:16
    |
 LL |     let _foo = Vec::new();
-   |         ----   ^^^^^^^^ cannot infer type for `T`
+   |         ----   ^^^^^^^^ cannot infer type for type parameter `T`
    |         |
    |         consider giving `_foo` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
 
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject 374db5c0b7a8ebc92ecb35ee21e11961da6c754
+Subproject 69f99e74ac2266dff4b5adc7c59b35236f0abef
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 15f8abd75d5..32965bbb292 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -569,6 +569,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
         list: false,
         options: test::Options::new(),
         time_options: None,
+        force_run_in_process: false,
     }
 }
 
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 7b928a2e7c2..36e412975b9 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -135,6 +135,7 @@ const WHITELIST: &[Crate<'_>] = &[
     Crate("polonius-engine"),
     Crate("ppv-lite86"),
     Crate("proc-macro2"),
+    Crate("punycode"),
     Crate("quick-error"),
     Crate("quote"),
     Crate("rand"),
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 41c4b618e60..22e4111ff3a 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -41,6 +41,7 @@ const WHITELIST: &[&str] = &[
     "E0514",
     "E0519",
     "E0523",
+    "E0553",
     "E0554",
     "E0570",
     "E0629",