about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2019-05-21 15:37:07 -0700
committerAlex Crichton <alex@alexcrichton.com>2019-05-21 15:37:07 -0700
commitfe3dd0b50fef21d14591c960a9610bafb224cdbf (patch)
treeee0b62d8e500d4ce4b6f50b4fe5d9056b9826072 /src
parente764f475ca7fffd6167ea991afc7d1b2b3f642dc (diff)
parent50a0defd5a93523067ef239936cc2e0755220904 (diff)
downloadrust-fe3dd0b50fef21d14591c960a9610bafb224cdbf.tar.gz
rust-fe3dd0b50fef21d14591c960a9610bafb224cdbf.zip
Merge remote-tracking branch 'origin/master' into azure-pipelines
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bootstrap.py1
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/bootstrap/native.rs4
-rw-r--r--src/bootstrap/test.rs21
-rw-r--r--src/build_helper/lib.rs2
-rw-r--r--src/ci/docker/dist-various-2/Dockerfile4
-rwxr-xr-xsrc/ci/docker/dist-various-2/build-wasi-toolchain.sh2
-rw-r--r--src/ci/docker/dist-x86_64-musl/Dockerfile8
-rw-r--r--src/ci/docker/scripts/musl-toolchain.sh9
-rwxr-xr-xsrc/ci/docker/x86_64-gnu-tools/checktools.sh4
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-guide0
-rw-r--r--src/doc/rustc/src/command-line-arguments.md167
-rw-r--r--src/doc/rustc/src/lints/groups.md4
-rw-r--r--src/doc/rustc/src/lints/listing/deny-by-default.md41
-rw-r--r--src/doc/rustdoc/src/the-doc-attribute.md15
-rw-r--r--src/doc/rustdoc/src/what-is-rustdoc.md20
-rw-r--r--src/etc/natvis/liballoc.natvis12
-rw-r--r--src/etc/natvis/libcore.natvis8
-rw-r--r--src/liballoc/Cargo.toml1
-rw-r--r--src/liballoc/alloc.rs18
-rw-r--r--src/liballoc/collections/binary_heap.rs58
-rw-r--r--src/liballoc/collections/btree/map.rs40
-rw-r--r--src/liballoc/collections/btree/set.rs15
-rw-r--r--src/liballoc/collections/vec_deque.rs26
-rw-r--r--src/liballoc/lib.rs2
-rw-r--r--src/liballoc/rc.rs5
-rw-r--r--src/liballoc/string.rs26
-rw-r--r--src/liballoc/sync.rs5
-rw-r--r--src/liballoc/tests/btree/set.rs4
-rw-r--r--src/liballoc/tests/lib.rs1
-rw-r--r--src/liballoc/vec.rs28
-rw-r--r--src/libcore/alloc.rs6
-rw-r--r--src/libcore/array.rs9
-rw-r--r--src/libcore/ascii.rs2
-rw-r--r--src/libcore/convert.rs40
-rw-r--r--src/libcore/fmt/mod.rs4
-rw-r--r--src/libcore/future/future.rs2
-rw-r--r--src/libcore/iter/adapters/mod.rs5
-rw-r--r--src/libcore/iter/traits/iterator.rs32
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libcore/mem.rs412
-rw-r--r--src/libcore/ptr.rs23
-rw-r--r--src/libcore/slice/mod.rs26
-rw-r--r--src/libcore/str/mod.rs24
-rw-r--r--src/libcore/task/wake.rs23
-rw-r--r--src/libcore/tests/alloc.rs10
-rw-r--r--src/libcore/tests/lib.rs4
-rw-r--r--src/librustc/Cargo.toml2
-rw-r--r--src/librustc/cfg/construct.rs41
-rw-r--r--src/librustc/hir/check_attr.rs39
-rw-r--r--src/librustc/hir/def_id.rs46
-rw-r--r--src/librustc/hir/intravisit.rs5
-rw-r--r--src/librustc/hir/lowering.rs277
-rw-r--r--src/librustc/hir/map/collector.rs2
-rw-r--r--src/librustc/hir/map/definitions.rs36
-rw-r--r--src/librustc/hir/map/mod.rs8
-rw-r--r--src/librustc/hir/mod.rs25
-rw-r--r--src/librustc/hir/print.rs114
-rw-r--r--src/librustc/ich/hcx.rs2
-rw-r--r--src/librustc/ich/impls_syntax.rs42
-rw-r--r--src/librustc/ich/mod.rs20
-rw-r--r--src/librustc/infer/error_reporting/mod.rs6
-rw-r--r--src/librustc/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--src/librustc/infer/lexical_region_resolve/graphviz.rs4
-rw-r--r--src/librustc/infer/opaque_types/mod.rs56
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc/lint/context.rs9
-rw-r--r--src/librustc/lint/levels.rs10
-rw-r--r--src/librustc/lint/mod.rs18
-rw-r--r--src/librustc/middle/dead.rs9
-rw-r--r--src/librustc/middle/entry.rs9
-rw-r--r--src/librustc/middle/expr_use_visitor.rs8
-rw-r--r--src/librustc/middle/lang_items.rs8
-rw-r--r--src/librustc/middle/lib_features.rs12
-rw-r--r--src/librustc/middle/liveness.rs29
-rw-r--r--src/librustc/middle/mem_categorization.rs5
-rw-r--r--src/librustc/middle/recursion_limit.rs7
-rw-r--r--src/librustc/middle/region.rs13
-rw-r--r--src/librustc/middle/resolve_lifetime.rs4
-rw-r--r--src/librustc/middle/stability.rs14
-rw-r--r--src/librustc/middle/weak_lang_items.rs6
-rw-r--r--src/librustc/mir/interpret/pointer.rs2
-rw-r--r--src/librustc/mir/interpret/value.rs4
-rw-r--r--src/librustc/mir/mod.rs9
-rw-r--r--src/librustc/mir/mono.rs6
-rw-r--r--src/librustc/mir/tcx.rs6
-rw-r--r--src/librustc/query/mod.rs2
-rw-r--r--src/librustc/session/config.rs6
-rw-r--r--src/librustc/session/mod.rs3
-rw-r--r--src/librustc/traits/coherence.rs9
-rw-r--r--src/librustc/traits/error_reporting.rs12
-rw-r--r--src/librustc/traits/object_safety.rs5
-rw-r--r--src/librustc/traits/on_unimplemented.rs11
-rw-r--r--src/librustc/traits/project.rs7
-rw-r--r--src/librustc/traits/select.rs55
-rw-r--r--src/librustc/traits/specialize/mod.rs45
-rw-r--r--src/librustc/traits/structural_impls.rs14
-rw-r--r--src/librustc/ty/context.rs9
-rw-r--r--src/librustc/ty/inhabitedness/mod.rs22
-rw-r--r--src/librustc/ty/layout.rs383
-rw-r--r--src/librustc/ty/mod.rs16
-rw-r--r--src/librustc/ty/print/pretty.rs12
-rw-r--r--src/librustc/ty/query/values.rs4
-rw-r--r--src/librustc/ty/sty.rs6
-rw-r--r--src/librustc/ty/util.rs3
-rw-r--r--src/librustc/util/common.rs3
-rw-r--r--src/librustc_allocator/expand.rs17
-rw-r--r--src/librustc_codegen_llvm/abi.rs391
-rw-r--r--src/librustc_codegen_llvm/attributes.rs4
-rw-r--r--src/librustc_codegen_llvm/back/write.rs4
-rw-r--r--src/librustc_codegen_llvm/builder.rs7
-rw-r--r--src/librustc_codegen_llvm/consts.rs3
-rw-r--r--src/librustc_codegen_llvm/debuginfo/gdb.rs4
-rw-r--r--src/librustc_codegen_llvm/declare.rs4
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs4
-rw-r--r--src/librustc_codegen_llvm/llvm_util.rs135
-rw-r--r--src/librustc_codegen_llvm/type_.rs2
-rw-r--r--src/librustc_codegen_llvm/type_of.rs4
-rw-r--r--src/librustc_codegen_ssa/back/write.rs10
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs5
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs24
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs4
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs6
-rw-r--r--src/librustc_codegen_ssa/traits/abi.rs8
-rw-r--r--src/librustc_codegen_ssa/traits/builder.rs2
-rw-r--r--src/librustc_codegen_ssa/traits/mod.rs11
-rw-r--r--src/librustc_codegen_utils/lib.rs3
-rw-r--r--src/librustc_codegen_utils/link.rs5
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs12
-rw-r--r--src/librustc_codegen_utils/symbol_names_test.rs6
-rw-r--r--src/librustc_data_structures/flock.rs1
-rw-r--r--src/librustc_data_structures/macros.rs9
-rw-r--r--src/librustc_data_structures/stable_hasher.rs44
-rw-r--r--src/librustc_driver/lib.rs3
-rw-r--r--src/librustc_driver/pretty.rs8
-rw-r--r--src/librustc_errors/diagnostic_builder.rs12
-rw-r--r--src/librustc_incremental/assert_module_sources.rs9
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs13
-rw-r--r--src/librustc_interface/passes.rs2
-rw-r--r--src/librustc_interface/proc_macro_decls.rs3
-rw-r--r--src/librustc_interface/util.rs34
-rw-r--r--src/librustc_lint/builtin.rs22
-rw-r--r--src/librustc_lint/lib.rs7
-rw-r--r--src/librustc_lint/nonstandard_style.rs7
-rw-r--r--src/librustc_lint/types.rs10
-rw-r--r--src/librustc_lint/unused.rs10
-rw-r--r--src/librustc_macros/src/symbols.rs43
-rw-r--r--src/librustc_metadata/creader.rs23
-rw-r--r--src/librustc_metadata/cstore_impl.rs4
-rw-r--r--src/librustc_metadata/decoder.rs6
-rw-r--r--src/librustc_metadata/encoder.rs20
-rw-r--r--src/librustc_metadata/index.rs4
-rw-r--r--src/librustc_metadata/link_args.rs5
-rw-r--r--src/librustc_metadata/locator.rs9
-rw-r--r--src/librustc_metadata/native_libs.rs20
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs37
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs3
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs84
-rw-r--r--src/librustc_mir/build/expr/as_place.rs1
-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.rs37
-rw-r--r--src/librustc_mir/dataflow/mod.rs11
-rw-r--r--src/librustc_mir/hair/cx/expr.rs7
-rw-r--r--src/librustc_mir/hair/cx/mod.rs4
-rw-r--r--src/librustc_mir/hair/mod.rs5
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs27
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs7
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs5
-rw-r--r--src/librustc_mir/interpret/cast.rs6
-rw-r--r--src/librustc_mir/interpret/eval_context.rs4
-rw-r--r--src/librustc_mir/monomorphize/item.rs4
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs45
-rw-r--r--src/librustc_mir/transform/const_prop.rs244
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs25
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs11
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs6
-rw-r--r--src/librustc_mir/util/graphviz.rs4
-rw-r--r--src/librustc_passes/ast_validation.rs30
-rw-r--r--src/librustc_passes/layout_test.rs13
-rw-r--r--src/librustc_passes/rvalue_promotion.rs12
-rw-r--r--src/librustc_plugin/build.rs4
-rw-r--r--src/librustc_plugin/load.rs11
-rw-r--r--src/librustc_plugin/registry.rs8
-rw-r--r--src/librustc_privacy/lib.rs7
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs26
-rw-r--r--src/librustc_resolve/lib.rs29
-rw-r--r--src/librustc_resolve/macros.rs30
-rw-r--r--src/librustc_resolve/resolve_imports.rs13
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs10
-rw-r--r--src/librustc_save_analysis/lib.rs10
-rw-r--r--src/librustc_target/spec/apple_base.rs17
-rw-r--r--src/librustc_target/spec/bitrig_base.rs16
-rw-r--r--src/librustc_target/spec/mod.rs5
-rw-r--r--src/librustc_target/spec/wasm32_wasi.rs (renamed from src/librustc_target/spec/wasm32_unknown_wasi.rs)34
-rw-r--r--src/librustc_target/spec/x86_64_unknown_bitrig.rs23
-rw-r--r--src/librustc_traits/lowering/mod.rs5
-rw-r--r--src/librustc_typeck/astconv.rs28
-rw-r--r--src/librustc_typeck/check/_match.rs467
-rw-r--r--src/librustc_typeck/check/coercion.rs11
-rw-r--r--src/librustc_typeck/check/demand.rs3
-rw-r--r--src/librustc_typeck/check/intrinsic.rs6
-rw-r--r--src/librustc_typeck/check/method/suggest.rs57
-rw-r--r--src/librustc_typeck/check/mod.rs247
-rw-r--r--src/librustc_typeck/check/op.rs83
-rw-r--r--src/librustc_typeck/check/wfcheck.rs3
-rw-r--r--src/librustc_typeck/check/writeback.rs57
-rw-r--r--src/librustc_typeck/check_unused.rs7
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs38
-rw-r--r--src/librustc_typeck/collect.rs116
-rw-r--r--src/librustc_typeck/outlives/mod.rs3
-rw-r--r--src/librustc_typeck/outlives/test.rs3
-rw-r--r--src/librustc_typeck/variance/test.rs3
-rw-r--r--src/librustdoc/clean/cfg.rs33
-rw-r--r--src/librustdoc/clean/inline.rs3
-rw-r--r--src/librustdoc/clean/mod.rs80
-rw-r--r--src/librustdoc/config.rs28
-rw-r--r--src/librustdoc/core.rs19
-rw-r--r--src/librustdoc/externalfiles.rs9
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/librustdoc/html/highlight.rs2
-rw-r--r--src/librustdoc/html/layout.rs6
-rw-r--r--src/librustdoc/html/markdown.rs71
-rw-r--r--src/librustdoc/html/render.rs130
-rw-r--r--src/librustdoc/html/static/main.js6
-rw-r--r--src/librustdoc/html/static/rustdoc.css452
-rw-r--r--src/librustdoc/html/static/themes/dark.css7
-rw-r--r--src/librustdoc/html/static/themes/light.css8
-rw-r--r--src/librustdoc/lib.rs11
-rw-r--r--src/librustdoc/markdown.rs12
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs36
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs5
-rw-r--r--src/librustdoc/passes/mod.rs19
-rw-r--r--src/librustdoc/passes/strip_hidden.rs3
-rw-r--r--src/librustdoc/test.rs59
-rw-r--r--src/librustdoc/visit_ast.rs26
-rw-r--r--src/librustdoc/visit_lib.rs3
-rw-r--r--src/libstd/Cargo.toml6
-rw-r--r--src/libstd/alloc.rs5
-rw-r--r--src/libstd/build.rs3
-rw-r--r--src/libstd/collections/hash/map.rs11
-rw-r--r--src/libstd/collections/hash/set.rs56
-rw-r--r--src/libstd/env.rs7
-rw-r--r--src/libstd/error.rs35
-rw-r--r--src/libstd/ffi/c_str.rs9
-rw-r--r--src/libstd/ffi/os_str.rs2
-rw-r--r--src/libstd/fs.rs2
-rw-r--r--src/libstd/io/buffered.rs2
-rw-r--r--src/libstd/io/mod.rs13
-rw-r--r--src/libstd/keyword_docs.rs294
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/macros.rs55
-rw-r--r--src/libstd/net/addr.rs17
-rw-r--r--src/libstd/net/tcp.rs4
-rw-r--r--src/libstd/net/udp.rs4
-rw-r--r--src/libstd/os/bitrig/fs.rs138
-rw-r--r--src/libstd/os/bitrig/mod.rs6
-rw-r--r--src/libstd/os/bitrig/raw.rs71
-rw-r--r--src/libstd/os/mod.rs1
-rw-r--r--src/libstd/path.rs10
-rw-r--r--src/libstd/sync/mpsc/mod.rs85
-rw-r--r--src/libstd/sync/mpsc/oneshot.rs72
-rw-r--r--src/libstd/sync/mpsc/select.rs352
-rw-r--r--src/libstd/sync/mpsc/select_tests.rs413
-rw-r--r--src/libstd/sync/mpsc/shared.rs35
-rw-r--r--src/libstd/sync/mpsc/stream.rs53
-rw-r--r--src/libstd/sync/mpsc/sync.rs37
-rw-r--r--src/libstd/sync/mutex.rs2
-rw-r--r--src/libstd/sync/rwlock.rs2
-rw-r--r--src/libstd/sys/unix/args.rs3
-rw-r--r--src/libstd/sys/unix/env.rs11
-rw-r--r--src/libstd/sys/unix/ext/net.rs4
-rw-r--r--src/libstd/sys/unix/fs.rs10
-rw-r--r--src/libstd/sys/unix/mod.rs1
-rw-r--r--src/libstd/sys/unix/os.rs5
-rw-r--r--src/libstd/sys/unix/rand.rs12
-rw-r--r--src/libstd/sys/unix/stack_overflow.rs3
-rw-r--r--src/libstd/sys/unix/thread.rs9
-rw-r--r--src/libstd/sys/wasm/args.rs4
-rw-r--r--src/libstd/sys/windows/args.rs2
-rw-r--r--src/libstd/sys_common/net.rs4
-rw-r--r--src/libstd/thread/mod.rs1
-rw-r--r--src/libsyntax/ast.rs32
-rw-r--r--src/libsyntax/attr/builtin.rs121
-rw-r--r--src/libsyntax/attr/mod.rs141
-rw-r--r--src/libsyntax/config.rs11
-rw-r--r--src/libsyntax/diagnostics/plugin.rs6
-rw-r--r--src/libsyntax/entry.rs7
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/build.rs11
-rw-r--r--src/libsyntax/ext/derive.rs4
-rw-r--r--src/libsyntax/ext/expand.rs46
-rw-r--r--src/libsyntax/ext/source_util.rs4
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs37
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs16
-rw-r--r--src/libsyntax/feature_gate.rs470
-rw-r--r--src/libsyntax/mut_visit.rs4
-rw-r--r--src/libsyntax/parse/classify.rs13
-rw-r--r--src/libsyntax/parse/diagnostics.rs304
-rw-r--r--src/libsyntax/parse/lexer/comments.rs29
-rw-r--r--src/libsyntax/parse/lexer/mod.rs45
-rw-r--r--src/libsyntax/parse/lexer/tokentrees.rs67
-rw-r--r--src/libsyntax/parse/literal.rs487
-rw-r--r--src/libsyntax/parse/mod.rs329
-rw-r--r--src/libsyntax/parse/parser.rs540
-rw-r--r--src/libsyntax/parse/token.rs30
-rw-r--r--src/libsyntax/print/pprust.rs170
-rw-r--r--src/libsyntax/std_inject.rs36
-rw-r--r--src/libsyntax/test.rs31
-rw-r--r--src/libsyntax/tokenstream.rs4
-rw-r--r--src/libsyntax_ext/asm.rs12
-rw-r--r--src/libsyntax_ext/concat_idents.rs4
-rw-r--r--src/libsyntax_ext/deriving/clone.rs4
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs8
-rw-r--r--src/libsyntax_ext/deriving/mod.rs4
-rw-r--r--src/libsyntax_ext/env.rs5
-rw-r--r--src/libsyntax_ext/format.rs6
-rw-r--r--src/libsyntax_ext/global_asm.rs4
-rw-r--r--src/libsyntax_ext/log_syntax.rs3
-rw-r--r--src/libsyntax_ext/proc_macro_decls.rs29
-rw-r--r--src/libsyntax_ext/test.rs14
-rw-r--r--src/libsyntax_ext/test_case.rs4
-rw-r--r--src/libsyntax_ext/trace_macros.rs4
-rw-r--r--src/libsyntax_pos/edition.rs7
-rw-r--r--src/libsyntax_pos/hygiene.rs5
-rw-r--r--src/libsyntax_pos/lib.rs6
-rw-r--r--src/libsyntax_pos/symbol.rs596
-rw-r--r--src/libtest/lib.rs10
-rw-r--r--src/libunwind/build.rs9
m---------src/llvm-project0
-rw-r--r--src/test/codegen/box-maybe-uninit.rs1
-rw-r--r--src/test/codegen/dllimports/main.rs2
-rw-r--r--src/test/codegen/enum-debug-niche-2.rs1
-rw-r--r--src/test/codegen/i686-no-macosx-deployment-target.rs2
-rw-r--r--src/test/codegen/panic-abort-windows.rs2
-rw-r--r--src/test/codegen/x86_64-no-macosx-deployment-target.rs2
-rw-r--r--src/test/incremental/foreign.rs1
-rw-r--r--src/test/incremental/hashes/closure_expressions.rs4
-rw-r--r--src/test/incremental/hashes/if_expressions.rs4
-rw-r--r--src/test/incremental/issue-60629.rs10
-rw-r--r--src/test/incremental/no_mangle.rs10
-rw-r--r--src/test/mir-opt/const_prop/array_index.rs33
-rw-r--r--src/test/mir-opt/const_prop/checked_add.rs21
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs34
-rw-r--r--src/test/mir-opt/const_prop/slice_len.rs37
-rw-r--r--src/test/mir-opt/const_prop/switch_int.rs38
-rw-r--r--src/test/mir-opt/issue-38669.rs8
-rw-r--r--src/test/mir-opt/loop_test.rs21
-rw-r--r--src/test/mir-opt/nll/region-subtyping-basic.rs6
-rw-r--r--src/test/mir-opt/remove_fake_borrows.rs2
-rw-r--r--src/test/mir-opt/simplify_if.rs12
-rw-r--r--src/test/run-fail/issue-51345.rs2
-rw-r--r--src/test/run-make-fulldeps/issue-14500/Makefile4
-rw-r--r--src/test/run-make-fulldeps/link-cfg/Makefile2
-rw-r--r--src/test/run-make-fulldeps/linker-output-non-utf8/Makefile2
-rw-r--r--src/test/run-make-fulldeps/reproducible-build/Makefile4
-rw-r--r--src/test/run-make-fulldeps/tools.mk5
-rw-r--r--src/test/run-make-fulldeps/use-extern-for-plugins/Makefile1
-rw-r--r--src/test/run-make/rustc-macro-dep-files/Makefile5
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs4
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs4
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs7
-rw-r--r--src/test/run-pass-valgrind/exit-flushes.rs1
-rw-r--r--src/test/run-pass/abort-on-c-abi.rs1
-rw-r--r--src/test/run-pass/atomic-print.rs1
-rw-r--r--src/test/run-pass/backtrace-debuginfo.rs2
-rw-r--r--src/test/run-pass/backtrace.rs1
-rw-r--r--src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs2
-rw-r--r--src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs1
-rw-r--r--src/test/run-pass/borrowck/two-phase-bin-ops.rs4
-rw-r--r--src/test/run-pass/c-stack-returning-int64.rs1
-rw-r--r--src/test/run-pass/cfg/cfg-family.rs1
-rw-r--r--src/test/run-pass/cfg/cfg-target-family.rs1
-rw-r--r--src/test/run-pass/command-exec.rs1
-rw-r--r--src/test/run-pass/command-pre-exec.rs1
-rw-r--r--src/test/run-pass/consts/const-ptr-nonnull.rs2
-rw-r--r--src/test/run-pass/core-run-destroy.rs1
-rw-r--r--src/test/run-pass/default-alloc-error-hook.rs1
-rw-r--r--src/test/run-pass/dupe-first-attr.rc3
-rw-r--r--src/test/run-pass/env-args-reverse-iterator.rs1
-rw-r--r--src/test/run-pass/env-funky-keys.rs1
-rw-r--r--src/test/run-pass/env-home-dir.rs1
-rw-r--r--src/test/run-pass/exec-env.rs1
-rw-r--r--src/test/run-pass/fds-are-cloexec.rs1
-rw-r--r--src/test/run-pass/foreign/foreign-fn-linkname.rs1
-rw-r--r--src/test/run-pass/functions-closures/parallel-codegen-closures.rs1
-rw-r--r--src/test/run-pass/if-ret.stderr8
-rw-r--r--src/test/run-pass/impl-trait-in-bindings.rs1
-rw-r--r--src/test/run-pass/impl-trait-in-bindings.stderr6
-rw-r--r--src/test/run-pass/impl-trait/lifetimes.rs6
-rw-r--r--src/test/run-pass/inherit-env.rs1
-rw-r--r--src/test/run-pass/intrinsics/intrinsic-alignment.rs2
-rw-r--r--src/test/run-pass/invalid_const_promotion.rs1
-rw-r--r--src/test/run-pass/issue-59020.rs1
-rw-r--r--src/test/run-pass/issues/issue-10626.rs1
-rw-r--r--src/test/run-pass/issues/issue-12133-3.rs1
-rw-r--r--src/test/run-pass/issues/issue-12699.rs1
-rw-r--r--src/test/run-pass/issues/issue-13304.rs1
-rw-r--r--src/test/run-pass/issues/issue-13494.rs35
-rw-r--r--src/test/run-pass/issues/issue-14456.rs1
-rw-r--r--src/test/run-pass/issues/issue-14940.rs1
-rw-r--r--src/test/run-pass/issues/issue-16272.rs1
-rw-r--r--src/test/run-pass/issues/issue-2214.rs2
-rw-r--r--src/test/run-pass/issues/issue-24313.rs1
-rw-r--r--src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs1
-rw-r--r--src/test/run-pass/issues/issue-30490.rs1
-rw-r--r--src/test/run-pass/issues/issue-33770.rs1
-rw-r--r--src/test/run-pass/issues/issue-48962.rs1
-rw-r--r--src/test/run-pass/issues/issue-51345.rs1
-rw-r--r--src/test/run-pass/issues/issue-9396.rs1
-rw-r--r--src/test/run-pass/linkage1.rs1
-rw-r--r--src/test/run-pass/macros/macro-comma-support.rs2
-rw-r--r--src/test/run-pass/mpsc_stress.rs1
-rw-r--r--src/test/run-pass/multi-panic.rs1
-rw-r--r--src/test/run-pass/nll/issue-47153-generic-const.rs1
-rw-r--r--src/test/run-pass/nll/issue-47589.rs2
-rw-r--r--src/test/run-pass/nll/issue-48623-closure.rs2
-rw-r--r--src/test/run-pass/nll/issue-48623-generator.rs1
-rw-r--r--src/test/run-pass/nll/issue-50343.rs1
-rw-r--r--src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs1
-rw-r--r--src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs1
-rw-r--r--src/test/run-pass/nll/mutating_references.rs2
-rw-r--r--src/test/run-pass/nll/process_or_insert_default.rs2
-rw-r--r--src/test/run-pass/nll/rc-loop.rs2
-rw-r--r--src/test/run-pass/no-stdio.rs1
-rw-r--r--src/test/run-pass/out-of-stack.rs1
-rw-r--r--src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs1
-rw-r--r--src/test/run-pass/panic-runtime/abort.rs1
-rw-r--r--src/test/run-pass/panic-runtime/lto-abort.rs1
-rw-r--r--src/test/run-pass/panic-runtime/lto-unwind.rs1
-rw-r--r--src/test/run-pass/panic-uninitialized-zeroed.rs2
-rw-r--r--src/test/run-pass/paths-containing-nul.rs1
-rw-r--r--src/test/run-pass/print-stdout-eprint-stderr.rs1
-rw-r--r--src/test/run-pass/process/process-envs.rs1
-rw-r--r--src/test/run-pass/process/process-exit.rs1
-rw-r--r--src/test/run-pass/process/process-remove-from-env.rs1
-rw-r--r--src/test/run-pass/process/process-spawn-nonexistent.rs1
-rw-r--r--src/test/run-pass/process/process-spawn-with-unicode-params.rs1
-rw-r--r--src/test/run-pass/process/process-status-inherits-stdin.rs1
-rw-r--r--src/test/run-pass/rfcs/rfc-1014.rs1
-rw-r--r--src/test/run-pass/running-with-no-runtime.rs1
-rw-r--r--src/test/run-pass/segfault-no-out-of-stack.rs1
-rw-r--r--src/test/run-pass/sepcomp/sepcomp-cci.rs1
-rw-r--r--src/test/run-pass/sepcomp/sepcomp-extern.rs1
-rw-r--r--src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs1
-rw-r--r--src/test/run-pass/sepcomp/sepcomp-fns.rs1
-rw-r--r--src/test/run-pass/sepcomp/sepcomp-statics.rs1
-rw-r--r--src/test/run-pass/sepcomp/sepcomp-unwind.rs1
-rw-r--r--src/test/run-pass/signal-alternate-stack-cleanup.rs1
-rw-r--r--src/test/run-pass/signal-exit-status.rs1
-rw-r--r--src/test/run-pass/sigpipe-should-be-ignored.rs1
-rw-r--r--src/test/run-pass/simd/simd-target-feature-mixup.rs1
-rw-r--r--src/test/run-pass/sleep.rs1
-rw-r--r--src/test/run-pass/stack-probes-lto.rs1
-rw-r--r--src/test/run-pass/stack-probes.rs1
-rw-r--r--src/test/run-pass/stdio-is-blocking.rs1
-rw-r--r--src/test/run-pass/structs-enums/rec-align-u64.rs2
-rw-r--r--src/test/run-pass/tcp-stress.rs2
-rw-r--r--src/test/run-pass/threads-sendsync/sync-send-in-std.rs1
-rw-r--r--src/test/run-pass/try-wait.rs1
-rw-r--r--src/test/run-pass/union/union-nonzero.rs51
-rw-r--r--src/test/run-pass/wait-forked-but-failed-child.rs1
-rw-r--r--src/test/run-pass/x86stdcall.rs3
-rw-r--r--src/test/rustdoc-ui/doc-without-codeblock.rs4
-rw-r--r--src/test/rustdoc-ui/doc-without-codeblock.stderr18
-rw-r--r--src/test/rustdoc-ui/lint-missing-doc-code-example.rs40
-rw-r--r--src/test/rustdoc-ui/lint-missing-doc-code-example.stderr21
-rw-r--r--src/test/rustdoc/async-move-doctest.rs14
-rw-r--r--src/test/rustdoc/attributes.rs4
-rw-r--r--src/test/rustdoc/generic-const.rs30
-rw-r--r--src/test/rustdoc/intra-link-libstd-re-export.rs3
-rw-r--r--src/test/rustdoc/playground-arg.rs2
-rw-r--r--src/test/rustdoc/playground.rs6
-rw-r--r--src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs8
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-for-crate.rs3
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs2
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-tool-test.rs4
-rw-r--r--src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr24
-rw-r--r--src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr24
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr24
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr10
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr24
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr24
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr11
-rw-r--r--src/test/ui/async-await/issue-60674.rs6
-rw-r--r--src/test/ui/async-await/issue-60674.stdout2
-rw-r--r--src/test/ui/attr-eq-token-tree.stderr4
-rw-r--r--src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs4
-rw-r--r--src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr10
-rw-r--r--src/test/ui/await-keyword/2018-edition-error.rs4
-rw-r--r--src/test/ui/await-keyword/2018-edition-error.stderr10
-rw-r--r--src/test/ui/await-keyword/incorrect-syntax-suggestions.rs111
-rw-r--r--src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr207
-rw-r--r--src/test/ui/await-keyword/post_expansion_error.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr40
-rw-r--r--src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr366
-rw-r--r--src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr27
-rw-r--r--src/test/ui/borrowck/borrowck-issue-48962.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-issue-48962.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr41
-rw-r--r--src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr23
-rw-r--r--src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr12
-rw-r--r--src/test/ui/borrowck/issue-10876.rs2
-rw-r--r--src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs2
-rw-r--r--src/test/ui/borrowck/issue-52713-bug.rs2
-rw-r--r--src/test/ui/borrowck/issue-52713-bug.stderr2
-rw-r--r--src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs2
-rw-r--r--src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr2
-rw-r--r--src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs12
-rw-r--r--src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr (renamed from src/test/ui/borrowck/issue-58776-borrowck-scans-children.nll.stderr)4
-rw-r--r--src/test/ui/borrowck/issue-7573.nll.stderr14
-rw-r--r--src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr12
-rw-r--r--src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr12
-rw-r--r--src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr12
-rw-r--r--src/test/ui/borrowck/two-phase-across-loop.rs2
-rw-r--r--src/test/ui/borrowck/two-phase-across-loop.stderr2
-rw-r--r--src/test/ui/borrowck/two-phase-multi-mut.rs2
-rw-r--r--src/test/ui/borrowck/two-phase-multi-mut.stderr4
-rw-r--r--src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr36
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-4.nll.stderr (renamed from src/test/ui/c-variadic/variadic-ffi-5.stderr)44
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-5.rs31
-rw-r--r--src/test/ui/cdylib-deps-must-be-static.rs2
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr53
-rw-r--r--src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr37
-rw-r--r--src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr42
-rw-r--r--src/test/ui/const-generics/cannot-infer-type-for-const-param.rs11
-rw-r--r--src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr15
-rw-r--r--src/test/ui/const-generics/impl-const-generic-struct.rs16
-rw-r--r--src/test/ui/const-generics/impl-const-generic-struct.stderr6
-rw-r--r--src/test/ui/const-generics/invalid-const-arg-for-type-param.rs9
-rw-r--r--src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr25
-rw-r--r--src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs2
-rw-r--r--src/test/ui/consts/const_let_refutable.nll.stderr31
-rw-r--r--src/test/ui/consts/issue-54224.rs2
-rw-r--r--src/test/ui/consts/issue-54224.stderr4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr328
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr31
-rw-r--r--src/test/ui/consts/promote_evaluation_unused_result.rs2
-rw-r--r--src/test/ui/consts/promote_fn_calls.rs2
-rw-r--r--src/test/ui/consts/promote_fn_calls_std.rs2
-rw-r--r--src/test/ui/consts/std/alloc.rs10
-rw-r--r--src/test/ui/consts/std/alloc.stderr11
-rw-r--r--src/test/ui/continue-after-missing-main.nll.stderr7
-rw-r--r--src/test/ui/empty/empty-never-array.nll.stderr23
-rw-r--r--src/test/ui/error-codes/E0502.nll.stderr13
-rw-r--r--src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr11
-rw-r--r--src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr4
-rw-r--r--src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr4
-rw-r--r--src/test/ui/existential-type/issue-60371.rs15
-rw-r--r--src/test/ui/existential-type/issue-60371.stderr29
-rw-r--r--src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr18
-rw-r--r--src/test/ui/existential_types/issue-60655-latebound-regions.rs30
-rw-r--r--src/test/ui/feature-gate/await-macro.stderr2
-rw-r--r--src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs2
-rw-r--r--src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr6
-rw-r--r--src/test/ui/generator/auto-trait-regions.nll.stderr41
-rw-r--r--src/test/ui/generator/generator-region-requirements.rs7
-rw-r--r--src/test/ui/generator/generator-region-requirements.stderr (renamed from src/test/ui/generator/generator-region-requirements.nll.stderr)2
-rw-r--r--src/test/ui/generator/generator-with-nll.rs1
-rw-r--r--src/test/ui/generator/generator-with-nll.stderr2
-rw-r--r--src/test/ui/hashmap-iter-value-lifetime.nll.stderr15
-rw-r--r--src/test/ui/hashmap-lifetimes.nll.stderr13
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr30
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr16
-rw-r--r--src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr77
-rw-r--r--src/test/ui/if/if-let-arm-types.rs5
-rw-r--r--src/test/ui/if/if-let-arm-types.stderr8
-rw-r--r--src/test/ui/if/if-no-match-bindings.rs22
-rw-r--r--src/test/ui/if/if-no-match-bindings.stderr39
-rw-r--r--src/test/ui/if/if-without-else-as-fn-expr.rs30
-rw-r--r--src/test/ui/if/if-without-else-as-fn-expr.stderr123
-rw-r--r--src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr10
-rw-r--r--src/test/ui/impl-trait/bindings-opaque.rs1
-rw-r--r--src/test/ui/impl-trait/bindings-opaque.stderr12
-rw-r--r--src/test/ui/impl-trait/bindings.rs1
-rw-r--r--src/test/ui/impl-trait/bindings.stderr14
-rw-r--r--src/test/ui/impl-trait/can-return-unconstrained-closure.rs4
-rw-r--r--src/test/ui/impl-trait/closure-calling-parent-fn.rs2
-rw-r--r--src/test/ui/impl-trait/issue-57464-unexpected-regions.rs7
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr51
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs1
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs1
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.rs1
-rw-r--r--src/test/ui/impl-trait/region-escape-via-bound.stderr6
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr26
-rw-r--r--src/test/ui/impl-trait/type_parameters_captured.nll.stderr11
-rw-r--r--src/test/ui/imports/extern-crate-used.rs12
-rw-r--r--src/test/ui/imports/extern-crate-used.stderr34
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched.nll.stderr20
-rw-r--r--src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr24
-rw-r--r--src/test/ui/issue-60622.rs18
-rw-r--r--src/test/ui/issue-60622.stderr27
-rw-r--r--src/test/ui/issues/issue-10291.nll.stderr11
-rw-r--r--src/test/ui/issues/issue-13058.nll.stderr12
-rw-r--r--src/test/ui/issues/issue-15034.nll.stderr11
-rw-r--r--src/test/ui/issues/issue-15381.nll.stderr16
-rw-r--r--src/test/ui/issues/issue-16683.nll.stderr10
-rw-r--r--src/test/ui/issues/issue-17728.nll.stderr21
-rw-r--r--src/test/ui/issues/issue-17758.nll.stderr10
-rw-r--r--src/test/ui/issues/issue-19991.stderr3
-rw-r--r--src/test/ui/issues/issue-20091.rs1
-rw-r--r--src/test/ui/issues/issue-26217.nll.stderr10
-rw-r--r--src/test/ui/issues/issue-28848.nll.stderr12
-rw-r--r--src/test/ui/issues/issue-32709.stderr1
-rw-r--r--src/test/ui/issues/issue-34721.rs2
-rw-r--r--src/test/ui/issues/issue-34721.stderr2
-rw-r--r--src/test/ui/issues/issue-39175.rs1
-rw-r--r--src/test/ui/issues/issue-39175.stderr2
-rw-r--r--src/test/ui/issues/issue-40510-1.migrate.nll.stderr13
-rw-r--r--src/test/ui/issues/issue-40510-1.migrate.stderr (renamed from src/test/ui/issues/issue-40510-1.stderr)10
-rw-r--r--src/test/ui/issues/issue-40510-1.nll.stderr13
-rw-r--r--src/test/ui/issues/issue-40510-1.rs12
-rw-r--r--src/test/ui/issues/issue-40510-3.migrate.nll.stderr15
-rw-r--r--src/test/ui/issues/issue-40510-3.migrate.stderr (renamed from src/test/ui/issues/issue-40510-3.stderr)10
-rw-r--r--src/test/ui/issues/issue-40510-3.nll.stderr15
-rw-r--r--src/test/ui/issues/issue-40510-3.rs12
-rw-r--r--src/test/ui/issues/issue-43355.rs1
-rw-r--r--src/test/ui/issues/issue-43355.stderr6
-rw-r--r--src/test/ui/issues/issue-45696-no-variant-box-recur.rs5
-rw-r--r--src/test/ui/issues/issue-46036.rs1
-rw-r--r--src/test/ui/issues/issue-46036.stderr2
-rw-r--r--src/test/ui/issues/issue-46983.rs2
-rw-r--r--src/test/ui/issues/issue-46983.stderr2
-rw-r--r--src/test/ui/issues/issue-47184.rs2
-rw-r--r--src/test/ui/issues/issue-47184.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-47646.rs3
-rw-r--r--src/test/ui/issues/issue-47646.stderr2
-rw-r--r--src/test/ui/issues/issue-47703-1.rs2
-rw-r--r--src/test/ui/issues/issue-47703-tuple.rs2
-rw-r--r--src/test/ui/issues/issue-47703.rs2
-rw-r--r--src/test/ui/issues/issue-47722.rs2
-rw-r--r--src/test/ui/issues/issue-47789.rs3
-rw-r--r--src/test/ui/issues/issue-48132.rs3
-rw-r--r--src/test/ui/issues/issue-48179.rs3
-rw-r--r--src/test/ui/issues/issue-48803.rs2
-rw-r--r--src/test/ui/issues/issue-48803.stderr2
-rw-r--r--src/test/ui/issues/issue-49579.rs2
-rw-r--r--src/test/ui/issues/issue-49824.nll.stderr18
-rw-r--r--src/test/ui/issues/issue-50577.rs1
-rw-r--r--src/test/ui/issues/issue-50577.stderr15
-rw-r--r--src/test/ui/issues/issue-51515.rs2
-rw-r--r--src/test/ui/issues/issue-51515.stderr4
-rw-r--r--src/test/ui/issues/issue-51719.rs2
-rw-r--r--src/test/ui/issues/issue-51719.stderr4
-rw-r--r--src/test/ui/issues/issue-51751.stderr5
-rw-r--r--src/test/ui/issues/issue-52057.rs2
-rw-r--r--src/test/ui/issues/issue-52213.nll.stderr13
-rw-r--r--src/test/ui/issues/issue-52533-1.nll.stderr11
-rw-r--r--src/test/ui/issues/issue-52533.nll.stderr11
-rw-r--r--src/test/ui/issues/issue-52992.rs2
-rw-r--r--src/test/ui/issues/issue-53498.rs17
-rw-r--r--src/test/ui/issues/issue-53498.stderr9
-rw-r--r--src/test/ui/issues/issue-53568.rs3
-rw-r--r--src/test/ui/issues/issue-54302-cases.nll.stderr26
-rw-r--r--src/test/ui/issues/issue-54302.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-54943-1.rs2
-rw-r--r--src/test/ui/issues/issue-54943-2.rs2
-rw-r--r--src/test/ui/issues/issue-54943.nll.stderr11
-rw-r--r--src/test/ui/issues/issue-54943.rs5
-rw-r--r--src/test/ui/issues/issue-54943.stderr11
-rw-r--r--src/test/ui/issues/issue-55731.nll.stderr11
-rw-r--r--src/test/ui/issues/issue-55796.nll.stderr20
-rw-r--r--src/test/ui/issues/issue-57843.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-60662.rs11
-rw-r--r--src/test/ui/issues/issue-60662.stdout14
-rw-r--r--src/test/ui/kindck/kindck-impl-type-params.nll.stderr63
-rw-r--r--src/test/ui/kindck/kindck-send-object1.nll.stderr32
-rw-r--r--src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr20
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr11
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr11
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr22
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr13
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr21
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr21
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr12
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr21
-rw-r--r--src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr12
-rw-r--r--src/test/ui/linkage2.rs1
-rw-r--r--src/test/ui/linkage2.stderr2
-rw-r--r--src/test/ui/lub-if.nll.stderr20
-rw-r--r--src/test/ui/lub-match.nll.stderr20
-rw-r--r--src/test/ui/macros/macro-attribute.stderr4
-rw-r--r--src/test/ui/malformed/malformed-interpolated.rs5
-rw-r--r--src/test/ui/malformed/malformed-interpolated.stderr17
-rw-r--r--src/test/ui/match/match-ref-mut-invariance.nll.stderr12
-rw-r--r--src/test/ui/match/match-ref-mut-let-invariance.nll.stderr13
-rw-r--r--src/test/ui/mir-dataflow/def-inits-1.rs1
-rw-r--r--src/test/ui/mir-dataflow/def-inits-1.stderr8
-rw-r--r--src/test/ui/mir-dataflow/inits-1.rs1
-rw-r--r--src/test/ui/mir-dataflow/inits-1.stderr6
-rw-r--r--src/test/ui/mir-dataflow/uninits-1.rs1
-rw-r--r--src/test/ui/mir-dataflow/uninits-1.stderr10
-rw-r--r--src/test/ui/mir-dataflow/uninits-2.rs1
-rw-r--r--src/test/ui/mir-dataflow/uninits-2.stderr2
-rw-r--r--src/test/ui/nll/borrow-use-issue-46875.rs2
-rw-r--r--src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs1
-rw-r--r--src/test/ui/nll/borrowed-local-error.rs2
-rw-r--r--src/test/ui/nll/borrowed-local-error.stderr2
-rw-r--r--src/test/ui/nll/borrowed-referent-issue-38899.rs1
-rw-r--r--src/test/ui/nll/borrowed-referent-issue-38899.stderr2
-rw-r--r--src/test/ui/nll/borrowed-temporary-error.rs2
-rw-r--r--src/test/ui/nll/borrowed-temporary-error.stderr2
-rw-r--r--src/test/ui/nll/borrowed-universal-error-2.rs3
-rw-r--r--src/test/ui/nll/borrowed-universal-error-2.stderr2
-rw-r--r--src/test/ui/nll/borrowed-universal-error.rs3
-rw-r--r--src/test/ui/nll/borrowed-universal-error.stderr2
-rw-r--r--src/test/ui/nll/capture-mut-ref.rs1
-rw-r--r--src/test/ui/nll/capture-mut-ref.stderr4
-rw-r--r--src/test/ui/nll/capture-ref-in-struct.rs3
-rw-r--r--src/test/ui/nll/capture-ref-in-struct.stderr2
-rw-r--r--src/test/ui/nll/closure-access-spans.rs2
-rw-r--r--src/test/ui/nll/closure-access-spans.stderr18
-rw-r--r--src/test/ui/nll/closure-borrow-spans.rs2
-rw-r--r--src/test/ui/nll/closure-borrow-spans.stderr28
-rw-r--r--src/test/ui/nll/closure-captures.rs3
-rw-r--r--src/test/ui/nll/closure-captures.stderr36
-rw-r--r--src/test/ui/nll/closure-move-spans.rs2
-rw-r--r--src/test/ui/nll/closure-move-spans.stderr6
-rw-r--r--src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs4
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr2
-rw-r--r--src/test/ui/nll/closure-use-spans.rs2
-rw-r--r--src/test/ui/nll/closure-use-spans.stderr6
-rw-r--r--src/test/ui/nll/closures-in-loops.rs2
-rw-r--r--src/test/ui/nll/closures-in-loops.stderr6
-rw-r--r--src/test/ui/nll/constant-thread-locals-issue-47053.rs1
-rw-r--r--src/test/ui/nll/constant-thread-locals-issue-47053.stderr2
-rw-r--r--src/test/ui/nll/decl-macro-illegal-copy.rs1
-rw-r--r--src/test/ui/nll/decl-macro-illegal-copy.stderr2
-rw-r--r--src/test/ui/nll/get_default.nll.stderr48
-rw-r--r--src/test/ui/nll/issue-16223.rs1
-rw-r--r--src/test/ui/nll/issue-21114-ebfull.rs2
-rw-r--r--src/test/ui/nll/issue-21114-kixunil.rs2
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs2
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr12
-rw-r--r--src/test/ui/nll/issue-22323-temp-destruction.rs2
-rw-r--r--src/test/ui/nll/issue-30104.rs2
-rw-r--r--src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs1
-rw-r--r--src/test/ui/nll/issue-43058.rs2
-rw-r--r--src/test/ui/nll/issue-46589.rs2
-rw-r--r--src/test/ui/nll/issue-46589.stderr2
-rw-r--r--src/test/ui/nll/issue-47022.rs3
-rw-r--r--src/test/ui/nll/issue-47388.rs1
-rw-r--r--src/test/ui/nll/issue-47388.stderr2
-rw-r--r--src/test/ui/nll/issue-47470.rs2
-rw-r--r--src/test/ui/nll/issue-47470.stderr2
-rw-r--r--src/test/ui/nll/issue-48070.rs2
-rw-r--r--src/test/ui/nll/issue-48697.rs2
-rw-r--r--src/test/ui/nll/issue-48697.stderr2
-rw-r--r--src/test/ui/nll/issue-50716-1.rs4
-rw-r--r--src/test/ui/nll/issue-50716.nll.stderr11
-rw-r--r--src/test/ui/nll/issue-50716.rs2
-rw-r--r--src/test/ui/nll/issue-50716.stderr19
-rw-r--r--src/test/ui/nll/issue-51191.rs2
-rw-r--r--src/test/ui/nll/issue-51191.stderr12
-rw-r--r--src/test/ui/nll/issue-51244.rs2
-rw-r--r--src/test/ui/nll/issue-51244.stderr2
-rw-r--r--src/test/ui/nll/issue-51268.rs2
-rw-r--r--src/test/ui/nll/issue-51268.stderr2
-rw-r--r--src/test/ui/nll/issue-51351.rs2
-rw-r--r--src/test/ui/nll/issue-51512.rs3
-rw-r--r--src/test/ui/nll/issue-51512.stderr2
-rw-r--r--src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs1
-rw-r--r--src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr8
-rw-r--r--src/test/ui/nll/issue-52078.rs3
-rw-r--r--src/test/ui/nll/issue-52086.rs2
-rw-r--r--src/test/ui/nll/issue-52086.stderr4
-rw-r--r--src/test/ui/nll/issue-52113.rs3
-rw-r--r--src/test/ui/nll/issue-52113.stderr2
-rw-r--r--src/test/ui/nll/issue-52534-1.rs3
-rw-r--r--src/test/ui/nll/issue-52534-1.stderr16
-rw-r--r--src/test/ui/nll/issue-52534-2.rs3
-rw-r--r--src/test/ui/nll/issue-52534-2.stderr2
-rw-r--r--src/test/ui/nll/issue-52534.rs3
-rw-r--r--src/test/ui/nll/issue-52534.stderr4
-rw-r--r--src/test/ui/nll/issue-52663-span-decl-captured-variable.rs2
-rw-r--r--src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr2
-rw-r--r--src/test/ui/nll/issue-52663-trait-object.rs1
-rw-r--r--src/test/ui/nll/issue-52663-trait-object.stderr2
-rw-r--r--src/test/ui/nll/issue-52669.rs2
-rw-r--r--src/test/ui/nll/issue-52669.stderr2
-rw-r--r--src/test/ui/nll/issue-52742.nll.stderr12
-rw-r--r--src/test/ui/nll/issue-52742.rs3
-rw-r--r--src/test/ui/nll/issue-52742.stderr24
-rw-r--r--src/test/ui/nll/issue-53119.rs2
-rw-r--r--src/test/ui/nll/issue-53570.rs4
-rw-r--r--src/test/ui/nll/issue-55288.rs2
-rw-r--r--src/test/ui/nll/issue-55344.rs2
-rw-r--r--src/test/ui/nll/issue-55394.nll.stderr12
-rw-r--r--src/test/ui/nll/issue-55394.rs4
-rw-r--r--src/test/ui/nll/issue-55394.stderr31
-rw-r--r--src/test/ui/nll/issue-55401.nll.stderr11
-rw-r--r--src/test/ui/nll/issue-55401.rs2
-rw-r--r--src/test/ui/nll/issue-55401.stderr16
-rw-r--r--src/test/ui/nll/issue-55850.rs2
-rw-r--r--src/test/ui/nll/issue-55850.stderr16
-rw-r--r--src/test/ui/nll/issue-57265-return-type-wf-check.rs2
-rw-r--r--src/test/ui/nll/issue-57265-return-type-wf-check.stderr2
-rw-r--r--src/test/ui/nll/issue-57280-1.rs2
-rw-r--r--src/test/ui/nll/issue-57280.rs2
-rw-r--r--src/test/ui/nll/issue-57989.rs2
-rw-r--r--src/test/ui/nll/issue-57989.stderr4
-rw-r--r--src/test/ui/nll/issue-58053.rs1
-rw-r--r--src/test/ui/nll/issue-58053.stderr4
-rw-r--r--src/test/ui/nll/issue-58299.rs1
-rw-r--r--src/test/ui/nll/issue-58299.stderr4
-rw-r--r--src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs3
-rw-r--r--src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr2
-rw-r--r--src/test/ui/nll/move-errors.rs3
-rw-r--r--src/test/ui/nll/move-errors.stderr44
-rw-r--r--src/test/ui/nll/move-subpaths-moves-root.rs2
-rw-r--r--src/test/ui/nll/move-subpaths-moves-root.stderr2
-rw-r--r--src/test/ui/nll/normalization-bounds-error.rs1
-rw-r--r--src/test/ui/nll/normalization-bounds-error.stderr10
-rw-r--r--src/test/ui/nll/normalization-bounds.rs1
-rw-r--r--src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs2
-rw-r--r--src/test/ui/nll/promoted-bounds.rs2
-rw-r--r--src/test/ui/nll/promoted-bounds.stderr2
-rw-r--r--src/test/ui/nll/promoted-closure-pair.rs2
-rw-r--r--src/test/ui/nll/promoted-closure-pair.stderr2
-rw-r--r--src/test/ui/nll/region-ends-after-if-condition.nll.stderr15
-rw-r--r--src/test/ui/nll/relate_tys/issue-48071.rs4
-rw-r--r--src/test/ui/nll/relate_tys/var-appears-twice.rs3
-rw-r--r--src/test/ui/nll/relate_tys/var-appears-twice.stderr2
-rw-r--r--src/test/ui/nll/return-ref-mut-issue-46557.rs3
-rw-r--r--src/test/ui/nll/return-ref-mut-issue-46557.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/issue-53789-1.rs3
-rw-r--r--src/test/ui/nll/ty-outlives/issue-53789-2.rs3
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr11
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr11
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr11
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env.rs2
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs30
-rw-r--r--src/test/ui/nll/type-alias-free-regions.nll.stderr22
-rw-r--r--src/test/ui/nll/type-alias-free-regions.rs2
-rw-r--r--src/test/ui/nll/type-alias-free-regions.stderr58
-rw-r--r--src/test/ui/nll/unused-mut-issue-50343.rs1
-rw-r--r--src/test/ui/nll/unused-mut-issue-50343.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-enums.rs2
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-enums.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-structs.rs2
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-structs.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.rs1
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-enums.rs1
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-enums.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-struct.rs2
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-struct.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/cast_static_lifetime.rs1
-rw-r--r--src/test/ui/nll/user-annotations/cast_static_lifetime.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr21
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr8
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr15
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr15
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr15
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs2
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr21
-rw-r--r--src/test/ui/nll/user-annotations/fns.rs2
-rw-r--r--src/test/ui/nll/user-annotations/fns.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs1
-rw-r--r--src/test/ui/nll/user-annotations/issue-55219.rs2
-rw-r--r--src/test/ui/nll/user-annotations/issue-55241.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-call.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-call.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-1.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-1.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-2.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-2.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-3.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-3.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs2
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/normalization.rs2
-rw-r--r--src/test/ui/nll/user-annotations/normalization.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/normalize-self-ty.rs2
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs2
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs2
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs2
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs2
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr4
-rw-r--r--src/test/ui/nll/user-annotations/promoted-annotation.rs2
-rw-r--r--src/test/ui/nll/user-annotations/promoted-annotation.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs1
-rw-r--r--src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr2
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr13
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr28
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr10
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr10
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr21
-rw-r--r--src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs1
-rw-r--r--src/test/ui/parser/attr-bad-meta-2.stderr4
-rw-r--r--src/test/ui/parser/pat-tuple-5.stderr4
-rw-r--r--src/test/ui/pattern/const-pat-ice.stderr2
-rw-r--r--src/test/ui/pattern/pattern-bindings-after-at.nll.stderr22
-rw-r--r--src/test/ui/print_type_sizes/niche-filling.rs17
-rw-r--r--src/test/ui/print_type_sizes/niche-filling.stdout26
-rw-r--r--src/test/ui/proc-macro/no-missing-docs.rs16
-rw-r--r--src/test/ui/reachable/expr_if.rs2
-rw-r--r--src/test/ui/reachable/expr_if.stderr20
-rw-r--r--src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr16
-rw-r--r--src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr11
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr12
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr12
-rw-r--r--src/test/ui/regions/region-object-lifetime-2.nll.stderr12
-rw-r--r--src/test/ui/regions/region-object-lifetime-4.nll.stderr12
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr38
-rw-r--r--src/test/ui/regions/regions-addr-of-self.nll.stderr10
-rw-r--r--src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr35
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr50
-rw-r--r--src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr10
-rw-r--r--src/test/ui/regions/regions-bounds.nll.stderr22
-rw-r--r--src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr36
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-2.nll.stderr20
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.nll.stderr37
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-5.nll.stderr29
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr20
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-close-param-into-object.nll.stderr36
-rw-r--r--src/test/ui/regions/regions-creating-enums3.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-creating-enums4.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-early-bound-error-method.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-early-bound-error.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-escape-method.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr24
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr33
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr15
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr (renamed from src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr)8
-rw-r--r--src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr19
-rw-r--r--src/test/ui/regions/regions-infer-call-3.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr10
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr10
-rw-r--r--src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr10
-rw-r--r--src/test/ui/regions/regions-infer-not-param.nll.stderr26
-rw-r--r--src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-nested-fns.nll.stderr51
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr24
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container.nll.stderr46
-rw-r--r--src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr12
-rw-r--r--src/test/ui/regions/regions-ret-borrowed-1.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-ret-borrowed.nll.stderr11
-rw-r--r--src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-static-bound.ll.nll.stderr28
-rw-r--r--src/test/ui/regions/regions-static-bound.migrate.nll.stderr28
-rw-r--r--src/test/ui/regions/regions-trait-object-subtyping.nll.stderr24
-rw-r--r--src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr13
-rw-r--r--src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr11
-rw-r--r--src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs1
-rw-r--r--src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs1
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr14
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs33
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs38
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr47
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs46
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr47
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs36
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs52
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr59
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs40
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs58
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs34
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs42
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr49
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs37
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs48
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs59
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs71
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr38
-rw-r--r--src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs31
-rw-r--r--src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed7
-rw-r--r--src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs5
-rw-r--r--src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr8
-rw-r--r--src/test/ui/rust-2018/remove-extern-crate.fixed6
-rw-r--r--src/test/ui/rust-2018/remove-extern-crate.rs4
-rw-r--r--src/test/ui/rust-2018/remove-extern-crate.stderr8
-rw-r--r--src/test/ui/save-analysis/issue-59134-0.rs12
-rw-r--r--src/test/ui/save-analysis/issue-59134-0.stderr9
-rw-r--r--src/test/ui/save-analysis/issue-59134-1.rs12
-rw-r--r--src/test/ui/save-analysis/issue-59134-1.stderr9
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.rs (renamed from src/test/ui/arbitrary-self-types-not-object-safe.rs)0
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.stderr (renamed from src/test/ui/arbitrary-self-types-not-object-safe.stderr)0
-rw-r--r--src/test/ui/self/arbitrary_self_types_pointers_and_wrappers.rs (renamed from src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs)1
-rw-r--r--src/test/ui/self/arbitrary_self_types_raw_pointer_struct.rs (renamed from src/test/run-pass/self/arbitrary_self_types_raw_pointer_struct.rs)0
-rw-r--r--src/test/ui/self/arbitrary_self_types_raw_pointer_trait.rs (renamed from src/test/run-pass/self/arbitrary_self_types_raw_pointer_trait.rs)0
-rw-r--r--src/test/ui/self/arbitrary_self_types_silly.rs (renamed from src/test/run-pass/self/arbitrary_self_types_silly.rs)0
-rw-r--r--src/test/ui/self/arbitrary_self_types_stdlib_pointers.rs (renamed from src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs)1
-rw-r--r--src/test/ui/self/arbitrary_self_types_struct.rs (renamed from src/test/run-pass/self/arbitrary_self_types_struct.rs)0
-rw-r--r--src/test/ui/self/arbitrary_self_types_trait.rs (renamed from src/test/run-pass/self/arbitrary_self_types_trait.rs)0
-rw-r--r--src/test/ui/self/arbitrary_self_types_unsized_struct.rs (renamed from src/test/run-pass/self/arbitrary_self_types_unsized_struct.rs)0
-rw-r--r--src/test/ui/self/auxiliary/explicit_self_xcrate.rs (renamed from src/test/run-pass/self/auxiliary/explicit_self_xcrate.rs)0
-rw-r--r--src/test/ui/self/builtin-superkinds-self-type.rs (renamed from src/test/run-pass/self/builtin-superkinds-self-type.rs)0
-rw-r--r--src/test/ui/self/by-value-self-in-mut-slot.rs (renamed from src/test/run-pass/self/by-value-self-in-mut-slot.rs)0
-rw-r--r--src/test/ui/self/explicit-self-closures.rs (renamed from src/test/run-pass/self/explicit-self-closures.rs)2
-rw-r--r--src/test/ui/self/explicit-self-generic.rs (renamed from src/test/run-pass/self/explicit-self-generic.rs)0
-rw-r--r--src/test/ui/self/explicit-self-objects-uniq.rs (renamed from src/test/run-pass/self/explicit-self-objects-uniq.rs)0
-rw-r--r--src/test/ui/self/explicit-self.rs (renamed from src/test/run-pass/self/explicit-self.rs)0
-rw-r--r--src/test/ui/self/explicit_self_xcrate_exe.rs (renamed from src/test/run-pass/self/explicit_self_xcrate_exe.rs)0
-rw-r--r--src/test/ui/self/move-self.rs (renamed from src/test/run-pass/self/move-self.rs)0
-rw-r--r--src/test/ui/self/object-safety-sized-self-by-value-self.rs (renamed from src/test/run-pass/self/object-safety-sized-self-by-value-self.rs)0
-rw-r--r--src/test/ui/self/object-safety-sized-self-generic-method.rs (renamed from src/test/run-pass/self/object-safety-sized-self-generic-method.rs)0
-rw-r--r--src/test/ui/self/object-safety-sized-self-return-Self.rs (renamed from src/test/run-pass/self/object-safety-sized-self-return-Self.rs)0
-rw-r--r--src/test/ui/self/self-impl-2.rs (renamed from src/test/run-pass/self/self-impl.rs)0
-rw-r--r--src/test/ui/self/self-in-mut-slot-default-method.rs (renamed from src/test/run-pass/self/self-in-mut-slot-default-method.rs)0
-rw-r--r--src/test/ui/self/self-in-mut-slot-immediate-value.rs (renamed from src/test/run-pass/self/self-in-mut-slot-immediate-value.rs)0
-rw-r--r--src/test/ui/self/self-in-typedefs.rs (renamed from src/test/run-pass/self/self-in-typedefs.rs)2
-rw-r--r--src/test/ui/self/self-re-assign.rs (renamed from src/test/run-pass/self/self-re-assign.rs)0
-rw-r--r--src/test/ui/self/self-shadowing-import.rs (renamed from src/test/run-pass/self/self-shadowing-import.rs)0
-rw-r--r--src/test/ui/self/self-type-param.rs (renamed from src/test/run-pass/self/self-type-param.rs)2
-rw-r--r--src/test/ui/self/string-self-append.rs (renamed from src/test/run-pass/self/string-self-append.rs)0
-rw-r--r--src/test/ui/self/ufcs-explicit-self.rs (renamed from src/test/run-pass/self/ufcs-explicit-self.rs)0
-rw-r--r--src/test/ui/self/uniq-self-in-mut-slot.rs (renamed from src/test/run-pass/self/uniq-self-in-mut-slot.rs)0
-rw-r--r--src/test/ui/self/where-for-self.rs (renamed from src/test/run-pass/self/where-for-self.rs)0
-rw-r--r--src/test/ui/span/issue-39018.rs20
-rw-r--r--src/test/ui/span/issue-39018.stderr150
-rw-r--r--src/test/ui/str/str-concat-on-double-ref.stderr7
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs2
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr68
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs2
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr84
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/simple.rs2
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/simple.stderr240
-rw-r--r--src/test/ui/suggestions/issue-57672.rs14
-rw-r--r--src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr11
-rw-r--r--src/test/ui/suggestions/suggest-ref-mut.rs2
-rw-r--r--src/test/ui/suggestions/suggest-ref-mut.stderr8
-rw-r--r--src/test/ui/thread-local-in-ctfe.nll.stderr49
-rw-r--r--src/test/ui/traits/cycle-cache-err-60010.rs71
-rw-r--r--src/test/ui/traits/cycle-cache-err-60010.stderr20
-rw-r--r--src/test/ui/try-block/try-block-bad-type.stderr1
-rw-r--r--src/test/ui/try-on-option.stderr1
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr12
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr11
-rw-r--r--src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr11
-rw-r--r--src/test/ui/variance/variance-btree-invariant-types.nll.stderr106
-rw-r--r--src/test/ui/variance/variance-cell-is-invariant.nll.stderr13
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr24
-rw-r--r--src/test/ui/variance/variance-trait-matching.nll.stderr12
-rw-r--r--src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr13
-rw-r--r--src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr13
-rw-r--r--src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr24
-rw-r--r--src/test/ui/wf/wf-static-method.nll.stderr65
-rw-r--r--src/tools/build-manifest/src/main.rs2
m---------src/tools/cargo0
m---------src/tools/clippy18
-rw-r--r--src/tools/compiletest/Cargo.toml1
-rw-r--r--src/tools/compiletest/src/main.rs27
-rw-r--r--src/tools/compiletest/src/runtest.rs28
-rw-r--r--src/tools/compiletest/src/util.rs1
-rw-r--r--src/tools/error_index_generator/main.rs4
m---------src/tools/miri24
m---------src/tools/rls0
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustc-std-workspace-alloc/Cargo.toml2
-rw-r--r--src/tools/rustc-std-workspace-core/Cargo.toml2
-rw-r--r--src/tools/rustc-workspace-hack/Cargo.toml2
-rw-r--r--src/tools/unstable-book-gen/Cargo.toml2
1126 files changed, 14403 insertions, 7431 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 86c82adffa9..1c2b882f665 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -177,7 +177,6 @@ def default_build_triple():
     # The goal here is to come up with the same triple as LLVM would,
     # at least for the subset of platforms we're willing to target.
     ostype_mapper = {
-        'Bitrig': 'unknown-bitrig',
         'Darwin': 'apple-darwin',
         'DragonFly': 'unknown-dragonfly',
         'FreeBSD': 'unknown-freebsd',
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 9c4e856f0b8..e1cdd226fd6 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -168,7 +168,7 @@ pub fn std_cargo(builder: &Builder<'_>,
             .arg("--manifest-path")
             .arg(builder.src.join("src/liballoc/Cargo.toml"))
             .arg("--features")
-            .arg("compiler-builtins-mem");
+            .arg("compiler-builtins-mem compiler-builtins-c");
     } else {
         let features = builder.std_features();
 
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 5777331b9bf..da2e03a1a08 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -317,6 +317,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
 fn configure_cmake(builder: &Builder<'_>,
                    target: Interned<String>,
                    cfg: &mut cmake::Config) {
+    // Do not print installation messages for up-to-date files.
+    // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
+    cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY");
+
     if builder.config.ninja {
         cfg.generator("Ninja");
     }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index a3d96836aad..be0af8be7b2 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -683,7 +683,7 @@ impl Step for RustdocUi {
             target: self.target,
             mode: "ui",
             suite: "rustdoc-ui",
-            path: None,
+            path: Some("src/test/rustdoc-ui"),
             compare_mode: None,
         })
     }
@@ -1184,8 +1184,19 @@ impl Step for Compiletest {
                     Err(_) => p,
                 }
             })
-            .filter(|p| p.starts_with(suite_path) && p.is_file())
-            .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap())
+            .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
+            .filter_map(|p| {
+                // Since test suite paths are themselves directories, if we don't
+                // specify a directory or file, we'll get an empty string here
+                // (the result of the test suite directory without its suite prefix).
+                // Therefore, we need to filter these out, as only the first --test-args
+                // flag is respected, so providing an empty --test-args conflicts with
+                // any following it.
+                match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
+                    Some(s) if s != "" => Some(s),
+                    _ => None,
+                }
+            })
             .collect();
 
         test_args.append(&mut builder.config.cmd.test_args());
@@ -1870,6 +1881,10 @@ impl Step for CrateRustdoc {
         cargo.arg("--");
         cargo.args(&builder.config.cmd.test_args());
 
+        if self.host.contains("musl") {
+            cargo.arg("'-Ctarget-feature=-crt-static'");
+        }
+
         if !builder.config.verbose_tests {
             cargo.arg("--quiet");
         }
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index bd99dc118e6..60911d91789 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -113,7 +113,7 @@ pub fn gnu_target(target: &str) -> &str {
 }
 
 pub fn make(host: &str) -> PathBuf {
-    if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd")
+    if host.contains("dragonfly") || host.contains("freebsd")
         || host.contains("netbsd") || host.contains("openbsd")
     {
         PathBuf::from("gmake")
diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile
index 04db5e9c057..d19862d9c58 100644
--- a/src/ci/docker/dist-various-2/Dockerfile
+++ b/src/ci/docker/dist-various-2/Dockerfile
@@ -75,7 +75,7 @@ ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
 ENV TARGETS=x86_64-fuchsia
 ENV TARGETS=$TARGETS,aarch64-fuchsia
 ENV TARGETS=$TARGETS,wasm32-unknown-unknown
-ENV TARGETS=$TARGETS,wasm32-unknown-wasi
+ENV TARGETS=$TARGETS,wasm32-wasi
 # FIXME(#61022) - reenable solaris
 # ENV TARGETS=$TARGETS,sparcv9-sun-solaris
 # ENV TARGETS=$TARGETS,x86_64-sun-solaris
@@ -87,5 +87,5 @@ ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
 ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/"
 
 ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \
-  --set target.wasm32-unknown-wasi.wasi-root=/wasm32-unknown-wasi
+  --set target.wasm32-wasi.wasi-root=/wasm32-wasi
 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
index 965286e5bcf..98d6df043ba 100755
--- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
+++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh
@@ -13,7 +13,7 @@ git clone https://github.com/CraneStation/wasi-sysroot
 
 cd wasi-sysroot
 git reset --hard e5f14be38362f1ab83302895a6e74b2ffd0e2302
-make -j$(nproc) INSTALL_DIR=/wasm32-unknown-wasi install
+make -j$(nproc) INSTALL_DIR=/wasm32-wasi install
 
 cd ..
 rm -rf reference-sysroot-wasi
diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile
index 39ad785b41a..385eefde846 100644
--- a/src/ci/docker/dist-x86_64-musl/Dockerfile
+++ b/src/ci/docker/dist-x86_64-musl/Dockerfile
@@ -23,7 +23,7 @@ COPY scripts/musl-toolchain.sh /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
     CXXFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
-    bash musl-toolchain.sh x86_64 && rm -rf build
+    REPLACE_CC=1 bash musl-toolchain.sh x86_64 && rm -rf build
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -35,10 +35,7 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-extended \
       --disable-docs \
       --set target.x86_64-unknown-linux-musl.crt-static=false \
-      --build $HOSTS \
-      --set target.x86_64-unknown-linux-musl.cc=x86_64-linux-musl-gcc \
-      --set target.x86_64-unknown-linux-musl.cxx=x86_64-linux-musl-g++ \
-      --set target.x86_64-unknown-linux-musl.linker=x86_64-linux-musl-gcc
+      --build $HOSTS
 
 # Newer binutils broke things on some vms/distros (i.e., linking against
 # unknown relocs disabled by the following flag), so we need to go out of our
@@ -49,4 +46,5 @@ ENV RUST_CONFIGURE_ARGS \
 ENV CFLAGS_x86_64_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none \
     -Wl,--compress-debug-sections=none"
 
+# To run native tests replace `dist` below with `test`
 ENV SCRIPT python2.7 ../x.py dist --build $HOSTS
diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh
index 8cdbfebea4d..d5988a25671 100644
--- a/src/ci/docker/scripts/musl-toolchain.sh
+++ b/src/ci/docker/scripts/musl-toolchain.sh
@@ -45,6 +45,15 @@ cd -
 ln -s $OUTPUT/$TARGET/lib/libc.so /lib/ld-musl-$ARCH.so.1
 echo $OUTPUT/$TARGET/lib >> /etc/ld-musl-$ARCH.path
 
+# Now when musl bootstraps itself create proper toolchain symlinks to make build and tests easier
+if [ "$REPLACE_CC" = "1" ]; then
+    for exec in cc gcc; do
+        ln -s $TARGET-gcc /usr/local/bin/$exec
+    done
+    for exec in cpp c++ g++; do
+        ln -s $TARGET-g++ /usr/local/bin/$exec
+    done
+fi
 
 export CC=$TARGET-gcc
 export CXX=$TARGET-g++
diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh
index af0198705a2..a0fe307cffc 100755
--- a/src/ci/docker/x86_64-gnu-tools/checktools.sh
+++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh
@@ -74,7 +74,9 @@ status_check() {
     check_dispatch $1 beta nomicon src/doc/nomicon
     check_dispatch $1 beta reference src/doc/reference
     check_dispatch $1 beta rust-by-example src/doc/rust-by-example
-    check_dispatch $1 beta edition-guide src/doc/edition-guide
+    # Temporarily disabled until
+    # https://github.com/rust-lang/rust/issues/60459 is fixed.
+    # check_dispatch $1 beta edition-guide src/doc/edition-guide
     check_dispatch $1 beta rls src/tools/rls
     check_dispatch $1 beta rustfmt src/tools/rustfmt
     check_dispatch $1 beta clippy-driver src/tools/clippy
diff --git a/src/doc/book b/src/doc/book
-Subproject db919bc6bb9071566e9c4f05053672133eaac33
+Subproject 29fe982990e43b9367be0ff47abc82fb2123fd0
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject c413d42a207bd082f801ec0137c31b71e4bfed4
+Subproject 581c6cccfaf995394ea9dcac362dc8e731c1855
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject de3d55f521e657863df45260ebbca1b10527f66
+Subproject 9858872bd1b7dbba5ec27dc30d34eba00acd7ef
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject fb29b147be4d9a1f8e24aba753a7e1de537abf6
+Subproject c656171b749b7307f21371dd0d3278efee5573b
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 2a2de9ce095979978ad7b582daecf94e4070b91
+Subproject 862b669c395822bb0938781d74f860e5762ad4f
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 1ff0f8e018838a710ebc0cc1a7bf74ebe73ad9f
+Subproject 811c697b232c611ed754d279ed20643a0c4096f
diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide
-Subproject 99e1b1d53656be08654df399fc200584aebb50e
+Subproject 3cb727b62b953d59b4360d39aa68b6dc8f15765
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index dfb40284ef6..bd7f6630ea2 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -17,28 +17,147 @@ to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively.
 
 ## `-L`: add a directory to the library search path
 
-When looking for external crates, a directory passed to this flag will be searched.
+When looking for external crates or libraries, a directory passed to this flag
+will be searched.
+
+The kind of search path can optionally be specified with the form `-L
+KIND=PATH` where `KIND` may be one of:
+
+- `dependency` — Only search for transitive dependencies in this directory.
+- `crate` — Only search for this crate's direct dependencies in this
+  directory.
+- `native` — Only search for native libraries in this directory.
+- `framework` — Only search for macOS frameworks in this directory.
+- `all` — Search for all library kinds in this directory. This is the default
+  if `KIND` is not specified.
 
 ## `-l`: link the generated crate to a native library
 
 This flag allows you to specify linking to a specific native library when building
 a crate.
 
+The kind of library can optionally be specified with the form `-l KIND=lib`
+where `KIND` may be one of:
+
+- `dylib` — A native dynamic library.
+- `static` — A native static library (such as a `.a` archive).
+- `framework` — A macOS framework.
+
+The kind of library can be specified in a [`#[link]`
+attribute][link-attribute]. If the kind is not specified in the `link`
+attribute or on the command-line, it will link a dynamic library if available,
+otherwise it will use a static library. If the kind is specified on the
+command-line, it will override the kind specified in a `link` attribute.
+
+The name used in a `link` attribute may be overridden using the form `-l
+ATTR_NAME:LINK_NAME` where `ATTR_NAME` is the name in the `link` attribute,
+and `LINK_NAME` is the name of the actual library that will be linked.
+
+[link-attribute]: ../reference/items/external-blocks.html#the-link-attribute
+
 ## `--crate-type`: a list of types of crates for the compiler to emit
 
-This instructs `rustc` on which crate type to build.
+This instructs `rustc` on which crate type to build. This flag accepts a
+comma-separated list of values, and may be specified multiple times. The valid
+crate types are:
+
+- `lib` — Generates a library kind preferred by the compiler, currently
+  defaults to `rlib`.
+- `rlib` — A Rust static library.
+- `staticlib` — A native static library.
+- `dylib` — A Rust dynamic library.
+- `cdylib` — A native dynamic library.
+- `bin` — A runnable executable program.
+- `proc-macro` — Generates a format suitable for a procedural macro library
+  that may be loaded by the compiler.
+
+The crate type may be specified with the [`crate_type` attribute][crate_type].
+The `--crate-type` command-line value will override the `crate_type`
+attribute.
+
+More details may be found in the [linkage chapter] of the reference.
+
+[linkage chapter]: ../reference/linkage.html
+[crate_type]: ../reference/linkage.html
 
 ## `--crate-name`: specify the name of the crate being built
 
 This informs `rustc` of the name of your crate.
 
-## `--emit`: emit output other than a crate
-
-Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR.
+## `--edition`: specify the edition to use
+
+This flag takes a value of `2015` or `2018`. The default is `2015`. More
+information about editions may be found in the [edition guide].
+
+[edition guide]: ../edition-guide/introduction.html
+
+## `--emit`: specifies the types of output files to generate
+
+This flag controls the types of output files generated by the compiler. It
+accepts a comma-separated list of values, and may be specified multiple times.
+The valid emit kinds are:
+
+- `asm` — Generates a file with the crate's assembly code. The default output
+  filename is `CRATE_NAME.s`.
+- `dep-info` — Generates a file with Makefile syntax that indicates all the
+  source files that were loaded to generate the crate. The default output
+  filename is `CRATE_NAME.d`.
+- `link` — Generates the crates specified by `--crate-type`. The default
+  output filenames depend on the crate type and platform. This is the default
+  if `--emit` is not specified.
+- `llvm-bc` — Generates a binary file containing the [LLVM bitcode]. The
+  default output filename is `CRATE_NAME.bc`.
+- `llvm-ir` — Generates a file containing [LLVM IR]. The default output
+  filename is `CRATE_NAME.ll`.
+- `metadata` — Generates a file containing metadata about the crate. The
+  default output filename is `CRATE_NAME.rmeta`.
+- `mir` — Generates a file containing rustc's mid-level intermediate
+  representation. The default output filename is `CRATE_NAME.mir`.
+- `obj` — Generates a native object file. The default output filename is
+  `CRATE_NAME.o`.
+
+The output filename can be set with the `-o` flag. A suffix may be added to
+the filename with the `-C extra-filename` flag. The files are written to the
+current directory unless the `--out-dir` flag is used. Each emission type may
+also specify the output filename with the form `KIND=PATH`, which takes
+precedence over the `-o` flag.
+
+[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
+[LLVM IR]: https://llvm.org/docs/LangRef.html
 
 ## `--print`: print compiler information
 
-This flag prints out various information about the compiler.
+This flag prints out various information about the compiler. This flag may be
+specified multiple times, and the information is printed in the order the
+flags are specified. Specifying a `--print` flag will usually disable the
+`--emit` step and will only print the requested information. The valid types
+of print values are:
+
+- `crate-name` — The name of the crate.
+- `file-names` — The names of the files created by the `link` emit kind.
+- `sysroot` — Path to the sysroot.
+- `cfg` — List of cfg values. See [conditional compilation] for more
+  information about cfg values.
+- `target-list` — List of known targets. The target may be selected with the
+  `--target` flag.
+- `target-cpus` — List of available CPU values for the current target. The
+  target CPU may be selected with the `-C target-cpu=val` flag.
+- `target-features` — List of available target features for the current
+  target. Target features may be enabled with the `-C target-feature=val`
+  flag.
+- `relocation-models` — List of relocation models. Relocation models may be
+  selected with the `-C relocation-model=val` flag.
+- `code-models` — List of code models. Code models may be selected with the
+  `-C code-model=val` flag.
+- `tls-models` — List of Thread Local Storage models supported. The model may
+  be selected with the `-Z tls-model=val` flag.
+- `native-static-libs` — This may be used when creating a `staticlib` crate
+  type. If this is the only flag, it will perform a full compilation and
+  include a diagnostic note that indicates the linker flags to use when
+  linking the resulting static library. The note starts with the text
+  `native-static-libs:` to make it easier to fetch the output.
+
+[conditional compilation]: ../reference/conditional-compilation.html
 
 ## `-g`: include debug information
 
@@ -54,7 +173,8 @@ This flag controls the output filename.
 
 ## `--out-dir`: directory to write the output in
 
-The outputted crate will be written to this directory.
+The outputted crate will be written to this directory. This flag is ignored if
+the `-o` flag is used.
 
 ## `--explain`: provide a detailed explanation of an error message
 
@@ -111,8 +231,9 @@ This flag, when combined with other flags, makes them produce extra output.
 
 ## `--extern`: specify where an external library is located
 
-This flag allows you to pass the name and location of an external crate that will
-be linked into the crate you're buildling.
+This flag allows you to pass the name and location of an external crate that
+will be linked into the crate you are building. This flag may be specified
+multiple times. The format of the value should be `CRATENAME=PATH`.
 
 ## `--sysroot`: Override the system root
 
@@ -121,8 +242,32 @@ distribution; this flag allows that to be overridden.
 
 ## `--error-format`: control how errors are produced
 
-This flag lets you control the format of errors.
+This flag lets you control the format of messages. Messages are printed to
+stderr. The valid options are:
+
+- `human` — Human-readable output. This is the default.
+- `json` — Structured JSON output.
+- `short` — Short, one-line messages.
 
 ## `--color`: configure coloring of output
 
-This flag lets you control color settings of the output.
+This flag lets you control color settings of the output. The valid options
+are:
+
+- `auto` — Use colors if output goes to a tty. This is the default.
+- `always` — Always use colors.
+- `never` — Never colorize output.
+
+## `--remap-path-prefix`: remap source names in output
+
+Remap source path prefixes in all output, including compiler diagnostics,
+debug information, macro expansions, etc. It takes a value of the form
+`FROM=TO` where a path prefix equal to `FROM` is rewritten to the value `TO`.
+The `FROM` may itself contain an `=` symbol, but the `TO` value may not. This
+flag may be specified multiple times.
+
+This is useful for normalizing build products, for example by removing the
+current directory out of pathnames emitted into the object files. The
+replacement is purely textual, with no consideration of the current system's
+pathname syntax. For example `--remap-path-prefix foo=bar` will match
+`foo/lib.rs` but not `./foo/lib.rs`.
diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md
index 46b717f3387..049e59b6517 100644
--- a/src/doc/rustc/src/lints/groups.md
+++ b/src/doc/rustc/src/lints/groups.md
@@ -21,9 +21,9 @@ Here's a list of each lint group, and the lints that they are made up of:
 | edition-2018        | Lints that will be turned into errors in Rust 2018            | tyvar-behind-raw-pointer                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
 | rust-2018-idioms    | Lints to nudge you toward idiomatic features of Rust 2018     | bare-trait-object, unreachable-pub                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
 | unused              | These lints detect things being declared but not used         | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens                                                                                                                                                                                    |
-| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, incoherent-fundamental-impls, tyvar-behind-raw-pointer, unstable-name-collision |
+| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision |
 
 Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`.
 
 Finally, you can also see the table above by invoking `rustc -W help`. This will give you the exact values for the specific
-compiler you have installed.
\ No newline at end of file
+compiler you have installed.
diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md
index fa62d1a03f5..c1740f272ed 100644
--- a/src/doc/rustc/src/lints/listing/deny-by-default.md
+++ b/src/doc/rustc/src/lints/listing/deny-by-default.md
@@ -222,44 +222,3 @@ error: invalid `crate_type` value
   | ^^^^^^^^^^^^^^^^^^^^
   |
 ```
-
-## incoherent-fundamental-impls
-
-This lint detects potentially-conflicting impls that were erroneously allowed. Some
-example code that triggers this lint:
-
-```rust,ignore
-pub trait Trait1<X> {
-    type Output;
-}
-
-pub trait Trait2<X> {}
-
-pub struct A;
-
-impl<X, T> Trait1<X> for T where T: Trait2<X> {
-    type Output = ();
-}
-
-impl<X> Trait1<Box<X>> for A {
-    type Output = i32;
-}
-```
-
-This will produce:
-
-```text
-error: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`: (E0119)
-  --> src/main.rs:13:1
-   |
-9  | impl<X, T> Trait1<X> for T where T: Trait2<X> {
-   | --------------------------------------------- first implementation here
-...
-13 | impl<X> Trait1<Box<X>> for A {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A`
-   |
-   = note: #[deny(incoherent_fundamental_impls)] on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205>
-   = note: downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A`
-```
diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md
index 61e5b3d0133..b165c5a6b3b 100644
--- a/src/doc/rustdoc/src/the-doc-attribute.md
+++ b/src/doc/rustdoc/src/the-doc-attribute.md
@@ -92,6 +92,21 @@ the tracking issue.
 #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
 ```
 
+### `html_root_url`
+
+The `#[doc(html_root_url = "…")]` attribute value indicates the URL for
+generating links to external crates. When rustdoc needs to generate a link to
+an item in an external crate, it will first check if the extern crate has been
+documented locally on-disk, and if so link directly to it. Failing that, it
+will use the URL given by the `--extern-html-root-url` command-line flag if
+available. If that is not available, then it will use the `html_root_url`
+value in the extern crate if it is available. If that is not available, then
+the extern items will not be linked.
+
+```rust,ignore
+#![doc(html_root_url = "https://docs.rs/serde/1.0")]
+```
+
 ### `html_no_source`
 
 By default, `rustdoc` will include the source code of your program, with links
diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md
index 54472e35b1b..bbcacb7f3d5 100644
--- a/src/doc/rustdoc/src/what-is-rustdoc.md
+++ b/src/doc/rustdoc/src/what-is-rustdoc.md
@@ -98,21 +98,21 @@ documentation for them as well!
 `rustdoc` can also generate HTML from standalone Markdown files. Let's
 give it a try: create a `README.md` file with these contents:
 
-```text
-    # Docs
+````text
+# Docs
 
-    This is a project to test out `rustdoc`.
+This is a project to test out `rustdoc`.
 
-    [Here is a link!](https://www.rust-lang.org)
+[Here is a link!](https://www.rust-lang.org)
 
-    ## Subheading
+## Subheading
 
-    ```rust
-    fn foo() -> i32 {
-        1 + 1
-    }
-    ```
+```rust
+fn foo() -> i32 {
+    1 + 1
+}
 ```
+````
 
 And call `rustdoc` on it:
 
diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis
index e3d99e34b35..de30b58526a 100644
--- a/src/etc/natvis/liballoc.natvis
+++ b/src/etc/natvis/liballoc.natvis
@@ -7,11 +7,11 @@
       <Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
       <ArrayItems>
         <Size>len</Size>
-        <ValuePointer>buf.ptr.pointer.__0</ValuePointer>
+        <ValuePointer>buf.ptr.pointer</ValuePointer>
       </ArrayItems>
     </Expand>
   </Type>
-  <Type Name="alloc::vec_deque::VecDeque&lt;*&gt;">
+  <Type Name="alloc::collections::vec_deque::VecDeque&lt;*&gt;">
     <DisplayString>{{ size={tail &lt;= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
     <Expand>
       <Item Name="[size]" ExcludeView="simple">tail &lt;= head ? head - tail : buf.cap - tail + head</Item>
@@ -24,19 +24,19 @@
           <If Condition="i == head">
             <Break/>
           </If>
-          <Item>buf.ptr.pointer.__0 + i</Item>
+          <Item>buf.ptr.pointer[i]</Item>
           <Exec>i = (i + 1 == buf.cap ? 0 : i + 1)</Exec>
         </Loop>
       </CustomListItems>
     </Expand>
   </Type>
-  <Type Name="alloc::linked_list::LinkedList&lt;*&gt;">
+  <Type Name="alloc::collections::linked_list::LinkedList&lt;*&gt;">
     <DisplayString>{{ size={len} }}</DisplayString>
     <Expand>
       <LinkedListItems>
         <Size>len</Size>
-        <HeadPointer>*(alloc::linked_list::Node&lt;$T1&gt; **)&amp;head</HeadPointer>
-        <NextPointer>*(alloc::linked_list::Node&lt;$T1&gt; **)&amp;next</NextPointer>
+        <HeadPointer>*(alloc::collections::linked_list::Node&lt;$T1&gt; **)&amp;head</HeadPointer>
+        <NextPointer>*(alloc::collections::linked_list::Node&lt;$T1&gt; **)&amp;next</NextPointer>
         <ValueNode>element</ValueNode>
       </LinkedListItems>
     </Expand>
diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis
index 37d64be1ce9..0e703b3b950 100644
--- a/src/etc/natvis/libcore.natvis
+++ b/src/etc/natvis/libcore.natvis
@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
   <Type Name="core::ptr::Unique&lt;*&gt;">
-    <DisplayString>{{ Unique {*pointer.__0} }}</DisplayString>
+    <DisplayString>{{ Unique {pointer} }}</DisplayString>
     <Expand>
-      <Item Name="[ptr]">pointer.__0</Item>
+      <Item Name="[ptr]">pointer</Item>
     </Expand>
   </Type>
   <Type Name="core::ptr::Shared&lt;*&gt;">
-    <DisplayString>{{ Shared {*pointer.__0} }}</DisplayString>
+    <DisplayString>{{ Shared {pointer} }}</DisplayString>
     <Expand>
-      <Item Name="[ptr]">pointer.__0</Item>
+      <Item Name="[ptr]">pointer</Item>
     </Expand>
   </Type>
   <Type Name="core::option::Option&lt;*&gt;">
diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml
index ddf0044c506..bcb27bb5161 100644
--- a/src/liballoc/Cargo.toml
+++ b/src/liballoc/Cargo.toml
@@ -33,3 +33,4 @@ harness = false
 
 [features]
 compiler-builtins-mem = ['compiler_builtins/mem']
+compiler-builtins-c = ["compiler_builtins/c"]
diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs
index ddc6481eec7..41ff06d70ff 100644
--- a/src/liballoc/alloc.rs
+++ b/src/liballoc/alloc.rs
@@ -37,6 +37,8 @@ extern "Rust" {
 ///
 /// Note: while this type is unstable, the functionality it provides can be
 /// accessed through the [free functions in `alloc`](index.html#functions).
+///
+/// [`Alloc`]: trait.Alloc.html
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, Default, Debug)]
 pub struct Global;
@@ -54,6 +56,10 @@ pub struct Global;
 ///
 /// See [`GlobalAlloc::alloc`].
 ///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc
+///
 /// # Examples
 ///
 /// ```
@@ -87,6 +93,10 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
 /// # Safety
 ///
 /// See [`GlobalAlloc::dealloc`].
+///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
@@ -105,6 +115,10 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
 /// # Safety
 ///
 /// See [`GlobalAlloc::realloc`].
+///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[inline]
 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
@@ -124,6 +138,10 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8
 ///
 /// See [`GlobalAlloc::alloc_zeroed`].
 ///
+/// [`Global`]: struct.Global.html
+/// [`Alloc`]: trait.Alloc.html
+/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed
+///
 /// # Examples
 ///
 /// ```
diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs
index c355361b53c..c5a0b6e877b 100644
--- a/src/liballoc/collections/binary_heap.rs
+++ b/src/liballoc/collections/binary_heap.rs
@@ -231,6 +231,20 @@ use super::SpecExtend;
 /// assert_eq!(heap.pop(), Some(Reverse(5)));
 /// assert_eq!(heap.pop(), None);
 /// ```
+///
+/// # Time complexity
+///
+/// | [push] | [pop]    | [peek]/[peek\_mut] |
+/// |--------|----------|--------------------|
+/// | O(1)~  | O(log n) | O(1)               |
+///
+/// The value for `push` is an expected cost; the method documentation gives a
+/// more detailed analysis.
+///
+/// [push]: #method.push
+/// [pop]: #method.pop
+/// [peek]: #method.peek
+/// [peek\_mut]: #method.peek_mut
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BinaryHeap<T> {
     data: Vec<T>,
@@ -384,6 +398,10 @@ impl<T: Ord> BinaryHeap<T> {
     /// }
     /// assert_eq!(heap.peek(), Some(&2));
     /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// Cost is O(1) in the worst case.
     #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
     pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
         if self.is_empty() {
@@ -411,6 +429,11 @@ impl<T: Ord> BinaryHeap<T> {
     /// assert_eq!(heap.pop(), Some(1));
     /// assert_eq!(heap.pop(), None);
     /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// The worst case cost of `pop` on a heap containing *n* elements is O(log
+    /// n).
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn pop(&mut self) -> Option<T> {
         self.data.pop().map(|mut item| {
@@ -438,6 +461,22 @@ impl<T: Ord> BinaryHeap<T> {
     /// assert_eq!(heap.len(), 3);
     /// assert_eq!(heap.peek(), Some(&5));
     /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// The expected cost of `push`, averaged over every possible ordering of
+    /// the elements being pushed, and over a sufficiently large number of
+    /// pushes, is O(1). This is the most meaningful cost metric when pushing
+    /// elements that are *not* already in any sorted pattern.
+    ///
+    /// The time complexity degrades if elements are pushed in predominantly
+    /// ascending order. In the worst case, elements are pushed in ascending
+    /// sorted order and the amortized cost per push is O(log n) against a heap
+    /// containing *n* elements.
+    ///
+    /// The worst case cost of a *single* call to `push` is O(n). The worst case
+    /// occurs when capacity is exhausted and needs a resize. The resize cost
+    /// has been amortized in the previous figures.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push(&mut self, item: T) {
         let old_len = self.len();
@@ -650,6 +689,10 @@ impl<T> BinaryHeap<T> {
     /// assert_eq!(heap.peek(), Some(&5));
     ///
     /// ```
+    ///
+    /// # Time complexity
+    ///
+    /// Cost is O(1) in the worst case.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn peek(&self) -> Option<&T> {
         self.data.get(0)
@@ -992,6 +1035,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1047,6 +1095,11 @@ impl<T> Iterator for IntoIter<T> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1093,6 +1146,11 @@ impl<T> Iterator for Drain<'_, T> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "drain", since = "1.6.0")]
diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs
index 6b079fc87cc..414abb00ef1 100644
--- a/src/liballoc/collections/btree/map.rs
+++ b/src/liballoc/collections/btree/map.rs
@@ -1193,6 +1193,11 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.length, Some(self.length))
     }
+
+    #[inline]
+    fn last(mut self) -> Option<(&'a K, &'a V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
@@ -1253,6 +1258,11 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.length, Some(self.length))
     }
+
+    #[inline]
+    fn last(mut self) -> Option<(&'a K, &'a mut V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1359,6 +1369,11 @@ impl<K, V> Iterator for IntoIter<K, V> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         (self.length, Some(self.length))
     }
+
+    #[inline]
+    fn last(mut self) -> Option<(K, V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1421,6 +1436,11 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a K> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1458,6 +1478,11 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a V> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1495,6 +1520,11 @@ impl<'a, K, V> Iterator for Range<'a, K, V> {
             unsafe { Some(self.next_unchecked()) }
         }
     }
+
+    #[inline]
+    fn last(mut self) -> Option<(&'a K, &'a V)> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1508,6 +1538,11 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a mut V> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1626,6 +1661,11 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
             unsafe { Some(self.next_unchecked()) }
         }
     }
+
+    #[inline]
+    fn last(mut self) -> Option<(&'a K, &'a mut V)> {
+        self.next_back()
+    }
 }
 
 impl<'a, K, V> RangeMut<'a, K, V> {
diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs
index 16a96ca19b8..6f2467dfd6b 100644
--- a/src/liballoc/collections/btree/set.rs
+++ b/src/liballoc/collections/btree/set.rs
@@ -1019,6 +1019,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a T> {
+        self.next_back()
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
@@ -1044,6 +1049,11 @@ impl<T> Iterator for IntoIter<T> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<T> {
+        self.next_back()
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> DoubleEndedIterator for IntoIter<T> {
@@ -1073,6 +1083,11 @@ impl<'a, T> Iterator for Range<'a, T> {
     fn next(&mut self) -> Option<&'a T> {
         self.iter.next().map(|(k, _)| k)
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "btree_range", since = "1.17.0")]
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index d65c24f7350..31e49d06a7b 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -1835,8 +1835,8 @@ impl<T> VecDeque<T> {
     /// Retains only the elements specified by the predicate.
     ///
     /// In other words, remove all elements `e` such that `f(&e)` returns false.
-    /// This method operates in place and preserves the order of the retained
-    /// elements.
+    /// This method operates in place, visiting each element exactly once in the
+    /// original order, and preserves the order of the retained elements.
     ///
     /// # Examples
     ///
@@ -1848,6 +1848,20 @@ impl<T> VecDeque<T> {
     /// buf.retain(|&x| x%2 == 0);
     /// assert_eq!(buf, [2, 4]);
     /// ```
+    ///
+    /// The exact order may be useful for tracking external state, like an index.
+    ///
+    /// ```
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut buf = VecDeque::new();
+    /// buf.extend(1..6);
+    ///
+    /// let keep = [false, true, true, false, true];
+    /// let mut i = 0;
+    /// buf.retain(|_| (keep[i], i += 1).0);
+    /// assert_eq!(buf, [2, 3, 5]);
+    /// ```
     #[stable(feature = "vec_deque_retain", since = "1.4.0")]
     pub fn retain<F>(&mut self, mut f: F)
         where F: FnMut(&T) -> bool
@@ -1934,8 +1948,6 @@ impl<T> VecDeque<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(vecdeque_rotate)]
-    ///
     /// use std::collections::VecDeque;
     ///
     /// let mut buf: VecDeque<_> = (0..10).collect();
@@ -1949,7 +1961,7 @@ impl<T> VecDeque<T> {
     /// }
     /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
     /// ```
-    #[unstable(feature = "vecdeque_rotate", issue = "56686")]
+    #[stable(feature = "vecdeque_rotate", since = "1.36.0")]
     pub fn rotate_left(&mut self, mid: usize) {
         assert!(mid <= self.len());
         let k = self.len() - mid;
@@ -1979,8 +1991,6 @@ impl<T> VecDeque<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(vecdeque_rotate)]
-    ///
     /// use std::collections::VecDeque;
     ///
     /// let mut buf: VecDeque<_> = (0..10).collect();
@@ -1994,7 +2004,7 @@ impl<T> VecDeque<T> {
     /// }
     /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
     /// ```
-    #[unstable(feature = "vecdeque_rotate", issue = "56686")]
+    #[stable(feature = "vecdeque_rotate", since = "1.36.0")]
     pub fn rotate_right(&mut self, k: usize) {
         assert!(k <= self.len());
         let mid = self.len() - k;
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 2edd946ff11..d90036eaf49 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -109,7 +109,7 @@
 #![feature(rustc_const_unstable)]
 #![feature(const_vec_new)]
 #![feature(slice_partition_dedup)]
-#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
+#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)]
 #![feature(alloc_layout_extra)]
 #![feature(try_trait)]
 #![feature(iter_nth_back)]
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 68eecd97ea1..0dffb19476f 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -932,6 +932,11 @@ impl<T: ?Sized + PartialEq> RcEqIdent<T> for Rc<T> {
     }
 }
 
+/// We're doing this specialization here, and not as a more general optimization on `&T`, because it
+/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to
+/// store large values, that are slow to clone, but also heavy to check for equality, causing this
+/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to
+/// the same value, than two `&T`s.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Eq> RcEqIdent<T> for Rc<T> {
     #[inline]
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index a3e2098695f..e74d37c1c2b 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -1200,8 +1200,8 @@ impl String {
     /// Retains only the characters specified by the predicate.
     ///
     /// In other words, remove all characters `c` such that `f(c)` returns `false`.
-    /// This method operates in place and preserves the order of the retained
-    /// characters.
+    /// This method operates in place, visiting each character exactly once in the
+    /// original order, and preserves the order of the retained characters.
     ///
     /// # Examples
     ///
@@ -1212,6 +1212,16 @@ impl String {
     ///
     /// assert_eq!(s, "foobar");
     /// ```
+    ///
+    /// The exact order may be useful for tracking external state, like an index.
+    ///
+    /// ```
+    /// let mut s = String::from("abcde");
+    /// let keep = [false, true, true, false, true];
+    /// let mut i = 0;
+    /// s.retain(|_| (keep[i], i += 1).0);
+    /// assert_eq!(s, "bce");
+    /// ```
     #[inline]
     #[stable(feature = "string_retain", since = "1.26.0")]
     pub fn retain<F>(&mut self, mut f: F)
@@ -2179,6 +2189,14 @@ impl From<&str> for String {
     }
 }
 
+#[stable(feature = "from_ref_string", since = "1.35.0")]
+impl From<&String> for String {
+    #[inline]
+    fn from(s: &String) -> String {
+        s.clone()
+    }
+}
+
 // note: test pulls in libstd, which causes errors here
 #[cfg(not(test))]
 #[stable(feature = "string_from_box", since = "1.18.0")]
@@ -2367,6 +2385,10 @@ impl Iterator for Drain<'_> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+    #[inline]
+    fn last(mut self) -> Option<char> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "drain", since = "1.6.0")]
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 466e806663c..90c7859b3db 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -1377,6 +1377,11 @@ impl<T: ?Sized + PartialEq> ArcEqIdent<T> for Arc<T> {
     }
 }
 
+/// We're doing this specialization here, and not as a more general optimization on `&T`, because it
+/// would otherwise add a cost to all equality checks on refs. We assume that `Arc`s are used to
+/// store large values, that are slow to clone, but also heavy to check for equality, causing this
+/// cost to pay off more easily. It's also more likely to have two `Arc` clones, that point to
+/// the same value, than two `&T`s.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Eq> ArcEqIdent<T> for Arc<T> {
     #[inline]
diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs
index d52814118b3..989beb3b1bf 100644
--- a/src/liballoc/tests/btree/set.rs
+++ b/src/liballoc/tests/btree/set.rs
@@ -143,8 +143,8 @@ fn test_union() {
 #[test]
 // Only tests the simple function definition with respect to intersection
 fn test_is_disjoint() {
-    let one = [1].into_iter().collect::<BTreeSet<_>>();
-    let two = [2].into_iter().collect::<BTreeSet<_>>();
+    let one = [1].iter().collect::<BTreeSet<_>>();
+    let two = [2].iter().collect::<BTreeSet<_>>();
     assert!(one.is_disjoint(&two));
 }
 
diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs
index b736750c576..ddb3120e89d 100644
--- a/src/liballoc/tests/lib.rs
+++ b/src/liballoc/tests/lib.rs
@@ -6,7 +6,6 @@
 #![feature(repeat_generic_slice)]
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
-#![feature(vecdeque_rotate)]
 #![deny(rust_2018_idioms)]
 
 use std::hash::{Hash, Hasher};
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index cd62c3e0524..c0cdffe596b 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -937,8 +937,8 @@ impl<T> Vec<T> {
     /// Retains only the elements specified by the predicate.
     ///
     /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
-    /// This method operates in place and preserves the order of the retained
-    /// elements.
+    /// This method operates in place, visiting each element exactly once in the
+    /// original order, and preserves the order of the retained elements.
     ///
     /// # Examples
     ///
@@ -947,6 +947,16 @@ impl<T> Vec<T> {
     /// vec.retain(|&x| x%2 == 0);
     /// assert_eq!(vec, [2, 4]);
     /// ```
+    ///
+    /// The exact order may be useful for tracking external state, like an index.
+    ///
+    /// ```
+    /// let mut vec = vec![1, 2, 3, 4, 5];
+    /// let keep = [false, true, true, false, true];
+    /// let mut i = 0;
+    /// vec.retain(|_| (keep[i], i += 1).0);
+    /// assert_eq!(vec, [2, 3, 5]);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn retain<F>(&mut self, mut f: F)
         where F: FnMut(&T) -> bool
@@ -2385,6 +2395,11 @@ impl<T> Iterator for IntoIter<T> {
     fn count(self) -> usize {
         self.len()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2504,6 +2519,11 @@ impl<T> Iterator for Drain<'_, T> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<T> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "drain", since = "1.6.0")]
@@ -2573,6 +2593,10 @@ impl<I: Iterator> Iterator for Splice<'_, I> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.drain.size_hint()
     }
+
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "vec_splice", since = "1.21.0")]
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index c124457118c..f25631e028e 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -99,7 +99,7 @@ impl Layout {
     /// [`Layout::from_size_align`](#method.from_size_align).
     #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
-    pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
+    pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
     }
 
@@ -480,7 +480,7 @@ pub unsafe trait GlobalAlloc {
     ///   this allocator,
     ///
     /// * `layout` must be the same layout that was used
-    ///   to allocated that block of memory,
+    ///   to allocate that block of memory,
     #[stable(feature = "global_alloc", since = "1.28.0")]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
 
@@ -535,7 +535,7 @@ pub unsafe trait GlobalAlloc {
     /// * `ptr` must be currently allocated via this allocator,
     ///
     /// * `layout` must be the same layout that was used
-    ///   to allocated that block of memory,
+    ///   to allocate that block of memory,
     ///
     /// * `new_size` must be greater than zero.
     ///
diff --git a/src/libcore/array.rs b/src/libcore/array.rs
index e4cadcbf75b..03094bfd333 100644
--- a/src/libcore/array.rs
+++ b/src/libcore/array.rs
@@ -8,7 +8,7 @@
 
 use crate::borrow::{Borrow, BorrowMut};
 use crate::cmp::Ordering;
-use crate::convert::TryFrom;
+use crate::convert::{Infallible, TryFrom};
 use crate::fmt;
 use crate::hash::{Hash, self};
 use crate::marker::Unsize;
@@ -74,6 +74,13 @@ impl TryFromSliceError {
     }
 }
 
+#[stable(feature = "try_from_slice_error", since = "1.36.0")]
+impl From<Infallible> for TryFromSliceError {
+    fn from(x: Infallible) -> TryFromSliceError {
+        match x {}
+    }
+}
+
 macro_rules! __impl_slice_eq1 {
     ($Lhs: ty, $Rhs: ty) => {
         __impl_slice_eq1! { $Lhs, $Rhs, Sized }
diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs
index c0ab364380f..ddee02ea232 100644
--- a/src/libcore/ascii.rs
+++ b/src/libcore/ascii.rs
@@ -117,6 +117,8 @@ impl Iterator for EscapeDefault {
     type Item = u8;
     fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
     fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+    #[inline]
+    fn last(mut self) -> Option<u8> { self.next_back() }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl DoubleEndedIterator for EscapeDefault {
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs
index cf92babcb40..b3ff447be5e 100644
--- a/src/libcore/convert.rs
+++ b/src/libcore/convert.rs
@@ -104,7 +104,6 @@ pub const fn identity<T>(x: T) -> T { x }
 /// If you need to do a costly conversion it is better to implement [`From`] with type
 /// `&T` or write a custom function.
 ///
-///
 /// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects:
 ///
 /// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either
@@ -133,7 +132,7 @@ pub const fn identity<T>(x: T) -> T { x }
 /// converted a the specified type `T`.
 ///
 /// For example: By creating a generic function that takes an `AsRef<str>` we express that we
-/// want to accept all references that can be converted to &str as an argument.
+/// want to accept all references that can be converted to `&str` as an argument.
 /// Since both [`String`] and `&str` implement `AsRef<str>` we can accept both as input argument.
 ///
 /// [`String`]: ../../std/string/struct.String.html
@@ -149,7 +148,6 @@ pub const fn identity<T>(x: T) -> T { x }
 /// let s = "hello".to_string();
 /// is_hello(s);
 /// ```
-///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait AsRef<T: ?Sized> {
     /// Performs the conversion.
@@ -182,6 +180,7 @@ pub trait AsRef<T: ?Sized> {
 /// write a function `add_one`that takes all arguments that can be converted to `&mut u64`.
 /// Because [`Box<T>`] implements `AsMut<T>` `add_one` accepts arguments of type
 /// `&mut Box<u64>` as well:
+///
 /// ```
 /// fn add_one<T: AsMut<u64>>(num: &mut T) {
 ///     *num.as_mut() += 1;
@@ -191,8 +190,8 @@ pub trait AsRef<T: ?Sized> {
 /// add_one(&mut boxed_num);
 /// assert_eq!(*boxed_num, 1);
 /// ```
-/// [`Box<T>`]: ../../std/boxed/struct.Box.html
 ///
+/// [`Box<T>`]: ../../std/boxed/struct.Box.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait AsMut<T: ?Sized> {
     /// Performs the conversion.
@@ -203,9 +202,9 @@ pub trait AsMut<T: ?Sized> {
 /// A value-to-value conversion that consumes the input value. The
 /// opposite of [`From`].
 ///
-/// One should only implement [`Into`] if a conversion to a type outside the current crate is
-/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because
-/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to
+/// One should only implement `Into` if a conversion to a type outside the current crate is
+/// required. Otherwise one should always prefer implementing [`From`] over `Into` because
+/// implementing [`From`] automatically provides one with a implementation of `Into` thanks to
 /// the blanket implementation in the standard library. [`From`] cannot do these type of
 /// conversions because of Rust's orphaning rules.
 ///
@@ -213,8 +212,8 @@ pub trait AsMut<T: ?Sized> {
 ///
 /// # Generic Implementations
 ///
-/// - [`From<T>`]` for U` implies `Into<U> for T`
-/// - [`Into`]` is reflexive, which means that `Into<T> for T` is implemented
+/// - [`From`]`<T> for U` implies `Into<U> for T`
+/// - `Into` is reflexive, which means that `Into<T> for T` is implemented
 ///
 /// # Implementing `Into` for conversions to external types
 ///
@@ -273,7 +272,7 @@ pub trait AsMut<T: ?Sized> {
 /// [`Option<T>`]: ../../std/option/enum.Option.html
 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
 /// [`String`]: ../../std/string/struct.String.html
-/// [From]: trait.From.html
+/// [`From`]: trait.From.html
 /// [`into`]: trait.Into.html#tymethod.into
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Into<T>: Sized {
@@ -285,18 +284,18 @@ pub trait Into<T>: Sized {
 /// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of
 /// [`Into`].
 ///
-/// One should always prefer implementing [`From`] over [`Into`]
-/// because implementing [`From`] automatically provides one with a implementation of [`Into`]
+/// One should always prefer implementing `From` over [`Into`]
+/// because implementing `From` automatically provides one with a 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.
-/// [`From`] cannot do these type of conversions because of Rust's orphaning rules.
+/// `From` cannot do these type of conversions because of Rust's orphaning rules.
 /// See [`Into`] for more details.
 ///
-/// Prefer using [`Into`] over using [`From`] when specifying trait bounds on a generic function.
+/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function.
 /// This way, types that directly implement [`Into`] can be used as arguments as well.
 ///
-/// The [`From`] is also very useful when performing error handling. When constructing a function
+/// The `From` is also very useful when performing error handling. When constructing a function
 /// that is capable of failing, the return type will generally be of the form `Result<T, E>`.
 /// The `From` trait simplifies error handling by allowing a function to return a single error type
 /// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more
@@ -306,14 +305,15 @@ pub trait Into<T>: Sized {
 ///
 /// # Generic Implementations
 ///
-/// - [`From<T>`]` for U` implies [`Into<U>`]` for T`
-/// - [`From`] is reflexive, which means that `From<T> for T` is implemented
+/// - `From<T> for U` implies [`Into`]`<U> for T`
+/// - `From` is reflexive, which means that `From<T> for T` is implemented
 ///
 /// # Examples
 ///
 /// [`String`] implements `From<&str>`:
 ///
-/// An explicit conversion from a &str to a String is done as follows:
+/// An explicit conversion from a `&str` to a String is done as follows:
+///
 /// ```
 /// let string = "hello".to_string();
 /// let other_string = String::from("hello");
@@ -361,7 +361,7 @@ pub trait Into<T>: Sized {
 /// [`Option<T>`]: ../../std/option/enum.Option.html
 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
 /// [`String`]: ../../std/string/struct.String.html
-/// [`Into<U>`]: trait.Into.html
+/// [`Into`]: trait.Into.html
 /// [`from`]: trait.From.html#tymethod.from
 /// [book]: ../../book/ch09-00-error-handling.html
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -422,7 +422,7 @@ pub trait TryInto<T>: Sized {
 ///
 /// # Generic Implementations
 ///
-/// - `TryFrom<T> for U` implies [`TryInto<U>`]` for T`
+/// - `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 `Infallible`.
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 43c1a3b7767..2f6d745d146 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -886,7 +886,7 @@ pub trait Pointer {
 ///
 /// # Examples
 ///
-/// Basic usage with `i32`:
+/// Basic usage with `f64`:
 ///
 /// ```
 /// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
@@ -929,7 +929,7 @@ pub trait LowerExp {
 ///
 /// # Examples
 ///
-/// Basic usage with `f32`:
+/// Basic usage with `f64`:
 ///
 /// ```
 /// let x = 42.0; // 42.0 is '4.2E1' in scientific notation
diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs
index 504330a023b..3f76ac20192 100644
--- a/src/libcore/future/future.rs
+++ b/src/libcore/future/future.rs
@@ -23,7 +23,7 @@ use crate::task::{Context, Poll};
 /// When using a future, you generally won't call `poll` directly, but instead
 /// `await!` the value.
 #[doc(spotlight)]
-#[must_use = "futures do nothing unless polled"]
+#[must_use = "futures do nothing unless you `.await` or poll them"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub trait Future {
     /// The type of value produced on completion.
diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs
index 518442efe74..64e588f65b4 100644
--- a/src/libcore/iter/adapters/mod.rs
+++ b/src/libcore/iter/adapters/mod.rs
@@ -73,6 +73,11 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
     {
         self.iter.position(predicate)
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 403f3358105..38c7c9bc4d0 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -356,7 +356,7 @@ pub trait Iterator {
     ///
     /// ```
     /// let a = [0, 1, 2, 3, 4, 5];
-    /// let mut iter = a.into_iter().step_by(2);
+    /// let mut iter = a.iter().step_by(2);
     ///
     /// assert_eq!(iter.next(), Some(&0));
     /// assert_eq!(iter.next(), Some(&2));
@@ -531,7 +531,7 @@ pub trait Iterator {
     /// ```
     /// let a = [1, 2, 3];
     ///
-    /// let mut iter = a.into_iter().map(|x| 2 * x);
+    /// let mut iter = a.iter().map(|x| 2 * x);
     ///
     /// assert_eq!(iter.next(), Some(2));
     /// assert_eq!(iter.next(), Some(4));
@@ -620,7 +620,7 @@ pub trait Iterator {
     /// ```
     /// let a = [0i32, 1, 2];
     ///
-    /// let mut iter = a.into_iter().filter(|x| x.is_positive());
+    /// let mut iter = a.iter().filter(|x| x.is_positive());
     ///
     /// assert_eq!(iter.next(), Some(&1));
     /// assert_eq!(iter.next(), Some(&2));
@@ -634,7 +634,7 @@ pub trait Iterator {
     /// ```
     /// let a = [0, 1, 2];
     ///
-    /// let mut iter = a.into_iter().filter(|x| **x > 1); // need two *s!
+    /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s!
     ///
     /// assert_eq!(iter.next(), Some(&2));
     /// assert_eq!(iter.next(), None);
@@ -646,7 +646,7 @@ pub trait Iterator {
     /// ```
     /// let a = [0, 1, 2];
     ///
-    /// let mut iter = a.into_iter().filter(|&x| *x > 1); // both & and *
+    /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and *
     ///
     /// assert_eq!(iter.next(), Some(&2));
     /// assert_eq!(iter.next(), None);
@@ -657,7 +657,7 @@ pub trait Iterator {
     /// ```
     /// let a = [0, 1, 2];
     ///
-    /// let mut iter = a.into_iter().filter(|&&x| x > 1); // two &s
+    /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s
     ///
     /// assert_eq!(iter.next(), Some(&2));
     /// assert_eq!(iter.next(), None);
@@ -837,7 +837,7 @@ pub trait Iterator {
     /// ```
     /// let a = [-1i32, 0, 1];
     ///
-    /// let mut iter = a.into_iter().skip_while(|x| x.is_negative());
+    /// let mut iter = a.iter().skip_while(|x| x.is_negative());
     ///
     /// assert_eq!(iter.next(), Some(&0));
     /// assert_eq!(iter.next(), Some(&1));
@@ -851,7 +851,7 @@ pub trait Iterator {
     /// ```
     /// let a = [-1, 0, 1];
     ///
-    /// let mut iter = a.into_iter().skip_while(|x| **x < 0); // need two *s!
+    /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s!
     ///
     /// assert_eq!(iter.next(), Some(&0));
     /// assert_eq!(iter.next(), Some(&1));
@@ -863,7 +863,7 @@ pub trait Iterator {
     /// ```
     /// let a = [-1, 0, 1, -2];
     ///
-    /// let mut iter = a.into_iter().skip_while(|x| **x < 0);
+    /// let mut iter = a.iter().skip_while(|x| **x < 0);
     ///
     /// assert_eq!(iter.next(), Some(&0));
     /// assert_eq!(iter.next(), Some(&1));
@@ -898,7 +898,7 @@ pub trait Iterator {
     /// ```
     /// let a = [-1i32, 0, 1];
     ///
-    /// let mut iter = a.into_iter().take_while(|x| x.is_negative());
+    /// let mut iter = a.iter().take_while(|x| x.is_negative());
     ///
     /// assert_eq!(iter.next(), Some(&-1));
     /// assert_eq!(iter.next(), None);
@@ -911,7 +911,7 @@ pub trait Iterator {
     /// ```
     /// let a = [-1, 0, 1];
     ///
-    /// let mut iter = a.into_iter().take_while(|x| **x < 0); // need two *s!
+    /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s!
     ///
     /// assert_eq!(iter.next(), Some(&-1));
     /// assert_eq!(iter.next(), None);
@@ -922,7 +922,7 @@ pub trait Iterator {
     /// ```
     /// let a = [-1, 0, 1, -2];
     ///
-    /// let mut iter = a.into_iter().take_while(|x| **x < 0);
+    /// let mut iter = a.iter().take_while(|x| **x < 0);
     ///
     /// assert_eq!(iter.next(), Some(&-1));
     ///
@@ -937,7 +937,7 @@ pub trait Iterator {
     ///
     /// ```
     /// let a = [1, 2, 3, 4];
-    /// let mut iter = a.into_iter();
+    /// let mut iter = a.iter();
     ///
     /// let result: Vec<i32> = iter.by_ref()
     ///                            .take_while(|n| **n != 3)
@@ -1321,7 +1321,7 @@ pub trait Iterator {
     /// ```
     /// let a = [1, 2, 3];
     ///
-    /// let iter = a.into_iter();
+    /// let iter = a.iter();
     ///
     /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i );
     ///
@@ -1334,7 +1334,7 @@ pub trait Iterator {
     /// // let's try that again
     /// let a = [1, 2, 3];
     ///
-    /// let mut iter = a.into_iter();
+    /// let mut iter = a.iter();
     ///
     /// // instead, we add in a .by_ref()
     /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i );
@@ -1479,7 +1479,7 @@ pub trait Iterator {
     /// let a = [1, 2, 3];
     ///
     /// let (even, odd): (Vec<i32>, Vec<i32>) = a
-    ///     .into_iter()
+    ///     .iter()
     ///     .partition(|&n| n % 2 == 0);
     ///
     /// assert_eq!(even, vec![2]);
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 28db55578c3..4a70329b64b 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -125,7 +125,7 @@
 #![feature(structural_match)]
 #![feature(abi_unadjusted)]
 #![feature(adx_target_feature)]
-#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
+#![feature(maybe_uninit_slice, maybe_uninit_array)]
 #![feature(external_doc)]
 
 #[prelude_import]
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 9fb071d2952..24bee6355a7 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -63,62 +63,6 @@ pub use crate::intrinsics::transmute;
 /// The practical use cases for `forget` are rather specialized and mainly come
 /// up in unsafe or FFI code.
 ///
-/// ## Use case 1
-///
-/// You have created an uninitialized value using [`mem::uninitialized`][uninit].
-/// You must either initialize or `forget` it on every computation path before
-/// Rust drops it automatically, like at the end of a scope or after a panic.
-/// Running the destructor on an uninitialized value would be [undefined behavior][ub].
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// # let some_condition = false;
-/// unsafe {
-///     let mut uninit_vec: Vec<u32> = mem::uninitialized();
-///
-///     if some_condition {
-///         // Initialize the variable.
-///         ptr::write(&mut uninit_vec, Vec::new());
-///     } else {
-///         // Forget the uninitialized value so its destructor doesn't run.
-///         mem::forget(uninit_vec);
-///     }
-/// }
-/// ```
-///
-/// ## Use case 2
-///
-/// You have duplicated the bytes making up a value, without doing a proper
-/// [`Clone`][clone]. You need the value's destructor to run only once,
-/// because a double `free` is undefined behavior.
-///
-/// An example is a possible implementation of [`mem::swap`][swap]:
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// # #[allow(dead_code)]
-/// fn swap<T>(x: &mut T, y: &mut T) {
-///     unsafe {
-///         // Give ourselves some scratch space to work with
-///         let mut t: T = mem::uninitialized();
-///
-///         // Perform the swap, `&mut` pointers never alias
-///         ptr::copy_nonoverlapping(&*x, &mut t, 1);
-///         ptr::copy_nonoverlapping(&*y, x, 1);
-///         ptr::copy_nonoverlapping(&t, y, 1);
-///
-///         // y and t now point to the same thing, but we need to completely
-///         // forget `t` because we do not want to run the destructor for `T`
-///         // on its value, which is still owned somewhere outside this function.
-///         mem::forget(t);
-///     }
-/// }
-/// ```
-///
 /// [drop]: fn.drop.html
 /// [uninit]: fn.uninitialized.html
 /// [clone]: ../clone/trait.Clone.html
@@ -465,29 +409,37 @@ pub const fn needs_drop<T>() -> bool {
 
 /// Creates a value whose bytes are all zero.
 ///
-/// This has the same effect as allocating space with
-/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for
-/// FFI sometimes, but should generally be avoided.
+/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
+/// It is useful for FFI sometimes, but should generally be avoided.
 ///
 /// There is no guarantee that an all-zero byte-pattern represents a valid value of
-/// some type `T`. If `T` has a destructor and the value is destroyed (due to
-/// a panic or the end of a scope) before being initialized, then the destructor
-/// will run on zeroed data, likely leading to [undefined behavior][ub].
-///
-/// See also the documentation for [`mem::uninitialized`][uninit], which has
-/// many of the same caveats.
+/// some type `T`. For example, the all-zero byte-pattern is not a valid value
+/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types
+/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv]
+/// that there always is a valid value in a variable it considers initialized.
 ///
-/// [uninit]: fn.uninitialized.html
+/// [zeroed]: union.MaybeUninit.html#method.zeroed
 /// [ub]: ../../reference/behavior-considered-undefined.html
+/// [inv]: union.MaybeUninit.html#initialization-invariant
 ///
 /// # Examples
 ///
+/// Correct usage of this function: initializing an integer with zero.
+///
 /// ```
 /// use std::mem;
 ///
 /// let x: i32 = unsafe { mem::zeroed() };
 /// assert_eq!(0, x);
 /// ```
+///
+/// *Incorrect* usage of this function: initializing a reference with zero.
+///
+/// ```no_run
+/// use std::mem;
+///
+/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
+/// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn zeroed<T>() -> T {
@@ -498,130 +450,23 @@ pub unsafe fn zeroed<T>() -> T {
 /// Bypasses Rust's normal memory-initialization checks by pretending to
 /// produce a value of type `T`, while doing nothing at all.
 ///
-/// **This is incredibly dangerous and should not be done lightly. Deeply
-/// consider initializing your memory with a default value instead.**
-///
-/// This is useful for FFI functions and initializing arrays sometimes,
-/// but should generally be avoided.
-///
-/// # Undefined behavior
-///
-/// It is [undefined behavior][ub] to read uninitialized memory, even just an
-/// uninitialized boolean. For instance, if you branch on the value of such
-/// a boolean, your program may take one, both, or neither of the branches.
-///
-/// Writing to the uninitialized value is similarly dangerous. Rust believes the
-/// value is initialized, and will therefore try to [`Drop`] the uninitialized
-/// value and its fields if you try to overwrite it in a normal manner. The only way
-/// to safely initialize an uninitialized value is with [`ptr::write`][write],
-/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no].
-///
-/// If the value does implement [`Drop`], it must be initialized before
-/// it goes out of scope (and therefore would be dropped). Note that this
-/// includes a `panic` occurring and unwinding the stack suddenly.
+/// **This functon is deprecated.** Use [`MaybeUninit<T>`] instead.
 ///
-/// If you partially initialize an array, you may need to use
-/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully
-/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running
-/// on the array. If a partially allocated array is dropped this will lead to
-/// undefined behaviour.
-///
-/// # Examples
-///
-/// Here's how to safely initialize an array of [`Vec`]s.
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// // Only declare the array. This safely leaves it
-/// // uninitialized in a way that Rust will track for us.
-/// // However we can't initialize it element-by-element
-/// // safely, and we can't use the `[value; 1000]`
-/// // constructor because it only works with `Copy` data.
-/// let mut data: [Vec<u32>; 1000];
-///
-/// unsafe {
-///     // So we need to do this to initialize it.
-///     data = mem::uninitialized();
-///
-///     // DANGER ZONE: if anything panics or otherwise
-///     // incorrectly reads the array here, we will have
-///     // Undefined Behavior.
-///
-///     // It's ok to mutably iterate the data, since this
-///     // doesn't involve reading it at all.
-///     // (ptr and len are statically known for arrays)
-///     for elem in &mut data[..] {
-///         // *elem = Vec::new() would try to drop the
-///         // uninitialized memory at `elem` -- bad!
-///         //
-///         // Vec::new doesn't allocate or do really
-///         // anything. It's only safe to call here
-///         // because we know it won't panic.
-///         ptr::write(elem, Vec::new());
-///     }
-///
-///     // SAFE ZONE: everything is initialized.
-/// }
-///
-/// println!("{:?}", &data[0]);
-/// ```
-///
-/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized`
-/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a
-/// value that is only [`Clone`], so the following is semantically equivalent and
-/// vastly less dangerous, as long as you can live with an extra heap
-/// allocation:
-///
-/// ```
-/// let data: Vec<Vec<u32>> = vec![Vec::new(); 1000];
-/// println!("{:?}", &data[0]);
-/// ```
-///
-/// This example shows how to handle partially initialized arrays, which could
-/// be found in low-level datastructures.
-///
-/// ```
-/// use std::mem;
-/// use std::ptr;
-///
-/// // Count the number of elements we have assigned.
-/// let mut data_len: usize = 0;
-/// let mut data: [String; 1000];
-///
-/// unsafe {
-///     data = mem::uninitialized();
-///
-///     for elem in &mut data[0..500] {
-///         ptr::write(elem, String::from("hello"));
-///         data_len += 1;
-///     }
-///
-///     // For each item in the array, drop if we allocated it.
-///     for i in &mut data[0..data_len] {
-///         ptr::drop_in_place(i);
-///     }
-/// }
-/// // Forget the data. If this is allowed to drop, you may see a crash such as:
-/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object
-/// // 0x7ff3b8402920: pointer being freed was not allocated'
-/// mem::forget(data);
-/// ```
+/// The reason for deprecation is that the function basically cannot be used
+/// correctly: [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
+/// is special in that the compiler knows that it does not have a fixed value.
+/// This makes it undefined behavior to have uninitialized data in a variable even
+/// if that variable has an integer type.
+/// (Notice that the rules around uninitialized integers are not finalized yet, but
+/// until they are, it is advisable to avoid them.)
 ///
-/// [`Vec`]: ../../std/vec/struct.Vec.html
-/// [`vec!`]: ../../std/macro.vec.html
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [write]: ../ptr/fn.write.html
-/// [drop_in_place]: ../ptr/fn.drop_in_place.html
-/// [mem_zeroed]: fn.zeroed.html
-/// [mem_forget]: fn.forget.html
-/// [copy]: ../intrinsics/fn.copy.html
-/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html
-/// [`Drop`]: ../ops/trait.Drop.html
+/// [`MaybeUninit<T>`]: union.MaybeUninit.html
+/// [inv]: union.MaybeUninit.html#initialization-invariant
 #[inline]
-#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")]
+#[rustc_deprecated(since = "1.40.0", reason = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn uninitialized<T>() -> T {
     intrinsics::panic_if_uninhabited::<T>();
@@ -899,7 +744,6 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
     }
 }
 
-// FIXME: Reference `MaybeUninit` from these docs, once that is stable.
 /// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
 ///
 /// This wrapper is 0-cost.
@@ -908,6 +752,7 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// As a consequence, it has *no effect* on the assumptions that the compiler makes
 /// about all values being initialized at their type.  In particular, initializing
 /// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
+/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
 ///
 /// # Examples
 ///
@@ -942,6 +787,7 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// ```
 ///
 /// [`mem::zeroed`]: fn.zeroed.html
+/// [`MaybeUninit<T>`]: union.MaybeUninit.html
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -1042,17 +888,18 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
     }
 }
 
-/// A wrapper to construct uninitialized instances of `T`.
+/// A wrapper type to construct uninitialized instances of `T`.
+///
+/// # Initialization invariant
 ///
 /// The compiler, in general, assumes that variables are properly initialized
 /// at their respective type. For example, a variable of reference type must
 /// be aligned and non-NULL. This is an invariant that must *always* be upheld,
 /// even in unsafe code. As a consequence, zero-initializing a variable of reference
-/// type causes instantaneous undefined behavior, no matter whether that reference
+/// type causes instantaneous [undefined behavior][ub], no matter whether that reference
 /// ever gets used to access memory:
 ///
 /// ```rust,no_run
-/// #![feature(maybe_uninit)]
 /// use std::mem::{self, MaybeUninit};
 ///
 /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
@@ -1067,7 +914,6 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 /// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior:
 ///
 /// ```rust,no_run
-/// #![feature(maybe_uninit)]
 /// use std::mem::{self, MaybeUninit};
 ///
 /// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior!
@@ -1078,10 +924,9 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 /// Moreover, uninitialized memory is special in that the compiler knows that
 /// it does not have a fixed value. This makes it undefined behavior to have
 /// uninitialized data in a variable even if that variable has an integer type,
-/// which otherwise can hold any bit pattern:
+/// which otherwise can hold any *fixed* bit pattern:
 ///
 /// ```rust,no_run
-/// #![feature(maybe_uninit)]
 /// use std::mem::{self, MaybeUninit};
 ///
 /// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
@@ -1091,37 +936,154 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 /// (Notice that the rules around uninitialized integers are not finalized yet, but
 /// until they are, it is advisable to avoid them.)
 ///
+/// On top of that, remember that most types have additional invariants beyond merely
+/// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`]
+/// is considered initialized because the only requirement the compiler knows about it
+/// is that the data pointer must be non-null. Creating such a `Vec<T>` does not cause
+/// *immediate* undefined behavior, but will cause undefined behavior with most
+/// safe operations (including dropping it).
+///
+/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
+///
+/// # Examples
+///
 /// `MaybeUninit<T>` serves to enable unsafe code to deal with uninitialized data.
 /// It is a signal to the compiler indicating that the data here might *not*
 /// be initialized:
 ///
 /// ```rust
-/// #![feature(maybe_uninit)]
 /// use std::mem::MaybeUninit;
 ///
 /// // Create an explicitly uninitialized reference. The compiler knows that data inside
 /// // a `MaybeUninit<T>` may be invalid, and hence this is not UB:
 /// let mut x = MaybeUninit::<&i32>::uninit();
 /// // Set it to a valid value.
-/// x.write(&0);
+/// unsafe { x.as_mut_ptr().write(&0); }
 /// // Extract the initialized data -- this is only allowed *after* properly
 /// // initializing `x`!
 /// let x = unsafe { x.assume_init() };
 /// ```
 ///
 /// The compiler then knows to not make any incorrect assumptions or optimizations on this code.
-//
-// FIXME before stabilizing, explain how to initialize a struct field-by-field.
+///
+/// ## out-pointers
+///
+/// You can use `MaybeUninit<T>` to implement "out-pointers": instead of returning data
+/// from a function, pass it a pointer to some (uninitialized) memory to put the
+/// result into. This can be useful when it is important for the caller to control
+/// how the memory the result is stored in gets allocated, and you want to avoid
+/// unnecessary moves.
+///
+/// ```
+/// use std::mem::MaybeUninit;
+///
+/// unsafe fn make_vec(out: *mut Vec<i32>) {
+///     // `write` does not drop the old contents, which is important.
+///     out.write(vec![1, 2, 3]);
+/// }
+///
+/// let mut v: MaybeUninit<Vec<i32>> = MaybeUninit::uninit();
+/// unsafe { make_vec(v.as_mut_ptr()); }
+/// // Now we know `v` is initialized! This also makes sure the vector gets
+/// // properly dropped.
+/// let v = unsafe { v.assume_init() };
+/// assert_eq!(&v, &[1, 2, 3]);
+/// ```
+///
+/// ## Initializing an array element-by-element
+///
+/// `MaybeUninit<T>` can be used to initialize a large array element-by-element:
+///
+/// ```
+/// use std::mem::{self, MaybeUninit};
+/// use std::ptr;
+///
+/// let data = {
+///     // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+///     // safe because the type we are claiming to have initialized here is a
+///     // bunch of `MaybeUninit`s, which do not require initialization.
+///     let mut data: [MaybeUninit<Vec<u32>>; 1000] = unsafe {
+///         MaybeUninit::uninit().assume_init()
+///     };
+///
+///     // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop,
+///     // we have a memory leak, but there is no memory safety issue.
+///     for elem in &mut data[..] {
+///         unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); }
+///     }
+///
+///     // Everything is initialized. Transmute the array to the
+///     // initialized type.
+///     unsafe { mem::transmute::<_, [Vec<u32>; 1000]>(data) }
+/// };
+///
+/// assert_eq!(&data[0], &[42]);
+/// ```
+///
+/// You can also work with partially initialized arrays, which could
+/// be found in low-level datastructures.
+///
+/// ```
+/// use std::mem::MaybeUninit;
+/// use std::ptr;
+///
+/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
+/// // safe because the type we are claiming to have initialized here is a
+/// // bunch of `MaybeUninit`s, which do not require initialization.
+/// let mut data: [MaybeUninit<String>; 1000] = unsafe { MaybeUninit::uninit().assume_init() };
+/// // Count the number of elements we have assigned.
+/// let mut data_len: usize = 0;
+///
+/// for elem in &mut data[0..500] {
+///     unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); }
+///     data_len += 1;
+/// }
+///
+/// // For each item in the array, drop if we allocated it.
+/// for elem in &mut data[0..data_len] {
+///     unsafe { ptr::drop_in_place(elem.as_mut_ptr()); }
+/// }
+/// ```
+///
+/// ## Initializing a struct field-by-field
+///
+/// There is currently no supported way to create a raw pointer or reference
+/// to a field of a struct inside `MaybeUninit<Struct>`. That means it is not possible
+/// to create a struct by calling `MaybeUninit::uninit::<Struct>()` and then writing
+/// to its fields.
+///
+/// [ub]: ../../reference/behavior-considered-undefined.html
+///
+/// # Layout
+///
+/// `MaybeUninit<T>` is guaranteed to have the same size and alignment as `T`:
+///
+/// ```rust
+/// use std::mem::{MaybeUninit, size_of, align_of};
+/// assert_eq!(size_of::<MaybeUninit<u64>>(), size_of::<u64>());
+/// assert_eq!(align_of::<MaybeUninit<u64>>(), align_of::<u64>());
+/// ```
+///
+/// However remember that a type *containing* a `MaybeUninit<T>` is not necessarily the same
+/// layout; Rust does not in general guarantee that the fields of a `Foo<T>` have the same order as
+/// a `Foo<U>` even if `T` and `U` have the same size and alignment. Furthermore because any bit
+/// value is valid for a `MaybeUninit<T>` the compiler can't apply non-zero/niche-filling
+/// optimizations, potentially resulting in a larger size:
+///
+/// ```rust
+/// # use std::mem::{MaybeUninit, size_of, align_of};
+/// assert_eq!(size_of::<Option<bool>>(), 1);
+/// assert_eq!(size_of::<Option<MaybeUninit<bool>>>(), 2);
+/// ```
 #[allow(missing_debug_implementations)]
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[stable(feature = "maybe_uninit", since = "1.36.0")]
 #[derive(Copy)]
-// NOTE: after stabilizing `MaybeUninit`, proceed to deprecate `mem::uninitialized`.
 pub union MaybeUninit<T> {
     uninit: (),
     value: ManuallyDrop<T>,
 }
 
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[stable(feature = "maybe_uninit", since = "1.36.0")]
 impl<T: Copy> Clone for MaybeUninit<T> {
     #[inline(always)]
     fn clone(&self) -> Self {
@@ -1132,10 +1094,13 @@ impl<T: Copy> Clone for MaybeUninit<T> {
 
 impl<T> MaybeUninit<T> {
     /// Creates a new `MaybeUninit<T>` initialized with the given value.
+    /// It is safe to call [`assume_init`] on the return value of this function.
     ///
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    ///
+    /// [`assume_init`]: #method.assume_init
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub const fn new(val: T) -> MaybeUninit<T> {
         MaybeUninit { value: ManuallyDrop::new(val) }
@@ -1145,7 +1110,11 @@ impl<T> MaybeUninit<T> {
     ///
     /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
     /// It is your responsibility to make sure `T` gets dropped if it got initialized.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    ///
+    /// See the [type-level documentation][type] for some examples.
+    ///
+    /// [type]: union.MaybeUninit.html
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub const fn uninit() -> MaybeUninit<T> {
         MaybeUninit { uninit: () }
@@ -1166,7 +1135,6 @@ impl<T> MaybeUninit<T> {
     /// fields of the struct can hold the bit-pattern 0 as a valid value.
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let x = MaybeUninit::<(u8, bool)>::zeroed();
@@ -1178,7 +1146,6 @@ impl<T> MaybeUninit<T> {
     /// cannot hold 0 as a valid value.
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// enum NotZero { One = 1, Two = 2 };
@@ -1188,7 +1155,7 @@ impl<T> MaybeUninit<T> {
     /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant.
     /// // This is undefined behavior.
     /// ```
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline]
     pub fn zeroed() -> MaybeUninit<T> {
         let mut u = MaybeUninit::<T>::uninit();
@@ -1202,7 +1169,7 @@ impl<T> MaybeUninit<T> {
     /// without dropping it, so be careful not to use this twice unless you want to
     /// skip running the destructor. For your convenience, this also returns a mutable
     /// reference to the (now safely initialized) contents of `self`.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[unstable(feature = "maybe_uninit_extra", issue = "53491")]
     #[inline(always)]
     pub fn write(&mut self, val: T) -> &mut T {
         unsafe {
@@ -1213,13 +1180,14 @@ impl<T> MaybeUninit<T> {
 
     /// Gets a pointer to the contained value. Reading from this pointer or turning it
     /// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized.
+    /// Writing to memory that this pointer (non-transitively) points to is undefined behavior
+    /// (except inside an `UnsafeCell<T>`).
     ///
     /// # Examples
     ///
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
@@ -1232,7 +1200,6 @@ impl<T> MaybeUninit<T> {
     /// *Incorrect* usage of this method:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let x = MaybeUninit::<Vec<u32>>::uninit();
@@ -1242,7 +1209,7 @@ impl<T> MaybeUninit<T> {
     ///
     /// (Notice that the rules around references to uninitialized data are not finalized yet, but
     /// until they are, it is advisable to avoid them.)
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub fn as_ptr(&self) -> *const T {
         unsafe { &*self.value as *const T }
@@ -1256,7 +1223,6 @@ impl<T> MaybeUninit<T> {
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
@@ -1271,7 +1237,6 @@ impl<T> MaybeUninit<T> {
     /// *Incorrect* usage of this method:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
@@ -1281,7 +1246,7 @@ impl<T> MaybeUninit<T> {
     ///
     /// (Notice that the rules around references to uninitialized data are not finalized yet, but
     /// until they are, it is advisable to avoid them.)
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub fn as_mut_ptr(&mut self) -> *mut T {
         unsafe { &mut *self.value as *mut T }
@@ -1294,15 +1259,17 @@ impl<T> MaybeUninit<T> {
     /// # Safety
     ///
     /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
-    /// state. Calling this when the content is not yet fully initialized causes undefined
-    /// behavior.
+    /// state. Calling this when the content is not yet fully initialized causes immediate undefined
+    /// behavior. The [type-level documentation][inv] contains more information about
+    /// this initialization invariant.
+    ///
+    /// [inv]: #initialization-invariant
     ///
     /// # Examples
     ///
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<bool>::uninit();
@@ -1314,14 +1281,13 @@ impl<T> MaybeUninit<T> {
     /// *Incorrect* usage of this method:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit)]
     /// use std::mem::MaybeUninit;
     ///
     /// let x = MaybeUninit::<Vec<u32>>::uninit();
     /// let x_init = unsafe { x.assume_init() };
     /// // `x` had not been initialized yet, so this last line caused undefined behavior.
     /// ```
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[stable(feature = "maybe_uninit", since = "1.36.0")]
     #[inline(always)]
     pub unsafe fn assume_init(self) -> T {
         intrinsics::panic_if_uninhabited::<T>();
@@ -1338,13 +1304,15 @@ impl<T> MaybeUninit<T> {
     ///
     /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
     /// state. Calling this when the content is not yet fully initialized causes undefined
-    /// behavior.
+    /// behavior. The [type-level documentation][inv] contains more information about
+    /// this initialization invariant.
     ///
     /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
     /// multiple copies of the data (by calling `read` multiple times, or first
     /// calling `read` and then [`assume_init`]), it is your responsibility
     /// to ensure that that data may indeed be duplicated.
     ///
+    /// [inv]: #initialization-invariant
     /// [`assume_init`]: #method.assume_init
     ///
     /// # Examples
@@ -1352,7 +1320,7 @@ impl<T> MaybeUninit<T> {
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit)]
+    /// #![feature(maybe_uninit_extra)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<u32>::uninit();
@@ -1373,7 +1341,7 @@ impl<T> MaybeUninit<T> {
     /// *Incorrect* usage of this method:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit)]
+    /// #![feature(maybe_uninit_extra)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
@@ -1383,7 +1351,7 @@ impl<T> MaybeUninit<T> {
     /// // We now created two copies of the same vector, leading to a double-free when
     /// // they both get dropped!
     /// ```
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[unstable(feature = "maybe_uninit_extra", issue = "53491")]
     #[inline(always)]
     pub unsafe fn read(&self) -> T {
         intrinsics::panic_if_uninhabited::<T>();
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 6355bcdcab2..006b1e143ee 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -155,12 +155,12 @@ pub use crate::intrinsics::write_bytes;
 /// location first:
 /// ```
 /// use std::ptr;
-/// use std::mem;
+/// use std::mem::{self, MaybeUninit};
 ///
 /// unsafe fn drop_after_copy<T>(to_drop: *mut T) {
-///     let mut copy: T = mem::uninitialized();
-///     ptr::copy(to_drop, &mut copy, 1);
-///     drop(copy);
+///     let mut copy: MaybeUninit<T> = MaybeUninit::uninit();
+///     ptr::copy(to_drop, copy.as_mut_ptr(), 1);
+///     drop(copy.assume_init());
 /// }
 ///
 /// #[repr(packed, C)]
@@ -374,10 +374,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
     // #[repr(simd)], even if we don't actually use this struct directly.
     //
     // FIXME repr(simd) broken on emscripten and redox
-    // It's also broken on big-endian powerpc64 and s390x.  #42778
-    #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox",
-                       target_endian = "big")),
-               repr(simd))]
+    #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox")), repr(simd))]
     struct Block(u64, u64, u64, u64);
     struct UnalignedBlock(u64, u64, u64, u64);
 
@@ -813,9 +810,6 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
-/// Memory accessed with `read_volatile` or [`write_volatile`] should not be
-/// accessed with non-volatile operations.
-///
 /// [`write_volatile`]: ./fn.write_volatile.html
 ///
 /// # Notes
@@ -840,7 +834,7 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 ///
 /// * `src` must be properly aligned.
 ///
-/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of
+/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of
 /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
 /// value and the value at `*src` can [violate memory safety][read-ownership].
 /// However, storing non-[`Copy`] types in volatile memory is almost certainly
@@ -884,9 +878,6 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
-/// Memory accessed with [`read_volatile`] or `write_volatile` should not be
-/// accessed with non-volatile operations.
-///
 /// `write_volatile` does not drop the contents of `dst`. This is safe, but it
 /// could leak allocations or resources, so care should be taken not to overwrite
 /// an object that should be dropped.
@@ -2973,7 +2964,6 @@ impl<T: Sized> NonNull<T> {
     /// some other means.
     #[stable(feature = "nonnull", since = "1.25.0")]
     #[inline]
-    #[rustc_const_unstable(feature = "const_ptr_nonnull")]
     pub const fn dangling() -> Self {
         unsafe {
             let ptr = mem::align_of::<T>() as *mut T;
@@ -3037,7 +3027,6 @@ impl<T: ?Sized> NonNull<T> {
     /// Cast to a pointer of another type
     #[stable(feature = "nonnull_cast", since = "1.27.0")]
     #[inline]
-    #[rustc_const_unstable(feature = "const_ptr_nonnull")]
     pub const fn cast<U>(self) -> NonNull<U> {
         unsafe {
             NonNull::new_unchecked(self.as_ptr() as *mut U)
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 8731f486753..d06d107d32a 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -359,6 +359,10 @@ impl<T> [T] {
     /// The caller must ensure that the slice outlives the pointer this
     /// function returns, or else it will end up pointing to garbage.
     ///
+    /// The caller must also ensure that the memory the pointer (non-transitively) points to
+    /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+    /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+    ///
     /// Modifying the container referenced by this slice may cause its buffer
     /// to be reallocated, which would also make any pointers to it invalid.
     ///
@@ -374,6 +378,8 @@ impl<T> [T] {
     ///     }
     /// }
     /// ```
+    ///
+    /// [`as_mut_ptr`]: #method.as_mut_ptr
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub const fn as_ptr(&self) -> *const T {
@@ -3541,6 +3547,11 @@ impl<'a, T, P> Iterator for Split<'a, T, P> where P: FnMut(&T) -> bool {
             (1, Some(self.v.len() + 1))
         }
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -3639,6 +3650,11 @@ impl<'a, T, P> Iterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {
             (1, Some(self.v.len() + 1))
         }
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -3704,6 +3720,11 @@ impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "slice_rsplit", since = "1.27.0")]
@@ -3768,6 +3789,11 @@ impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "slice_rsplit", since = "1.27.0")]
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 45421848cec..0e8a2da3c11 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -1333,6 +1333,11 @@ impl<'a> Iterator for Lines<'a> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.0.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1379,6 +1384,11 @@ impl<'a> Iterator for LinesAny<'a> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.0.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2188,7 +2198,11 @@ impl str {
     /// [`u8`]. This pointer will be pointing to the first byte of the string
     /// slice.
     ///
+    /// The caller must ensure that the returned pointer is never written to.
+    /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`].
+    ///
     /// [`u8`]: primitive.u8.html
+    /// [`as_mut_ptr`]: #method.as_mut_ptr
     ///
     /// # Examples
     ///
@@ -4217,6 +4231,11 @@ impl<'a> Iterator for SplitWhitespace<'a> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "split_whitespace", since = "1.1.0")]
@@ -4243,6 +4262,11 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs
index b4e91249832..a6d611d2e93 100644
--- a/src/libcore/task/wake.rs
+++ b/src/libcore/task/wake.rs
@@ -10,6 +10,8 @@ use crate::marker::{PhantomData, Unpin};
 ///
 /// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
 /// customizes the behavior of the `RawWaker`.
+///
+/// [`Waker`]: struct.Waker.html
 #[derive(PartialEq, Debug)]
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub struct RawWaker {
@@ -55,6 +57,8 @@ impl RawWaker {
 /// pointer of a properly constructed [`RawWaker`] object from inside the
 /// [`RawWaker`] implementation. Calling one of the contained functions using
 /// any other `data` pointer will cause undefined behavior.
+///
+/// [`RawWaker`]: struct.RawWaker.html
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct RawWakerVTable {
@@ -65,6 +69,9 @@ pub struct RawWakerVTable {
     /// required for this additional instance of a [`RawWaker`] and associated
     /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
     /// of the same task that would have been awoken by the original [`RawWaker`].
+    ///
+    /// [`Waker`]: struct.Waker.html
+    /// [`RawWaker`]: struct.RawWaker.html
     clone: unsafe fn(*const ()) -> RawWaker,
 
     /// This function will be called when `wake` is called on the [`Waker`].
@@ -73,6 +80,9 @@ pub struct RawWakerVTable {
     /// The implementation of this function must make sure to release any
     /// resources that are associated with this instance of a [`RawWaker`] and
     /// associated task.
+    ///
+    /// [`Waker`]: struct.Waker.html
+    /// [`RawWaker`]: struct.RawWaker.html
     wake: unsafe fn(*const ()),
 
     /// This function will be called when `wake_by_ref` is called on the [`Waker`].
@@ -80,6 +90,9 @@ pub struct RawWakerVTable {
     ///
     /// This function is similar to `wake`, but must not consume the provided data
     /// pointer.
+    ///
+    /// [`Waker`]: struct.Waker.html
+    /// [`RawWaker`]: struct.RawWaker.html
     wake_by_ref: unsafe fn(*const ()),
 
     /// This function gets called when a [`RawWaker`] gets dropped.
@@ -87,6 +100,8 @@ pub struct RawWakerVTable {
     /// The implementation of this function must make sure to release any
     /// resources that are associated with this instance of a [`RawWaker`] and
     /// associated task.
+    ///
+    /// [`RawWaker`]: struct.RawWaker.html
     drop: unsafe fn(*const ()),
 }
 
@@ -128,6 +143,9 @@ impl RawWakerVTable {
     /// The implementation of this function must make sure to release any
     /// resources that are associated with this instance of a [`RawWaker`] and
     /// associated task.
+    ///
+    /// [`Waker`]: struct.Waker.html
+    /// [`RawWaker`]: struct.RawWaker.html
     #[rustc_promotable]
     #[cfg_attr(stage0, unstable(feature = "futures_api_const_fn_ptr", issue = "50547"))]
     #[cfg_attr(not(stage0), stable(feature = "futures_api", since = "1.36.0"))]
@@ -201,6 +219,8 @@ impl fmt::Debug for Context<'_> {
 /// executor-specific wakeup behavior.
 ///
 /// Implements [`Clone`], [`Send`], and [`Sync`].
+///
+/// [`RawWaker`]: struct.RawWaker.html
 #[repr(transparent)]
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub struct Waker {
@@ -266,6 +286,9 @@ impl Waker {
     /// The behavior of the returned `Waker` is undefined if the contract defined
     /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
     /// Therefore this method is unsafe.
+    ///
+    /// [`RawWaker`]: struct.RawWaker.html
+    /// [`RawWakerVTable`]: struct.RawWakerVTable.html
     #[inline]
     #[stable(feature = "futures_api", since = "1.36.0")]
     pub unsafe fn from_raw(waker: RawWaker) -> Waker {
diff --git a/src/libcore/tests/alloc.rs b/src/libcore/tests/alloc.rs
new file mode 100644
index 00000000000..63537ba23d8
--- /dev/null
+++ b/src/libcore/tests/alloc.rs
@@ -0,0 +1,10 @@
+use core::alloc::Layout;
+
+#[test]
+fn const_unchecked_layout() {
+    const SIZE: usize = 0x2000;
+    const ALIGN: usize = 0x1000;
+    const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) };
+    assert_eq!(LAYOUT.size(), SIZE);
+    assert_eq!(LAYOUT.align(), ALIGN);
+}
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 025f7fb5cc6..c617596aba8 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -31,10 +31,12 @@
 #![feature(slice_partition_dedup)]
 #![feature(copy_within)]
 #![feature(int_error_matching)]
-#![deny(rust_2018_idioms)]
+#![feature(const_fn)]
+#![warn(rust_2018_idioms)]
 
 extern crate test;
 
+mod alloc;
 mod any;
 mod array;
 mod ascii;
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml
index 2468de99d60..4d50e80d4cf 100644
--- a/src/librustc/Cargo.toml
+++ b/src/librustc/Cargo.toml
@@ -36,7 +36,7 @@ byteorder = { version = "1.1", features = ["i128"]}
 chalk-engine = { version = "0.9.0", default-features=false }
 rustc_fs_util = { path = "../librustc_fs_util" }
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-measureme = "0.2.1"
+measureme = "0.3"
 
 # Note that these dependencies are a lie, they're just here to get linkage to
 # work.
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 2592af7d4ad..2e54165be1f 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -166,47 +166,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
             }
 
-            hir::ExprKind::If(ref cond, ref then, None) => {
-                //
-                //     [pred]
-                //       |
-                //       v 1
-                //     [cond]
-                //       |
-                //      / \
-                //     /   \
-                //    v 2   *
-                //  [then]  |
-                //    |     |
-                //    v 3   v 4
-                //   [..expr..]
-                //
-                let cond_exit = self.expr(&cond, pred);                // 1
-                let then_exit = self.expr(&then, cond_exit);          // 2
-                self.add_ast_node(expr.hir_id.local_id, &[cond_exit, then_exit])      // 3,4
-            }
-
-            hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
-                //
-                //     [pred]
-                //       |
-                //       v 1
-                //     [cond]
-                //       |
-                //      / \
-                //     /   \
-                //    v 2   v 3
-                //  [then][otherwise]
-                //    |     |
-                //    v 4   v 5
-                //   [..expr..]
-                //
-                let cond_exit = self.expr(&cond, pred);                // 1
-                let then_exit = self.expr(&then, cond_exit);          // 2
-                let else_exit = self.expr(&otherwise, cond_exit);      // 3
-                self.add_ast_node(expr.hir_id.local_id, &[then_exit, else_exit])      // 4, 5
-            }
-
             hir::ExprKind::While(ref cond, ref body, _) => {
                 //
                 //         [pred]
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 4c527f80d0f..b199eee6dad 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -12,6 +12,7 @@ use crate::hir;
 use crate::hir::def_id::DefId;
 use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use std::fmt::{self, Display};
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 #[derive(Copy, Clone, PartialEq)]
@@ -95,18 +96,18 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
     fn check_attributes(&self, item: &hir::Item, target: Target) {
         if target == Target::Fn || target == Target::Const {
             self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id_from_hir_id(item.hir_id));
-        } else if let Some(a) = item.attrs.iter().find(|a| a.check_name("target_feature")) {
+        } else if let Some(a) = item.attrs.iter().find(|a| a.check_name(sym::target_feature)) {
             self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function")
                 .span_label(item.span, "not a function")
                 .emit();
         }
 
         for attr in &item.attrs {
-            if attr.check_name("inline") {
+            if attr.check_name(sym::inline) {
                 self.check_inline(attr, &item.span, target)
-            } else if attr.check_name("non_exhaustive") {
+            } else if attr.check_name(sym::non_exhaustive) {
                 self.check_non_exhaustive(attr, item, target)
-            } else if attr.check_name("marker") {
+            } else if attr.check_name(sym::marker) {
                 self.check_marker(attr, item, target)
             }
         }
@@ -166,7 +167,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
         // ```
         let hints: Vec<_> = item.attrs
             .iter()
-            .filter(|attr| attr.check_name("repr"))
+            .filter(|attr| attr.check_name(sym::repr))
             .filter_map(|attr| attr.meta_item_list())
             .flatten()
             .collect();
@@ -177,9 +178,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
         let mut is_transparent = false;
 
         for hint in &hints {
-            let (article, allowed_targets) = match hint.name_or_empty().get() {
-                name @ "C" | name @ "align" => {
-                    is_c |= name == "C";
+            let (article, allowed_targets) = match hint.name_or_empty() {
+                name @ sym::C | name @ sym::align => {
+                    is_c |= name == sym::C;
                     if target != Target::Struct &&
                             target != Target::Union &&
                             target != Target::Enum {
@@ -188,7 +189,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                         continue
                     }
                 }
-                "packed" => {
+                sym::packed => {
                     if target != Target::Struct &&
                             target != Target::Union {
                                 ("a", "struct or union")
@@ -196,7 +197,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                         continue
                     }
                 }
-                "simd" => {
+                sym::simd => {
                     is_simd = true;
                     if target != Target::Struct {
                         ("a", "struct")
@@ -204,7 +205,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                         continue
                     }
                 }
-                "transparent" => {
+                sym::transparent => {
                     is_transparent = true;
                     if target != Target::Struct {
                         ("a", "struct")
@@ -212,9 +213,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                         continue
                     }
                 }
-                "i8"  | "u8"  | "i16" | "u16" |
-                "i32" | "u32" | "i64" | "u64" |
-                "isize" | "usize" => {
+                sym::i8  | sym::u8  | sym::i16 | sym::u16 |
+                sym::i32 | sym::u32 | sym::i64 | sym::u64 |
+                sym::isize | sym::usize => {
                     int_reprs += 1;
                     if target != Target::Enum {
                         ("an", "enum")
@@ -268,10 +269,10 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
         // When checking statements ignore expressions, they will be checked later
         if let hir::StmtKind::Local(ref l) = stmt.node {
             for attr in l.attrs.iter() {
-                if attr.check_name("inline") {
+                if attr.check_name(sym::inline) {
                     self.check_inline(attr, &stmt.span, Target::Statement);
                 }
-                if attr.check_name("repr") {
+                if attr.check_name(sym::repr) {
                     self.emit_repr_error(
                         attr.span,
                         stmt.span,
@@ -289,10 +290,10 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
             _ => Target::Expression,
         };
         for attr in expr.attrs.iter() {
-            if attr.check_name("inline") {
+            if attr.check_name(sym::inline) {
                 self.check_inline(attr, &expr.span, target);
             }
-            if attr.check_name("repr") {
+            if attr.check_name(sym::repr) {
                 self.emit_repr_error(
                     attr.span,
                     expr.span,
@@ -305,7 +306,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
 
     fn check_used(&self, item: &hir::Item, target: Target) {
         for attr in &item.attrs {
-            if attr.check_name("used") && target != Target::Static {
+            if attr.check_name(sym::used) && target != Target::Static {
                 self.tcx.sess
                     .span_err(attr.span, "attribute must be applied to a `static` variable");
             }
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index b268a1a494d..0c4f5fb3fc1 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -96,34 +96,20 @@ impl fmt::Display for CrateNum {
 impl serialize::UseSpecializedEncodable for CrateNum {}
 impl serialize::UseSpecializedDecodable for CrateNum {}
 
-/// A DefIndex is an index into the hir-map for a crate, identifying a
-/// particular definition. It should really be considered an interned
-/// shorthand for a particular DefPath.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
-pub struct DefIndex(u32);
-
-/// The crate root is always assigned index 0 by the AST Map code,
-/// thanks to `NodeCollector::new`.
-pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
+newtype_index! {
+    /// A DefIndex is an index into the hir-map for a crate, identifying a
+    /// particular definition. It should really be considered an interned
+    /// shorthand for a particular DefPath.
+    pub struct DefIndex {
+        DEBUG_FORMAT = "DefIndex({})",
 
-impl fmt::Debug for DefIndex {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "DefIndex({})", self.as_array_index())
+        /// The crate root is always assigned index 0 by the AST Map code,
+        /// thanks to `NodeCollector::new`.
+        const CRATE_DEF_INDEX = 0,
     }
 }
 
 impl DefIndex {
-    /// Converts this DefIndex into a zero-based array index.
-    #[inline]
-    pub fn as_array_index(&self) -> usize {
-        self.0 as usize
-    }
-
-    #[inline]
-    pub fn from_array_index(i: usize) -> DefIndex {
-        DefIndex(i as u32)
-    }
-
     // Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
     // function maps the index of the macro within the crate (which is also the
     // index of the macro in the CrateMetadata::proc_macros array) to the
@@ -132,7 +118,7 @@ impl DefIndex {
         // DefIndex for proc macros start from FIRST_FREE_DEF_INDEX,
         // because the first FIRST_FREE_DEF_INDEX indexes are reserved
         // for internal use.
-        let def_index = DefIndex::from_array_index(
+        let def_index = DefIndex::from(
             proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX)
                 .expect("integer overflow adding `proc_macro_index`"));
         assert!(def_index != CRATE_DEF_INDEX);
@@ -141,19 +127,11 @@ impl DefIndex {
 
     // This function is the reverse of from_proc_macro_index() above.
     pub fn to_proc_macro_index(self: DefIndex) -> usize {
-        self.as_array_index().checked_sub(FIRST_FREE_DEF_INDEX)
+        self.index().checked_sub(FIRST_FREE_DEF_INDEX)
             .unwrap_or_else(|| {
                 bug!("using local index {:?} as proc-macro index", self)
             })
     }
-
-    pub fn from_raw_u32(x: u32) -> DefIndex {
-        DefIndex(x)
-    }
-
-    pub fn as_raw_u32(&self) -> u32 {
-        self.0
-    }
 }
 
 impl serialize::UseSpecializedEncodable for DefIndex {}
@@ -169,7 +147,7 @@ pub struct DefId {
 
 impl fmt::Debug for DefId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "DefId({}:{}", self.krate, self.index.as_array_index())?;
+        write!(f, "DefId({}:{}", self.krate, self.index.index())?;
 
         ty::tls::with_opt(|opt_tcx| {
             if let Some(tcx) = opt_tcx {
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 0c73d97394f..38d6d710868 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -1032,11 +1032,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprKind::DropTemps(ref subexpression) => {
             visitor.visit_expr(subexpression);
         }
-        ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
-            visitor.visit_expr(head_expression);
-            visitor.visit_expr(if_block);
-            walk_list!(visitor, visit_expr, optional_else);
-        }
         ExprKind::While(ref subexpression, ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_expr(subexpression);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 4d5707560b0..3ec4d4e8cc8 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -62,8 +62,9 @@ use syntax::ext::hygiene::Mark;
 use syntax::print::pprust;
 use syntax::ptr::P;
 use syntax::source_map::{respan, CompilerDesugaringKind, Spanned};
+use syntax::source_map::CompilerDesugaringKind::IfTemporary;
 use syntax::std_inject;
-use syntax::symbol::{keywords, Symbol};
+use syntax::symbol::{keywords, Symbol, sym};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::Token;
 use syntax::visit::{self, Visitor};
@@ -72,7 +73,7 @@ use syntax_pos::Span;
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
 pub struct LoweringContext<'a> {
-    crate_root: Option<&'static str>,
+    crate_root: Option<Symbol>,
 
     /// Used to assign ids to HIR nodes that do not directly correspond to an AST node.
     sess: &'a Session,
@@ -96,6 +97,10 @@ pub struct LoweringContext<'a> {
     is_generator: bool,
     is_async_body: bool,
 
+    /// Used to get the current `fn`'s def span to point to when using `await`
+    /// outside of an `async fn`.
+    current_item: Option<Span>,
+
     catch_scopes: Vec<NodeId>,
     loop_scopes: Vec<NodeId>,
     is_in_loop_condition: bool,
@@ -163,8 +168,8 @@ pub trait Resolver {
     fn resolve_str_path(
         &mut self,
         span: Span,
-        crate_root: Option<&str>,
-        components: &[&str],
+        crate_root: Option<Symbol>,
+        components: &[Symbol],
         is_value: bool,
     ) -> hir::Path;
 }
@@ -227,7 +232,7 @@ pub fn lower_crate(
     dep_graph.assert_ignored();
 
     LoweringContext {
-        crate_root: std_inject::injected_crate_name(),
+        crate_root: std_inject::injected_crate_name().map(Symbol::intern),
         sess,
         cstore,
         resolver,
@@ -249,6 +254,7 @@ pub fn lower_crate(
         node_id_to_hir_id: IndexVec::new(),
         is_generator: false,
         is_async_body: false,
+        current_item: None,
         is_in_trait_impl: false,
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
@@ -849,10 +855,6 @@ impl<'a> LoweringContext<'a> {
         self.sess.diagnostic()
     }
 
-    fn str_to_ident(&self, s: &'static str) -> Ident {
-        Ident::with_empty_ctxt(Symbol::gensym(s))
-    }
-
     fn with_anonymous_lifetime_mode<R>(
         &mut self,
         anonymous_lifetime_mode: AnonymousLifetimeMode,
@@ -1148,7 +1150,7 @@ impl<'a> LoweringContext<'a> {
             ].into()),
         );
         let gen_future = self.expr_std_path(
-            unstable_span, &["future", "from_generator"], None, ThinVec::new());
+            unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new());
         hir::ExprKind::Call(P(gen_future), hir_vec![generator])
     }
 
@@ -2212,7 +2214,7 @@ impl<'a> LoweringContext<'a> {
                         bindings: hir_vec![
                             hir::TypeBinding {
                                 hir_id: this.next_id(),
-                                ident: Ident::from_str(FN_OUTPUT_NAME),
+                                ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
                                 ty: output
                                     .as_ref()
                                     .map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed()))
@@ -2537,7 +2539,7 @@ impl<'a> LoweringContext<'a> {
         let future_params = P(hir::GenericArgs {
             args: hir_vec![],
             bindings: hir_vec![hir::TypeBinding {
-                ident: Ident::from_str(FN_OUTPUT_NAME),
+                ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME),
                 ty: output_ty,
                 hir_id: self.next_id(),
                 span,
@@ -2547,7 +2549,7 @@ impl<'a> LoweringContext<'a> {
 
         // ::std::future::Future<future_params>
         let future_path =
-            self.std_path(span, &["future", "Future"], Some(future_params), false);
+            self.std_path(span, &[sym::future, sym::Future], Some(future_params), false);
 
         hir::GenericBound::Trait(
             hir::PolyTraitRef {
@@ -2726,7 +2728,7 @@ impl<'a> LoweringContext<'a> {
                         self.lower_ty(x, ImplTraitContext::disallowed())
                     }),
                     synthetic: param.attrs.iter()
-                                          .filter(|attr| attr.check_name("rustc_synthetic"))
+                                          .filter(|attr| attr.check_name(sym::rustc_synthetic))
                                           .map(|_| hir::SyntheticTyParamKind::ImplTrait)
                                           .next(),
                 };
@@ -2744,7 +2746,7 @@ impl<'a> LoweringContext<'a> {
             hir_id: self.lower_node_id(param.id),
             name,
             span: param.ident.span,
-            pure_wrt_drop: attr::contains_name(&param.attrs, "may_dangle"),
+            pure_wrt_drop: attr::contains_name(&param.attrs, sym::may_dangle),
             attrs: self.lower_attrs(&param.attrs),
             bounds,
             kind,
@@ -3115,6 +3117,7 @@ impl<'a> LoweringContext<'a> {
             ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
                 self.with_new_scopes(|this| {
+                    this.current_item = Some(ident.span);
                     let mut lower_fn = |decl: &FnDecl| {
                         // Note: we don't need to change the return type from `T` to
                         // `impl Future<Output = T>` here because lower_body
@@ -3653,6 +3656,7 @@ impl<'a> LoweringContext<'a> {
                 } else {
                     lower_method(sig)
                 };
+                self.current_item = Some(i.span);
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
@@ -3772,8 +3776,8 @@ impl<'a> LoweringContext<'a> {
         let mut vis = self.lower_visibility(&i.vis, None);
         let attrs = self.lower_attrs(&i.attrs);
         if let ItemKind::MacroDef(ref def) = i.node {
-            if !def.legacy || attr::contains_name(&i.attrs, "macro_export") ||
-                              attr::contains_name(&i.attrs, "rustc_doc_only_macro") {
+            if !def.legacy || attr::contains_name(&i.attrs, sym::macro_export) ||
+                              attr::contains_name(&i.attrs, sym::rustc_doc_only_macro) {
                 let body = self.lower_token_stream(def.stream());
                 let hir_id = self.lower_node_id(i.id);
                 self.exported_macros.push(hir::MacroDef {
@@ -4099,7 +4103,7 @@ impl<'a> LoweringContext<'a> {
                 let ohs = P(self.lower_expr(ohs));
                 hir::ExprKind::Unary(op, ohs)
             }
-            ExprKind::Lit(ref l) => hir::ExprKind::Lit((*l).clone()),
+            ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.node.clone())),
             ExprKind::Cast(ref expr, ref ty) => {
                 let expr = P(self.lower_expr(expr));
                 hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
@@ -4115,31 +4119,46 @@ impl<'a> LoweringContext<'a> {
             }
             // More complicated than you might expect because the else branch
             // might be `if let`.
-            ExprKind::If(ref cond, ref blk, ref else_opt) => {
-                let else_opt = else_opt.as_ref().map(|els| {
-                    match els.node {
+            ExprKind::If(ref cond, ref then, ref else_opt) => {
+                // `true => then`:
+                let then_pat = self.pat_bool(e.span, true);
+                let then_blk = self.lower_block(then, false);
+                let then_expr = self.expr_block(then_blk, ThinVec::new());
+                let then_arm = self.arm(hir_vec![then_pat], P(then_expr));
+
+                // `_ => else_block` where `else_block` is `{}` if there's `None`:
+                let else_pat = self.pat_wild(e.span);
+                let else_expr = match else_opt {
+                    None => self.expr_block_empty(e.span),
+                    Some(els) => match els.node {
                         ExprKind::IfLet(..) => {
                             // Wrap the `if let` expr in a block.
-                            let span = els.span;
-                            let els = P(self.lower_expr(els));
-                            let blk = P(hir::Block {
-                                stmts: hir_vec![],
-                                expr: Some(els),
-                                hir_id: self.next_id(),
-                                rules: hir::DefaultBlock,
-                                span,
-                                targeted_by_break: false,
-                            });
-                            P(self.expr_block(blk, ThinVec::new()))
+                            let els = self.lower_expr(els);
+                            let blk = self.block_all(els.span, hir_vec![], Some(P(els)));
+                            self.expr_block(P(blk), ThinVec::new())
                         }
-                        _ => P(self.lower_expr(els)),
+                        _ => self.lower_expr(els),
                     }
-                });
-
-                let then_blk = self.lower_block(blk, false);
-                let then_expr = self.expr_block(then_blk, ThinVec::new());
+                };
+                let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
+
+                // Lower condition:
+                let span_block = self
+                    .sess
+                    .source_map()
+                    .mark_span_with_reason(IfTemporary, cond.span, None);
+                let cond = self.lower_expr(cond);
+                // Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
+                // semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
+                let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
 
-                hir::ExprKind::If(P(self.lower_expr(cond)), P(then_expr), else_opt)
+                hir::ExprKind::Match(
+                    P(cond),
+                    vec![then_arm, else_arm].into(),
+                    hir::MatchSource::IfDesugar {
+                        contains_else_clause: else_opt.is_some()
+                    },
+                )
             }
             ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
                 hir::ExprKind::While(
@@ -4178,7 +4197,7 @@ impl<'a> LoweringContext<'a> {
                         |x: P<hir::Expr>| x.into_inner(),
                     );
                     block.expr = Some(this.wrap_in_try_constructor(
-                        "from_ok", tail, unstable_span));
+                        sym::from_ok, tail, unstable_span));
                     hir::ExprKind::Block(P(block), None)
                 })
             }
@@ -4254,6 +4273,7 @@ impl<'a> LoweringContext<'a> {
                     let fn_decl = self.lower_fn_decl(decl, None, false, None);
 
                     self.with_new_scopes(|this| {
+                        this.current_item = Some(fn_decl_span);
                         let mut is_generator = false;
                         let body_id = this.lower_body(Some(decl), |this| {
                             let e = this.lower_expr(body);
@@ -4320,7 +4340,7 @@ impl<'a> LoweringContext<'a> {
                 self.expr_call_std_assoc_fn(
                     id,
                     e.span,
-                    &["ops", "RangeInclusive"],
+                    &[sym::ops, sym::RangeInclusive],
                     "new",
                     hir_vec![e1, e2],
                 )
@@ -4329,11 +4349,11 @@ impl<'a> LoweringContext<'a> {
                 use syntax::ast::RangeLimits::*;
 
                 let path = match (e1, e2, lims) {
-                    (&None, &None, HalfOpen) => "RangeFull",
-                    (&Some(..), &None, HalfOpen) => "RangeFrom",
-                    (&None, &Some(..), HalfOpen) => "RangeTo",
-                    (&Some(..), &Some(..), HalfOpen) => "Range",
-                    (&None, &Some(..), Closed) => "RangeToInclusive",
+                    (&None, &None, HalfOpen) => sym::RangeFull,
+                    (&Some(..), &None, HalfOpen) => sym::RangeFrom,
+                    (&None, &Some(..), HalfOpen) => sym::RangeTo,
+                    (&Some(..), &Some(..), HalfOpen) => sym::Range,
+                    (&None, &Some(..), Closed) => sym::RangeToInclusive,
                     (&Some(..), &Some(..), Closed) => unreachable!(),
                     (_, &None, Closed) => self.diagnostic()
                         .span_fatal(e.span, "inclusive range with no end")
@@ -4351,7 +4371,7 @@ impl<'a> LoweringContext<'a> {
                     .collect::<P<[hir::Field]>>();
 
                 let is_unit = fields.is_empty();
-                let struct_path = ["ops", path];
+                let struct_path = [sym::ops, path];
                 let struct_path = self.std_path(e.span, &struct_path, None, is_unit);
                 let struct_path = hir::QPath::Resolved(None, P(struct_path));
 
@@ -4486,16 +4506,16 @@ impl<'a> LoweringContext<'a> {
                     arms.push(self.arm(pats, body_expr));
                 }
 
-                // _ => [<else_opt>|()]
+                // _ => [<else_opt>|{}]
                 {
                     let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
                     let wildcard_pattern = self.pat_wild(e.span);
                     let body = if let Some(else_expr) = wildcard_arm {
-                        P(self.lower_expr(else_expr))
+                        self.lower_expr(else_expr)
                     } else {
-                        P(self.expr_tuple(e.span, hir_vec![]))
+                        self.expr_block_empty(e.span)
                     };
-                    arms.push(self.arm(hir_vec![wildcard_pattern], body));
+                    arms.push(self.arm(hir_vec![wildcard_pattern], P(body)));
                 }
 
                 let contains_else_clause = else_opt.is_some();
@@ -4597,18 +4617,18 @@ impl<'a> LoweringContext<'a> {
                 );
                 head.span = desugared_span;
 
-                let iter = self.str_to_ident("iter");
+                let iter = Ident::with_empty_ctxt(sym::iter);
 
-                let next_ident = self.str_to_ident("__next");
+                let next_ident = Ident::with_empty_ctxt(sym::__next);
                 let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
                     desugared_span,
                     next_ident,
                     hir::BindingAnnotation::Mutable,
                 );
 
-                // `::std::option::Option::Some(val) => next = val`
+                // `::std::option::Option::Some(val) => __next = val`
                 let pat_arm = {
-                    let val_ident = self.str_to_ident("val");
+                    let val_ident = Ident::with_empty_ctxt(sym::val);
                     let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
                     let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
                     let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
@@ -4640,7 +4660,7 @@ impl<'a> LoweringContext<'a> {
                 let match_expr = {
                     let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
                     let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
-                    let next_path = &["iter", "Iterator", "next"];
+                    let next_path = &[sym::iter, sym::Iterator, sym::next];
                     let next_expr = P(self.expr_call_std_path(
                         head_sp,
                         next_path,
@@ -4658,11 +4678,7 @@ impl<'a> LoweringContext<'a> {
                         ThinVec::new(),
                     ))
                 };
-                let match_stmt = hir::Stmt {
-                    hir_id: self.next_id(),
-                    node: hir::StmtKind::Expr(match_expr),
-                    span: head_sp,
-                };
+                let match_stmt = self.stmt(head_sp, hir::StmtKind::Expr(match_expr));
 
                 let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
 
@@ -4685,11 +4701,7 @@ impl<'a> LoweringContext<'a> {
 
                 let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
                 let body_expr = P(self.expr_block(body_block, ThinVec::new()));
-                let body_stmt = hir::Stmt {
-                    hir_id: self.next_id(),
-                    node: hir::StmtKind::Expr(body_expr),
-                    span: body.span,
-                };
+                let body_stmt = self.stmt(body.span, hir::StmtKind::Expr(body_expr));
 
                 let loop_block = P(self.block_all(
                     e.span,
@@ -4715,7 +4727,8 @@ impl<'a> LoweringContext<'a> {
 
                 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
                 let into_iter_expr = {
-                    let into_iter_path = &["iter", "IntoIterator", "into_iter"];
+                    let into_iter_path =
+                        &[sym::iter, sym::IntoIterator, sym::into_iter];
                     P(self.expr_call_std_path(
                         head_sp,
                         into_iter_path,
@@ -4754,17 +4767,13 @@ impl<'a> LoweringContext<'a> {
                 let unstable_span = self.sess.source_map().mark_span_with_reason(
                     CompilerDesugaringKind::QuestionMark,
                     e.span,
-                    Some(vec![
-                        Symbol::intern("try_trait")
-                    ].into()),
+                    Some(vec![sym::try_trait].into()),
                 );
                 let try_span = self.sess.source_map().end_point(e.span);
                 let try_span = self.sess.source_map().mark_span_with_reason(
                     CompilerDesugaringKind::QuestionMark,
                     try_span,
-                    Some(vec![
-                        Symbol::intern("try_trait")
-                    ].into()),
+                    Some(vec![sym::try_trait].into()),
                 );
 
                 // `Try::into_result(<expr>)`
@@ -4772,7 +4781,7 @@ impl<'a> LoweringContext<'a> {
                     // expand <expr>
                     let sub_expr = self.lower_expr(sub_expr);
 
-                    let path = &["ops", "Try", "into_result"];
+                    let path = &[sym::ops, sym::Try, sym::into_result];
                     P(self.expr_call_std_path(
                         unstable_span,
                         path,
@@ -4784,8 +4793,9 @@ impl<'a> LoweringContext<'a> {
                 let attr = {
                     // `allow(unreachable_code)`
                     let allow = {
-                        let allow_ident = Ident::from_str("allow").with_span_pos(e.span);
-                        let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span);
+                        let allow_ident = Ident::with_empty_ctxt(sym::allow).with_span_pos(e.span);
+                        let uc_ident = Ident::with_empty_ctxt(sym::unreachable_code)
+                            .with_span_pos(e.span);
                         let uc_nested = attr::mk_nested_word_item(uc_ident);
                         attr::mk_list_item(e.span, allow_ident, vec![uc_nested])
                     };
@@ -4795,7 +4805,7 @@ impl<'a> LoweringContext<'a> {
 
                 // `Ok(val) => #[allow(unreachable_code)] val,`
                 let ok_arm = {
-                    let val_ident = self.str_to_ident("val");
+                    let val_ident = Ident::with_empty_ctxt(sym::val);
                     let (val_pat, val_pat_nid) = self.pat_ident(e.span, val_ident);
                     let val_expr = P(self.expr_ident_with_attrs(
                         e.span,
@@ -4811,15 +4821,15 @@ impl<'a> LoweringContext<'a> {
                 // `Err(err) => #[allow(unreachable_code)]
                 //              return Try::from_error(From::from(err)),`
                 let err_arm = {
-                    let err_ident = self.str_to_ident("err");
+                    let err_ident = Ident::with_empty_ctxt(sym::err);
                     let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
                     let from_expr = {
-                        let from_path = &["convert", "From", "from"];
+                        let from_path = &[sym::convert, sym::From, sym::from];
                         let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
                         self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
                     };
                     let from_err_expr =
-                        self.wrap_in_try_constructor("from_error", from_expr, unstable_span);
+                        self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
                     let thin_attrs = ThinVec::from(attrs);
                     let catch_scope = self.catch_scopes.last().map(|x| *x);
                     let ret_expr = if let Some(catch_node) = catch_scope {
@@ -4869,12 +4879,7 @@ impl<'a> LoweringContext<'a> {
                     .into_iter()
                     .map(|item_id| {
                         let item_id = hir::ItemId { id: self.lower_node_id(item_id) };
-
-                        hir::Stmt {
-                            hir_id: self.next_id(),
-                            node: hir::StmtKind::Item(item_id),
-                            span: s.span,
-                        }
+                        self.stmt(s.span, hir::StmtKind::Item(item_id))
                     })
                     .collect();
                 ids.push({
@@ -5054,7 +5059,7 @@ impl<'a> LoweringContext<'a> {
     fn expr_call_std_path(
         &mut self,
         span: Span,
-        path_components: &[&str],
+        path_components: &[Symbol],
         args: hir::HirVec<hir::Expr>,
     ) -> hir::Expr {
         let path = P(self.expr_std_path(span, path_components, None, ThinVec::new()));
@@ -5074,7 +5079,7 @@ impl<'a> LoweringContext<'a> {
         &mut self,
         ty_path_id: hir::HirId,
         span: Span,
-        ty_path_components: &[&str],
+        ty_path_components: &[Symbol],
         assoc_fn_name: &str,
         args: hir::HirVec<hir::Expr>,
     ) -> hir::ExprKind {
@@ -5116,7 +5121,7 @@ impl<'a> LoweringContext<'a> {
     fn expr_std_path(
         &mut self,
         span: Span,
-        components: &[&str],
+        components: &[Symbol],
         params: Option<P<hir::GenericArgs>>,
         attrs: ThinVec<Attribute>,
     ) -> hir::Expr {
@@ -5174,28 +5179,32 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    fn stmt(&mut self, span: Span, node: hir::StmtKind) -> hir::Stmt {
+        hir::Stmt { span, node, hir_id: self.next_id() }
+    }
+
     fn stmt_let_pat(
         &mut self,
-        sp: Span,
-        ex: Option<P<hir::Expr>>,
+        span: Span,
+        init: Option<P<hir::Expr>>,
         pat: P<hir::Pat>,
         source: hir::LocalSource,
     ) -> hir::Stmt {
         let local = hir::Local {
             pat,
             ty: None,
-            init: ex,
+            init,
             hir_id: self.next_id(),
-            span: sp,
-            attrs: ThinVec::new(),
+            span,
             source,
+            attrs: ThinVec::new()
         };
+        self.stmt(span, hir::StmtKind::Local(P(local)))
+    }
 
-        hir::Stmt {
-            hir_id: self.next_id(),
-            node: hir::StmtKind::Local(P(local)),
-            span: sp
-        }
+    fn expr_block_empty(&mut self, span: Span) -> hir::Expr {
+        let blk = self.block_all(span, hir_vec![], None);
+        self.expr_block(P(blk), ThinVec::new())
     }
 
     fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
@@ -5235,26 +5244,33 @@ impl<'a> LoweringContext<'a> {
         )
     }
 
+    /// Constructs a `true` or `false` literal pattern.
+    fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
+        let lit = Spanned { span, node: LitKind::Bool(val) };
+        let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new());
+        self.pat(span, hir::PatKind::Lit(P(expr)))
+    }
+
     fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
+        self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], hir_vec![pat])
     }
 
     fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        self.pat_std_enum(span, &["result", "Result", "Err"], hir_vec![pat])
+        self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], hir_vec![pat])
     }
 
     fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
-        self.pat_std_enum(span, &["option", "Option", "Some"], hir_vec![pat])
+        self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], hir_vec![pat])
     }
 
     fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
-        self.pat_std_enum(span, &["option", "Option", "None"], hir_vec![])
+        self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], hir_vec![])
     }
 
     fn pat_std_enum(
         &mut self,
         span: Span,
-        components: &[&str],
+        components: &[Symbol],
         subpats: hir::HirVec<P<hir::Pat>>,
     ) -> P<hir::Pat> {
         let path = self.std_path(span, components, None, true);
@@ -5307,7 +5323,7 @@ impl<'a> LoweringContext<'a> {
     fn std_path(
         &mut self,
         span: Span,
-        components: &[&str],
+        components: &[Symbol],
         params: Option<P<hir::GenericArgs>>,
         is_value: bool,
     ) -> hir::Path {
@@ -5506,11 +5522,11 @@ impl<'a> LoweringContext<'a> {
 
     fn wrap_in_try_constructor(
         &mut self,
-        method: &'static str,
+        method: Symbol,
         e: hir::Expr,
         unstable_span: Span,
     ) -> P<hir::Expr> {
-        let path = &["ops", "Try", method];
+        let path = &[sym::ops, sym::Try, method];
         let from_err = P(self.expr_std_path(unstable_span, path, None,
                                             ThinVec::new()));
         P(self.expr_call(e.span, from_err, hir_vec![e]))
@@ -5529,20 +5545,25 @@ impl<'a> LoweringContext<'a> {
         //         match ::std::future::poll_with_tls_context(unsafe {
         //             ::std::pin::Pin::new_unchecked(&mut pinned)
         //         }) {
-        //             ::std::task::Poll::Ready(x) => break x,
+        //             ::std::task::Poll::Ready(result) => break result,
         //             ::std::task::Poll::Pending => {},
         //         }
         //         yield ();
         //     }
         // }
         if !self.is_async_body {
-            span_err!(
+            let mut err = struct_span_err!(
                 self.sess,
                 await_span,
                 E0728,
                 "`await` is only allowed inside `async` functions and blocks"
             );
-            self.sess.abort_if_errors();
+            err.span_label(await_span, "only allowed inside `async` functions and blocks");
+            if let Some(item_sp) = self.current_item {
+                err.span_label(item_sp, "this is not `async`");
+            }
+            err.emit();
+            return hir::ExprKind::Err;
         }
         let span = self.sess.source_map().mark_span_with_reason(
             CompilerDesugaringKind::Await,
@@ -5552,12 +5573,12 @@ impl<'a> LoweringContext<'a> {
         let gen_future_span = self.sess.source_map().mark_span_with_reason(
             CompilerDesugaringKind::Await,
             await_span,
-            Some(vec![Symbol::intern("gen_future")].into()),
+            Some(vec![sym::gen_future].into()),
         );
 
         // let mut pinned = <expr>;
         let expr = P(self.lower_expr(expr));
-        let pinned_ident = self.str_to_ident("pinned");
+        let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
         let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
             span,
             pinned_ident,
@@ -5580,7 +5601,7 @@ impl<'a> LoweringContext<'a> {
             let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
                 pin_ty_id,
                 span,
-                &["pin", "Pin"],
+                &[sym::pin, sym::Pin],
                 "new_unchecked",
                 hir_vec![ref_mut_pinned],
             );
@@ -5588,21 +5609,21 @@ impl<'a> LoweringContext<'a> {
             let unsafe_expr = self.expr_unsafe(new_unchecked);
             P(self.expr_call_std_path(
                 gen_future_span,
-                &["future", "poll_with_tls_context"],
+                &[sym::future, sym::poll_with_tls_context],
                 hir_vec![unsafe_expr],
             ))
         };
 
-        // `::std::task::Poll::Ready(x) => break x`
+        // `::std::task::Poll::Ready(result) => break result`
         let loop_node_id = self.sess.next_node_id();
         let loop_hir_id = self.lower_node_id(loop_node_id);
         let ready_arm = {
-            let x_ident = self.str_to_ident("x");
+            let x_ident = Ident::with_empty_ctxt(sym::result);
             let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
             let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
             let ready_pat = self.pat_std_enum(
                 span,
-                &["task", "Poll", "Ready"],
+                &[sym::task, sym::Poll, sym::Ready],
                 hir_vec![x_pat],
             );
             let break_x = self.with_loop_scope(loop_node_id, |this| {
@@ -5619,18 +5640,10 @@ impl<'a> LoweringContext<'a> {
         let pending_arm = {
             let pending_pat = self.pat_std_enum(
                 span,
-                &["task", "Poll", "Pending"],
+                &[sym::task, sym::Poll, sym::Pending],
                 hir_vec![],
             );
-            let empty_block = P(hir::Block {
-                stmts: hir_vec![],
-                expr: None,
-                hir_id: self.next_id(),
-                rules: hir::DefaultBlock,
-                span,
-                targeted_by_break: false,
-            });
-            let empty_block = P(self.expr_block(empty_block, ThinVec::new()));
+            let empty_block = P(self.expr_block_empty(span));
             self.arm(hir_vec![pending_pat], empty_block)
         };
 
@@ -5641,11 +5654,7 @@ impl<'a> LoweringContext<'a> {
                 hir_vec![ready_arm, pending_arm],
                 hir::MatchSource::AwaitDesugar,
             ));
-            hir::Stmt {
-                hir_id: self.next_id(),
-                node: hir::StmtKind::Expr(match_expr),
-                span,
-            }
+            self.stmt(span, hir::StmtKind::Expr(match_expr))
         };
 
         let yield_stmt = {
@@ -5655,11 +5664,7 @@ impl<'a> LoweringContext<'a> {
                 hir::ExprKind::Yield(P(unit)),
                 ThinVec::new(),
             ));
-            hir::Stmt {
-                hir_id: self.next_id(),
-                node: hir::StmtKind::Expr(yield_expr),
-                span,
-            }
+            self.stmt(span, hir::StmtKind::Expr(yield_expr))
         };
 
         let loop_block = P(self.block_all(
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index a1cf338bf12..eeba628b3bf 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -226,7 +226,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
 
     fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) {
         debug!("hir_map: {:?} => {:?}", id, entry);
-        let local_map = &mut self.map[id.owner.as_array_index()];
+        let local_map = &mut self.map[id.owner.index()];
         let i = id.local_id.as_u32() as usize;
         if local_map.is_none() {
             *local_map = Some(IndexVec::with_capacity(i + 1));
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index dc6cddc89f9..1cc9a2c0e8a 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -17,7 +17,7 @@ use std::fmt::Write;
 use std::hash::Hash;
 use syntax::ast;
 use syntax::ext::hygiene::Mark;
-use syntax::symbol::{Symbol, InternedString};
+use syntax::symbol::{Symbol, sym, InternedString};
 use syntax_pos::{Span, DUMMY_SP};
 use crate::util::nodemap::NodeMap;
 
@@ -38,7 +38,7 @@ impl DefPathTable {
                 def_path_hash: DefPathHash)
                 -> DefIndex {
         let index = {
-            let index = DefIndex::from_array_index(self.index_to_key.len());
+            let index = DefIndex::from(self.index_to_key.len());
             debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
             self.index_to_key.push(key);
             index
@@ -49,17 +49,17 @@ impl DefPathTable {
     }
 
     pub fn next_id(&self) -> DefIndex {
-        DefIndex::from_array_index(self.index_to_key.len())
+        DefIndex::from(self.index_to_key.len())
     }
 
     #[inline(always)]
     pub fn def_key(&self, index: DefIndex) -> DefKey {
-        self.index_to_key[index.as_array_index()].clone()
+        self.index_to_key[index.index()].clone()
     }
 
     #[inline(always)]
     pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
-        let ret = self.def_path_hashes[index.as_array_index()];
+        let ret = self.def_path_hashes[index.index()];
         debug!("def_path_hash({:?}) = {:?}", index, ret);
         return ret
     }
@@ -74,7 +74,7 @@ impl DefPathTable {
                 .map(|(index, &hash)| {
                     let def_id = DefId {
                         krate: cnum,
-                        index: DefIndex::from_array_index(index),
+                        index: DefIndex::from(index),
                     };
                     (hash, def_id)
                 })
@@ -387,7 +387,7 @@ impl Definitions {
     #[inline]
     pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
         if def_id.krate == LOCAL_CRATE {
-            let node_id = self.def_index_to_node[def_id.index.as_array_index()];
+            let node_id = self.def_index_to_node[def_id.index.index()];
             if node_id != ast::DUMMY_NODE_ID {
                 return Some(node_id);
             }
@@ -417,7 +417,7 @@ impl Definitions {
 
     #[inline]
     pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId {
-        let node_id = self.def_index_to_node[def_index.as_array_index()];
+        let node_id = self.def_index_to_node[def_index.index()];
         self.node_to_hir_id[node_id]
     }
 
@@ -508,7 +508,7 @@ impl Definitions {
 
         // Create the definition.
         let index = self.table.allocate(key, def_path_hash);
-        assert_eq!(index.as_array_index(), self.def_index_to_node.len());
+        assert_eq!(index.index(), self.def_index_to_node.len());
         self.def_index_to_node.push(node_id);
 
         // Some things for which we allocate DefIndices don't correspond to
@@ -584,16 +584,16 @@ impl DefPathData {
                 return name
             }
             // note that this does not show up in user printouts
-            CrateRoot => "{{crate}}",
-            Impl => "{{impl}}",
-            Misc => "{{misc}}",
-            ClosureExpr => "{{closure}}",
-            Ctor => "{{constructor}}",
-            AnonConst => "{{constant}}",
-            ImplTrait => "{{opaque}}",
+            CrateRoot => sym::double_braced_crate,
+            Impl => sym::double_braced_impl,
+            Misc => sym::double_braced_misc,
+            ClosureExpr => sym::double_braced_closure,
+            Ctor => sym::double_braced_constructor,
+            AnonConst => sym::double_braced_constant,
+            ImplTrait => sym::double_braced_opaque,
         };
 
-        Symbol::intern(s).as_interned_str()
+        s.as_interned_str()
     }
 
     pub fn to_string(&self) -> String {
@@ -653,7 +653,7 @@ macro_rules! define_global_metadata_kind {
                                           .position(|k| *k == def_key)
                                           .unwrap();
 
-                DefIndex::from_array_index(index)
+                DefIndex::from(index)
             }
 
             fn name(&self) -> Symbol {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 1a48dff213b..4b94f772554 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -189,7 +189,7 @@ pub struct Map<'hir> {
 impl<'hir> Map<'hir> {
     #[inline]
     fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> {
-        let local_map = self.map.get(id.owner.as_array_index())?;
+        let local_map = self.map.get(id.owner.index())?;
         local_map.as_ref()?.get(id.local_id)?.as_ref()
     }
 
@@ -1023,7 +1023,7 @@ impl<'hir> Map<'hir> {
             local_map.iter_enumerated().filter_map(move |(i, entry)| entry.map(move |_| {
                 // Reconstruct the HirId based on the 3 indices we used to find it
                 HirId {
-                    owner: DefIndex::from_array_index(array_index),
+                    owner: DefIndex::from(array_index),
                     local_id: i,
                 }
             }))
@@ -1146,7 +1146,7 @@ impl<'a> NodesMatchingSuffix<'a> {
                 None => return false,
                 Some((node_id, name)) => (node_id, name),
             };
-            if mod_name != &**part {
+            if mod_name.as_str() != *part {
                 return false;
             }
             cursor = self.map.get_parent_item(mod_id);
@@ -1183,7 +1183,7 @@ impl<'a> NodesMatchingSuffix<'a> {
     // We are looking at some node `n` with a given name and parent
     // id; do their names match what I am seeking?
     fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool {
-        name == &**self.item_name && self.suffix_matches(parent_of_n)
+        name.as_str() == *self.item_name && self.suffix_matches(parent_of_n)
     }
 
     fn matches_suffix(&self, hir: HirId) -> bool {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 01de7917e6e..57304c5ed37 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -20,7 +20,7 @@ use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
 use syntax::source_map::Spanned;
 use rustc_target::spec::abi::Abi;
 use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
-use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy};
+use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy};
 use syntax::attr::{InlineAttr, OptimizeAttr};
 use syntax::ext::hygiene::SyntaxContext;
 use syntax::ptr::P;
@@ -126,12 +126,12 @@ mod item_local_id_inner {
     use rustc_macros::HashStable;
     newtype_index! {
         /// An `ItemLocalId` uniquely identifies something within a given "item-like",
-        /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
+        /// that is, within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
         /// guarantee that the numerical value of a given `ItemLocalId` corresponds to
         /// the node's position within the owning item in any way, but there is a
         /// guarantee that the `LocalItemId`s within an owner occupy a dense range of
         /// integers starting at zero, so a mapping that maps all or most nodes within
-        /// an "item-like" to something else can be implement by a `Vec` instead of a
+        /// an "item-like" to something else can be implemented by a `Vec` instead of a
         /// tree or hash map.
         pub struct ItemLocalId {
             derive [HashStable]
@@ -609,9 +609,9 @@ impl Generics {
         own_counts
     }
 
-    pub fn get_named(&self, name: &InternedString) -> Option<&GenericParam> {
+    pub fn get_named(&self, name: InternedString) -> Option<&GenericParam> {
         for param in &self.params {
-            if *name == param.name.ident().as_interned_str() {
+            if name == param.name.ident().as_interned_str() {
                 return Some(param);
             }
         }
@@ -1331,6 +1331,9 @@ impl BodyOwnerKind {
     }
 }
 
+/// A literal.
+pub type Lit = Spanned<LitKind>;
+
 /// A constant (expression) that's not an item or associated item,
 /// but needs its own `DefId` for type-checking, const-eval, etc.
 /// These are usually found nested inside types (e.g., array lengths)
@@ -1353,7 +1356,7 @@ pub struct Expr {
 
 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 72);
+static_assert_size!(Expr, 72);
 
 impl Expr {
     pub fn precedence(&self) -> ExprPrecedence {
@@ -1368,7 +1371,6 @@ impl Expr {
             ExprKind::Lit(_) => ExprPrecedence::Lit,
             ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
             ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
-            ExprKind::If(..) => ExprPrecedence::If,
             ExprKind::While(..) => ExprPrecedence::While,
             ExprKind::Loop(..) => ExprPrecedence::Loop,
             ExprKind::Match(..) => ExprPrecedence::Match,
@@ -1421,7 +1423,6 @@ impl Expr {
             ExprKind::MethodCall(..) |
             ExprKind::Struct(..) |
             ExprKind::Tup(..) |
-            ExprKind::If(..) |
             ExprKind::Match(..) |
             ExprKind::Closure(..) |
             ExprKind::Block(..) |
@@ -1498,10 +1499,6 @@ pub enum ExprKind {
     /// This construct only exists to tweak the drop order in HIR lowering.
     /// An example of that is the desugaring of `for` loops.
     DropTemps(P<Expr>),
-    /// An `if` block, with an optional else block.
-    ///
-    /// I.e., `if <expr> { <expr> } else { <expr> }`.
-    If(P<Expr>, P<Expr>, Option<P<Expr>>),
     /// A while loop, with an optional label
     ///
     /// I.e., `'label: while expr { <block> }`.
@@ -1615,6 +1612,10 @@ pub enum LocalSource {
 pub enum MatchSource {
     /// A `match _ { .. }`.
     Normal,
+    /// An `if _ { .. }` (optionally with `else { .. }`).
+    IfDesugar {
+        contains_else_clause: bool,
+    },
     /// An `if let _ = _ { .. }` (optionally with `else { .. }`).
     IfLetDesugar {
         contains_else_clause: bool,
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 54816316f0b..8a9028e5443 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -5,7 +5,7 @@ use syntax::parse::ParseSess;
 use syntax::parse::lexer::comments;
 use syntax::print::pp::{self, Breaks};
 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
-use syntax::print::pprust::PrintState;
+use syntax::print::pprust::{self, PrintState};
 use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax::util::parser::{self, AssocOp, Fixity};
@@ -18,7 +18,6 @@ use crate::hir::{GenericParam, GenericParamKind, GenericArg};
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::io::{self, Write, Read};
-use std::iter::Peekable;
 use std::vec;
 
 pub enum AnnNode<'a> {
@@ -76,7 +75,6 @@ pub struct State<'a> {
     pub s: pp::Printer<'a>,
     cm: Option<&'a SourceMap>,
     comments: Option<Vec<comments::Comment>>,
-    literals: Peekable<vec::IntoIter<comments::Literal>>,
     cur_cmnt: usize,
     boxes: Vec<pp::Breaks>,
     ann: &'a (dyn PpAnn + 'a),
@@ -98,14 +96,6 @@ impl<'a> PrintState<'a> for State<'a> {
     fn cur_cmnt(&mut self) -> &mut usize {
         &mut self.cur_cmnt
     }
-
-    fn cur_lit(&mut self) -> Option<&comments::Literal> {
-        self.literals.peek()
-    }
-
-    fn bump_lit(&mut self) -> Option<comments::Literal> {
-        self.literals.next()
-    }
 }
 
 #[allow(non_upper_case_globals)]
@@ -116,18 +106,16 @@ pub const default_columns: usize = 78;
 
 
 /// Requires you to pass an input filename and reader so that
-/// it can scan the input text for comments and literals to
-/// copy forward.
+/// it can scan the input text for comments to copy forward.
 pub fn print_crate<'a>(cm: &'a SourceMap,
                        sess: &ParseSess,
                        krate: &hir::Crate,
                        filename: FileName,
                        input: &mut dyn Read,
                        out: Box<dyn Write + 'a>,
-                       ann: &'a dyn PpAnn,
-                       is_expanded: bool)
+                       ann: &'a dyn PpAnn)
                        -> io::Result<()> {
-    let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded);
+    let mut s = State::new_from_input(cm, sess, filename, input, out, ann);
 
     // When printing the AST, we sometimes need to inject `#[no_std]` here.
     // Since you can't compile the HIR, it's not necessary.
@@ -143,36 +131,21 @@ impl<'a> State<'a> {
                           filename: FileName,
                           input: &mut dyn Read,
                           out: Box<dyn Write + 'a>,
-                          ann: &'a dyn PpAnn,
-                          is_expanded: bool)
+                          ann: &'a dyn PpAnn)
                           -> State<'a> {
-        let (cmnts, lits) = comments::gather_comments_and_literals(sess, filename, input);
-
-        State::new(cm,
-                   out,
-                   ann,
-                   Some(cmnts),
-                   // If the code is post expansion, don't use the table of
-                   // literals, since it doesn't correspond with the literals
-                   // in the AST anymore.
-                   if is_expanded {
-                       None
-                   } else {
-                       Some(lits)
-                   })
+        let comments = comments::gather_comments(sess, filename, input);
+        State::new(cm, out, ann, Some(comments))
     }
 
     pub fn new(cm: &'a SourceMap,
                out: Box<dyn Write + 'a>,
                ann: &'a dyn PpAnn,
-               comments: Option<Vec<comments::Comment>>,
-               literals: Option<Vec<comments::Literal>>)
+               comments: Option<Vec<comments::Comment>>)
                -> State<'a> {
         State {
             s: pp::mk_printer(out, default_columns),
             cm: Some(cm),
             comments,
-            literals: literals.unwrap_or_default().into_iter().peekable(),
             cur_cmnt: 0,
             boxes: Vec::new(),
             ann,
@@ -189,7 +162,6 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
             s: pp::mk_printer(Box::new(&mut wr), default_columns),
             cm: None,
             comments: None,
-            literals: vec![].into_iter().peekable(),
             cur_cmnt: 0,
             boxes: Vec::new(),
             ann,
@@ -646,7 +618,6 @@ impl<'a> State<'a> {
 
                 self.print_where_clause(&exist.generics.where_clause)?;
                 self.s.space()?;
-                self.word_space(":")?;
                 let mut real_bounds = Vec::with_capacity(exist.bounds.len());
                 for b in exist.bounds.iter() {
                     if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
@@ -1093,65 +1064,6 @@ impl<'a> State<'a> {
         self.ann.post(self, AnnNode::Block(blk))
     }
 
-    fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> {
-        match els {
-            Some(_else) => {
-                match _else.node {
-                    // "another else-if"
-                    hir::ExprKind::If(ref i, ref then, ref e) => {
-                        self.cbox(indent_unit - 1)?;
-                        self.ibox(0)?;
-                        self.s.word(" else if ")?;
-                        self.print_expr_as_cond(&i)?;
-                        self.s.space()?;
-                        self.print_expr(&then)?;
-                        self.print_else(e.as_ref().map(|e| &**e))
-                    }
-                    // "final else"
-                    hir::ExprKind::Block(ref b, _) => {
-                        self.cbox(indent_unit - 1)?;
-                        self.ibox(0)?;
-                        self.s.word(" else ")?;
-                        self.print_block(&b)
-                    }
-                    // BLEAH, constraints would be great here
-                    _ => {
-                        panic!("print_if saw if with weird alternative");
-                    }
-                }
-            }
-            _ => Ok(()),
-        }
-    }
-
-    pub fn print_if(&mut self,
-                    test: &hir::Expr,
-                    blk: &hir::Expr,
-                    elseopt: Option<&hir::Expr>)
-                    -> io::Result<()> {
-        self.head("if")?;
-        self.print_expr_as_cond(test)?;
-        self.s.space()?;
-        self.print_expr(blk)?;
-        self.print_else(elseopt)
-    }
-
-    pub fn print_if_let(&mut self,
-                        pat: &hir::Pat,
-                        expr: &hir::Expr,
-                        blk: &hir::Block,
-                        elseopt: Option<&hir::Expr>)
-                        -> io::Result<()> {
-        self.head("if let")?;
-        self.print_pat(pat)?;
-        self.s.space()?;
-        self.word_space("=")?;
-        self.print_expr_as_cond(expr)?;
-        self.s.space()?;
-        self.print_block(blk)?;
-        self.print_else(elseopt)
-    }
-
     pub fn print_anon_const(&mut self, constant: &hir::AnonConst) -> io::Result<()> {
         self.ann.nested(self, Nested::Body(constant.body))
     }
@@ -1335,6 +1247,12 @@ impl<'a> State<'a> {
         self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
     }
 
+    fn print_literal(&mut self, lit: &hir::Lit) -> io::Result<()> {
+        self.maybe_print_comment(lit.span.lo())?;
+        let (token, suffix) = lit.node.to_lit_token();
+        self.writer().word(pprust::literal_to_string(token, suffix))
+    }
+
     pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
         self.maybe_print_comment(expr.span.lo())?;
         self.print_outer_attributes(&expr.attrs)?;
@@ -1406,9 +1324,6 @@ impl<'a> State<'a> {
                 // Print `}`:
                 self.bclose_maybe_open(expr.span, indent_unit, true)?;
             }
-            hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
-            }
             hir::ExprKind::While(ref test, ref blk, opt_label) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident)?;
@@ -2414,7 +2329,6 @@ impl<'a> State<'a> {
 /// isn't parsed as (if true {...} else {...} | x) | 5
 fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
     match e.node {
-        hir::ExprKind::If(..) |
         hir::ExprKind::Match(..) |
         hir::ExprKind::Block(..) |
         hir::ExprKind::While(..) |
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
index 6da2cb9ab57..8be610e8bf7 100644
--- a/src/librustc/ich/hcx.rs
+++ b/src/librustc/ich/hcx.rs
@@ -28,7 +28,7 @@ use smallvec::SmallVec;
 
 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
     debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0);
-    ich::IGNORED_ATTRIBUTES.iter().map(|&s| Symbol::intern(s)).collect()
+    ich::IGNORED_ATTRIBUTES.iter().map(|&s| s).collect()
 }
 
 /// This is the context state available during incr. comp. hashing. It contains
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 90dd5099cbf..4e5718cc5ef 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -162,7 +162,13 @@ impl_stable_hash_for!(enum ::syntax::ast::LitIntType {
     Unsuffixed
 });
 
-impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
+impl_stable_hash_for!(struct ::syntax::ast::Lit {
+    node,
+    token,
+    suffix,
+    span
+});
+
 impl_stable_hash_for!(enum ::syntax::ast::LitKind {
     Str(value, style),
     Err(value),
@@ -175,6 +181,8 @@ impl_stable_hash_for!(enum ::syntax::ast::LitKind {
     Bool(value)
 });
 
+impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
+
 impl_stable_hash_for!(enum ::syntax::ast::IntTy { Isize, I8, I16, I32, I64, I128 });
 impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, U8, U16, U32, U64, U128 });
 impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 });
@@ -280,6 +288,19 @@ for tokenstream::TokenStream {
     }
 }
 
+impl_stable_hash_for!(enum token::Lit {
+    Bool(val),
+    Byte(val),
+    Char(val),
+    Err(val),
+    Integer(val),
+    Float(val),
+    Str_(val),
+    ByteStr(val),
+    StrRaw(val, n),
+    ByteStrRaw(val, n)
+});
+
 fn hash_token<'a, 'gcx, W: StableHasherResult>(
     token: &token::Token,
     hcx: &mut StableHashingContext<'a>,
@@ -327,22 +348,8 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
         token::Token::CloseDelim(delim_token) => {
             std_hash::Hash::hash(&delim_token, hasher);
         }
-        token::Token::Literal(ref lit, ref opt_name) => {
-            mem::discriminant(lit).hash_stable(hcx, hasher);
-            match *lit {
-                token::Lit::Byte(val) |
-                token::Lit::Char(val) |
-                token::Lit::Err(val) |
-                token::Lit::Integer(val) |
-                token::Lit::Float(val) |
-                token::Lit::Str_(val) |
-                token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher),
-                token::Lit::StrRaw(val, n) |
-                token::Lit::ByteStrRaw(val, n) => {
-                    val.hash_stable(hcx, hasher);
-                    n.hash_stable(hcx, hasher);
-                }
-            };
+        token::Token::Literal(lit, opt_name) => {
+            lit.hash_stable(hcx, hasher);
             opt_name.hash_stable(hcx, hasher);
         }
 
@@ -395,6 +402,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
 });
 
 impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
+    IfTemporary,
     Async,
     Await,
     QuestionMark,
diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs
index b407b75e68c..f3fc7ec8fda 100644
--- a/src/librustc/ich/mod.rs
+++ b/src/librustc/ich/mod.rs
@@ -4,6 +4,8 @@ crate use rustc_data_structures::fingerprint::Fingerprint;
 pub use self::caching_source_map_view::CachingSourceMapView;
 pub use self::hcx::{StableHashingContextProvider, StableHashingContext, NodeIdHashingMode,
                     hash_stable_trait_impls};
+use syntax::symbol::{Symbol, sym};
+
 mod caching_source_map_view;
 mod hcx;
 
@@ -12,16 +14,16 @@ mod impls_misc;
 mod impls_ty;
 mod impls_syntax;
 
-pub const ATTR_DIRTY: &str = "rustc_dirty";
-pub const ATTR_CLEAN: &str = "rustc_clean";
-pub const ATTR_IF_THIS_CHANGED: &str = "rustc_if_this_changed";
-pub const ATTR_THEN_THIS_WOULD_NEED: &str = "rustc_then_this_would_need";
-pub const ATTR_PARTITION_REUSED: &str = "rustc_partition_reused";
-pub const ATTR_PARTITION_CODEGENED: &str = "rustc_partition_codegened";
-pub const ATTR_EXPECTED_CGU_REUSE: &str = "rustc_expected_cgu_reuse";
+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: &[&str] = &[
-    "cfg",
+pub const IGNORED_ATTRIBUTES: &[Symbol] = &[
+    sym::cfg,
     ATTR_IF_THIS_CHANGED,
     ATTR_THEN_THIS_WOULD_NEED,
     ATTR_DIRTY,
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 4b6e7da3330..e4505a24037 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -194,20 +194,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 let mut sp = cm.def_span(self.hir().span_by_hir_id(node));
                 if let Some(param) = self.hir()
                     .get_generics(scope)
-                    .and_then(|generics| generics.get_named(&br.name))
+                    .and_then(|generics| generics.get_named(br.name))
                 {
                     sp = param.span;
                 }
                 (format!("the lifetime {} as defined on", br.name), sp)
             }
             ty::ReFree(ty::FreeRegion {
-                bound_region: ty::BoundRegion::BrNamed(_, ref name),
+                bound_region: ty::BoundRegion::BrNamed(_, name),
                 ..
             }) => {
                 let mut sp = cm.def_span(self.hir().span_by_hir_id(node));
                 if let Some(param) = self.hir()
                     .get_generics(scope)
-                    .and_then(|generics| generics.get_named(&name))
+                    .and_then(|generics| generics.get_named(name))
                 {
                     sp = param.span;
                 }
diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs
index 3ed28a1f988..feade7a8f56 100644
--- a/src/librustc/infer/error_reporting/nice_region_error/util.rs
+++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs
@@ -43,7 +43,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
     ) -> Option<AnonymousArgInfo<'_>> {
         let (id, bound_region) = match *anon_region {
             ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
-            ty::ReEarlyBound(ref ebr) => (
+            ty::ReEarlyBound(ebr) => (
                 self.tcx().parent(ebr.def_id).unwrap(),
                 ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
             ),
diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc/infer/lexical_region_resolve/graphviz.rs
index 073a3f74422..1878afd581d 100644
--- a/src/librustc/infer/lexical_region_resolve/graphviz.rs
+++ b/src/librustc/infer/lexical_region_resolve/graphviz.rs
@@ -56,7 +56,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
     }
 
     let requested_node = env::var("RUST_REGION_GRAPH_NODE")
-        .ok().and_then(|s| s.parse().map(DefIndex::from_raw_u32).ok());
+        .ok().and_then(|s| s.parse().map(DefIndex::from_u32).ok());
 
     if requested_node.is_some() && requested_node != Some(context.index) {
         return;
@@ -90,7 +90,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
             let mut new_str = String::new();
             for c in output_template.chars() {
                 if c == '%' {
-                    new_str.push_str(&context.index.as_raw_u32().to_string());
+                    new_str.push_str(&context.index.as_u32().to_string());
                 } else {
                     new_str.push(c);
                 }
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index f85fd524a5d..4351f94df2f 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -284,18 +284,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         debug!("constrain_opaque_type: def_id={:?}", def_id);
         debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn);
 
+        let tcx = self.tcx;
+
         let concrete_ty = self.resolve_type_vars_if_possible(&opaque_defn.concrete_ty);
 
         debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty);
 
-        let abstract_type_generics = self.tcx.generics_of(def_id);
+        let abstract_type_generics = tcx.generics_of(def_id);
 
-        let span = self.tcx.def_span(def_id);
+        let span = tcx.def_span(def_id);
 
-        // If there are required region bounds, we can just skip
-        // ahead.  There will already be a registered region
-        // obligation related `concrete_ty` to those regions.
+        // If there are required region bounds, we can use them.
         if opaque_defn.has_required_region_bounds {
+            let predicates_of = tcx.predicates_of(def_id);
+            debug!(
+                "constrain_opaque_type: predicates: {:#?}",
+                predicates_of,
+            );
+            let bounds = predicates_of.instantiate(tcx, opaque_defn.substs);
+            debug!("constrain_opaque_type: bounds={:#?}", bounds);
+            let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
+
+            let required_region_bounds = tcx.required_region_bounds(
+                opaque_type,
+                bounds.predicates.clone(),
+            );
+            debug_assert!(!required_region_bounds.is_empty());
+
+            for region in required_region_bounds {
+                concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor {
+                    infcx: self,
+                    least_region: region,
+                    span,
+                });
+            }
             return;
         }
 
@@ -371,7 +393,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        let least_region = least_region.unwrap_or(self.tcx.lifetimes.re_static);
+        let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
         debug!("constrain_opaque_types: least_region={:?}", least_region);
 
         concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor {
@@ -589,10 +611,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx>
             ty::ReLateBound(..) |
 
             // ignore `'static`, as that can appear anywhere
-            ty::ReStatic |
-
-            // ignore `ReScope`, which may appear in impl Trait in bindings.
-            ty::ReScope(..) => return r,
+            ty::ReStatic => return r,
 
             _ => { }
         }
@@ -683,6 +702,23 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx>
                 self.tcx.mk_closure(def_id, ty::ClosureSubsts { substs })
             }
 
+            ty::Generator(def_id, substs, movability) => {
+                let generics = self.tcx.generics_of(def_id);
+                let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map(
+                    |(index, &kind)| {
+                        if index < generics.parent_count {
+                            // Accommodate missing regions in the parent kinds...
+                            self.fold_kind_mapping_missing_regions_to_empty(kind)
+                        } else {
+                            // ...but not elsewhere.
+                            self.fold_kind_normally(kind)
+                        }
+                    },
+                ));
+
+                self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability)
+            }
+
             _ => ty.super_fold_with(self),
         }
     }
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 993e1aacb4e..69d865f53d4 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -199,12 +199,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    pub INCOHERENT_FUNDAMENTAL_IMPLS,
-    Deny,
-    "potentially-conflicting impls were erroneously allowed"
-}
-
-declare_lint! {
     pub ORDER_DEPENDENT_TRAIT_OBJECTS,
     Deny,
     "trait-object types were treated as different depending on marker-trait order"
@@ -428,7 +422,6 @@ declare_lint_pass! {
         MISSING_FRAGMENT_SPECIFIER,
         PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
         LATE_BOUND_LIFETIME_ARGUMENTS,
-        INCOHERENT_FUNDAMENTAL_IMPLS,
         ORDER_DEPENDENT_TRAIT_OBJECTS,
         DEPRECATED,
         UNUSED_UNSAFE,
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index e713cf8d805..7e1e751e856 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -828,8 +828,8 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
 
                 // This shouldn't ever be needed, but just in case:
                 Ok(vec![match trait_ref {
-                    Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)).as_str(),
-                    None => Symbol::intern(&format!("<{}>", self_ty)).as_str(),
+                    Some(trait_ref) => LocalInternedString::intern(&format!("{:?}", trait_ref)),
+                    None => LocalInternedString::intern(&format!("<{}>", self_ty)),
                 }])
             }
 
@@ -845,9 +845,10 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
                 // This shouldn't ever be needed, but just in case:
                 path.push(match trait_ref {
                     Some(trait_ref) => {
-                        Symbol::intern(&format!("<impl {} for {}>", trait_ref, self_ty)).as_str()
+                        LocalInternedString::intern(&format!("<impl {} for {}>", trait_ref,
+                                                    self_ty))
                     },
-                    None => Symbol::intern(&format!("<impl {}>", self_ty)).as_str(),
+                    None => LocalInternedString::intern(&format!("<impl {}>", self_ty)),
                 });
 
                 Ok(path)
diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs
index 2e5bd8add0c..9c926dff325 100644
--- a/src/librustc/lint/levels.rs
+++ b/src/librustc/lint/levels.rs
@@ -14,7 +14,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate;
 use syntax::source_map::MultiSpan;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 
 pub struct LintLevelSets {
     list: Vec<LintSet>,
@@ -194,7 +194,7 @@ impl<'a> LintLevelsBuilder<'a> {
             struct_span_err!(sess, span, E0452, "malformed lint attribute")
         };
         for attr in attrs {
-            let level = match Level::from_str(&attr.name_or_empty()) {
+            let level = match Level::from_symbol(attr.name_or_empty()) {
                 None => continue,
                 Some(lvl) => lvl,
             };
@@ -221,7 +221,7 @@ impl<'a> LintLevelsBuilder<'a> {
                 match item.node {
                     ast::MetaItemKind::Word => {}  // actual lint names handled later
                     ast::MetaItemKind::NameValue(ref name_value) => {
-                        if item.path == "reason" {
+                        if item.path == sym::reason {
                             // found reason, reslice meta list to exclude it
                             metas = &metas[0..metas.len()-1];
                             // FIXME (#55112): issue unused-attributes lint if we thereby
@@ -230,7 +230,7 @@ impl<'a> LintLevelsBuilder<'a> {
                                 if !self.sess.features_untracked().lint_reasons {
                                     feature_gate::emit_feature_err(
                                         &self.sess.parse_sess,
-                                        "lint_reasons",
+                                        sym::lint_reasons,
                                         item.span,
                                         feature_gate::GateIssue::Language,
                                         "lint reasons are experimental"
@@ -261,7 +261,7 @@ impl<'a> LintLevelsBuilder<'a> {
                         let mut err = bad_attr(li.span());
                         if let Some(item) = li.meta_item() {
                             if let ast::MetaItemKind::NameValue(_) = item.node {
-                                if item.path == "reason" {
+                                if item.path == sym::reason {
                                     err.help("reason in lint attribute must come last");
                                 }
                             }
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index 6613440ee7c..9c4683e0946 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -38,7 +38,7 @@ use syntax::ast;
 use syntax::source_map::{MultiSpan, ExpnFormat};
 use syntax::early_buffered_lints::BufferedEarlyLintId;
 use syntax::edition::Edition;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 
 pub use crate::lint::context::{LateContext, EarlyContext, LintContext, LintStore,
@@ -570,6 +570,17 @@ impl Level {
             _ => None,
         }
     }
+
+    /// Converts a symbol to a level.
+    pub fn from_symbol(x: Symbol) -> Option<Level> {
+        match x {
+            sym::allow => Some(Allow),
+            sym::warn => Some(Warn),
+            sym::deny => Some(Deny),
+            sym::forbid => Some(Forbid),
+            _ => None,
+        }
+    }
 }
 
 /// How a lint level was set.
@@ -752,7 +763,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
 
 pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool {
     let attrs = tcx.hir().attrs_by_hir_id(id);
-    attrs.iter().any(|attr| Level::from_str(&attr.name_or_empty()).is_some())
+    attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some())
 }
 
 fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
@@ -767,6 +778,9 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
 
     let push = builder.levels.push(&krate.attrs);
     builder.levels.register_id(hir::CRATE_HIR_ID);
+    for macro_def in &krate.exported_macros {
+       builder.levels.register_id(macro_def.hir_id);
+    }
     intravisit::walk_crate(&mut builder, krate);
     builder.levels.pop(push);
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index a0107ed0546..2a9928567f4 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -19,6 +19,7 @@ use rustc_data_structures::fx::FxHashMap;
 
 use syntax::{ast, source_map};
 use syntax::attr;
+use syntax::symbol::sym;
 use syntax_pos;
 
 // Any local node that may call something in its body block should be
@@ -304,22 +305,22 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
 fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_, '_, '_>,
                                     id: hir::HirId,
                                     attrs: &[ast::Attribute]) -> bool {
-    if attr::contains_name(attrs, "lang") {
+    if attr::contains_name(attrs, sym::lang) {
         return true;
     }
 
     // Stable attribute for #[lang = "panic_impl"]
-    if attr::contains_name(attrs, "panic_handler") {
+    if attr::contains_name(attrs, sym::panic_handler) {
         return true;
     }
 
     // (To be) stable attribute for #[lang = "oom"]
-    if attr::contains_name(attrs, "alloc_error_handler") {
+    if attr::contains_name(attrs, sym::alloc_error_handler) {
         return true;
     }
 
     // Don't lint about global allocators
-    if attr::contains_name(attrs, "global_allocator") {
+    if attr::contains_name(attrs, sym::global_allocator) {
         return true;
     }
 
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index df77033ebef..67db2ec2481 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -4,6 +4,7 @@ use crate::session::{config, Session};
 use crate::session::config::EntryFnType;
 use syntax::attr;
 use syntax::entry::EntryPointType;
+use syntax::symbol::sym;
 use syntax_pos::Span;
 use crate::hir::{HirId, Item, ItemKind, ImplItem, TraitItem};
 use crate::hir::itemlikevisit::ItemLikeVisitor;
@@ -58,7 +59,7 @@ fn entry_fn(tcx: TyCtxt<'_, '_, '_>, cnum: CrateNum) -> Option<(DefId, EntryFnTy
     }
 
     // If the user wants no main function at all, then stop here.
-    if attr::contains_name(&tcx.hir().krate().attrs, "no_main") {
+    if attr::contains_name(&tcx.hir().krate().attrs, sym::no_main) {
         return None;
     }
 
@@ -81,11 +82,11 @@ fn entry_fn(tcx: TyCtxt<'_, '_, '_>, cnum: CrateNum) -> Option<(DefId, EntryFnTy
 fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
     match item.node {
         ItemKind::Fn(..) => {
-            if attr::contains_name(&item.attrs, "start") {
+            if attr::contains_name(&item.attrs, sym::start) {
                 EntryPointType::Start
-            } else if attr::contains_name(&item.attrs, "main") {
+            } else if attr::contains_name(&item.attrs, sym::main) {
                 EntryPointType::MainAttr
-            } else if item.ident.name == "main" {
+            } else if item.ident.name == sym::main {
                 if at_root {
                     // This is a top-level function so can be 'main'.
                     EntryPointType::MainNamed
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 93ba4241c47..d46bba92f3f 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -424,14 +424,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 self.consume_exprs(exprs);
             }
 
-            hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => {
-                self.consume_expr(&cond_expr);
-                self.walk_expr(&then_expr);
-                if let Some(ref else_expr) = *opt_else_expr {
-                    self.consume_expr(&else_expr);
-                }
-            }
-
             hir::ExprKind::Match(ref discr, ref arms, _) => {
                 let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr)));
                 let r = self.tcx().lifetimes.re_empty;
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 0e283ca6b1c..103580a598f 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -18,7 +18,7 @@ use crate::middle::weak_lang_items;
 use crate::util::nodemap::FxHashMap;
 
 use syntax::ast;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 use rustc_macros::HashStable;
 use crate::hir::itemlikevisit::ItemLikeVisitor;
@@ -209,9 +209,9 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
 /// are also extracted out when found.
 pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     attrs.iter().find_map(|attr| Some(match attr {
-        _ if attr.check_name("lang") => (attr.value_str()?, attr.span),
-        _ if attr.check_name("panic_handler") => (Symbol::intern("panic_impl"), attr.span),
-        _ if attr.check_name("alloc_error_handler") => (Symbol::intern("oom"), attr.span),
+        _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span),
+        _ if attr.check_name(sym::panic_handler) => (Symbol::intern("panic_impl"), attr.span),
+        _ if attr.check_name(sym::alloc_error_handler) => (Symbol::intern("oom"), attr.span),
         _ => return None,
     }))
 }
diff --git a/src/librustc/middle/lib_features.rs b/src/librustc/middle/lib_features.rs
index e79ef8bfc6f..76934ddd69b 100644
--- a/src/librustc/middle/lib_features.rs
+++ b/src/librustc/middle/lib_features.rs
@@ -8,7 +8,7 @@ use crate::ty::TyCtxt;
 use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use syntax::symbol::Symbol;
 use syntax::ast::{Attribute, MetaItem, MetaItemKind};
-use syntax_pos::{Span, symbols};
+use syntax_pos::{Span, sym};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use rustc_macros::HashStable;
 use errors::DiagnosticId;
@@ -51,7 +51,7 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
     }
 
     fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
-        let stab_attrs = [symbols::stable, symbols::unstable, symbols::rustc_const_unstable];
+        let stab_attrs = [sym::stable, sym::unstable, sym::rustc_const_unstable];
 
         // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
         // `#[rustc_const_unstable (..)]`).
@@ -65,9 +65,9 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
                 for meta in metas {
                     if let Some(mi) = meta.meta_item() {
                         // Find the `feature = ".."` meta-item.
-                        match (mi.name_or_empty().get(), mi.value_str()) {
-                            ("feature", val) => feature = val,
-                            ("since", val) => since = val,
+                        match (mi.name_or_empty(), mi.value_str()) {
+                            (sym::feature, val) => feature = val,
+                            (sym::since, val) => since = val,
                             _ => {}
                         }
                     }
@@ -76,7 +76,7 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
                     // This additional check for stability is to make sure we
                     // don't emit additional, irrelevant errors for malformed
                     // attributes.
-                    if *stab_attr != "stable" || since.is_some() {
+                    if *stab_attr != sym::stable || since.is_some() {
                         return Some((feature, since, attr.span));
                     }
                 }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 4b458e474b2..cb333b5b0cb 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -112,7 +112,7 @@ use std::io;
 use std::rc::Rc;
 use syntax::ast::{self, NodeId};
 use syntax::ptr::P;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax_pos::Span;
 
 use crate::hir;
@@ -362,7 +362,7 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
     if let FnKind::Method(..) = fk {
         let parent = ir.tcx.hir().get_parent_item(id);
         if let Some(Node::Item(i)) = ir.tcx.hir().find_by_hir_id(parent) {
-            if i.attrs.iter().any(|a| a.check_name("automatically_derived")) {
+            if i.attrs.iter().any(|a| a.check_name(sym::automatically_derived)) {
                 return;
             }
         }
@@ -500,7 +500,6 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
       }
 
       // live nodes required for interesting control flow:
-      hir::ExprKind::If(..) |
       hir::ExprKind::Match(..) |
       hir::ExprKind::While(..) |
       hir::ExprKind::Loop(..) => {
@@ -1040,28 +1039,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 })
             }
 
-            hir::ExprKind::If(ref cond, ref then, ref els) => {
-                //
-                //     (cond)
-                //       |
-                //       v
-                //     (expr)
-                //     /   \
-                //    |     |
-                //    v     v
-                //  (then)(els)
-                //    |     |
-                //    v     v
-                //   (  succ  )
-                //
-                let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
-                let then_ln = self.propagate_through_expr(&then, succ);
-                let ln = self.live_node(expr.hir_id, expr.span);
-                self.init_from_succ(ln, else_ln);
-                self.merge_from_succ(ln, then_ln, false);
-                self.propagate_through_expr(&cond, ln)
-            }
-
             hir::ExprKind::While(ref cond, ref blk, _) => {
                 self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ)
             }
@@ -1523,7 +1500,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
         }
 
         // no correctness conditions related to liveness
-        hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::If(..) |
+        hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) |
         hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
         hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
         hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 7edd5c5a9de..c7f8cf684e6 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -72,6 +72,7 @@ use crate::hir::{MutImmutable, MutMutable, PatKind};
 use crate::hir::pat_util::EnumerateAndAdjustIterator;
 use crate::hir;
 use syntax::ast::{self, Name};
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 use std::borrow::Cow;
@@ -678,7 +679,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) |
             hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
             hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) |
-            hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) |
+            hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) |
             hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
             hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
             hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) |
@@ -714,7 +715,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                 // they also cannot be moved out of.
                 let is_thread_local = self.tcx.get_attrs(def_id)[..]
                     .iter()
-                    .any(|attr| attr.check_name("thread_local"));
+                    .any(|attr| attr.check_name(sym::thread_local));
 
                 let cat = if is_thread_local {
                     let re = self.temporary_scope(hir_id.local_id);
diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs
index ea077220e0b..5f355d17072 100644
--- a/src/librustc/middle/recursion_limit.rs
+++ b/src/librustc/middle/recursion_limit.rs
@@ -7,15 +7,16 @@
 
 use crate::session::Session;
 use syntax::ast;
+use syntax::symbol::{Symbol, sym};
 
 use rustc_data_structures::sync::Once;
 
 pub fn update_limits(sess: &Session, krate: &ast::Crate) {
-    update_limit(krate, &sess.recursion_limit, "recursion_limit", 64);
-    update_limit(krate, &sess.type_length_limit, "type_length_limit", 1048576);
+    update_limit(krate, &sess.recursion_limit, sym::recursion_limit, 64);
+    update_limit(krate, &sess.type_length_limit, sym::type_length_limit, 1048576);
 }
 
-fn update_limit(krate: &ast::Crate, limit: &Once<usize>, name: &str, default: usize) {
+fn update_limit(krate: &ast::Crate, limit: &Once<usize>, name: Symbol, default: usize) {
     for attr in &krate.attrs {
         if !attr.check_name(name) {
             continue;
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 2b88f273adc..37681ad7fcd 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -158,7 +158,7 @@ newtype_index! {
 impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private });
 
 // compilation error if size of `ScopeData` is not the same as a `u32`
-static_assert!(ASSERT_SCOPE_DATA: mem::size_of::<ScopeData>() == 4);
+static_assert_size!(ScopeData, 4);
 
 impl Scope {
     /// Returns a item-local ID associated with this scope.
@@ -884,17 +884,6 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
                     terminating(r.hir_id.local_id);
             }
 
-            hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => {
-                terminating(expr.hir_id.local_id);
-                terminating(then.hir_id.local_id);
-                terminating(otherwise.hir_id.local_id);
-            }
-
-            hir::ExprKind::If(ref expr, ref then, None) => {
-                terminating(expr.hir_id.local_id);
-                terminating(then.hir_id.local_id);
-            }
-
             hir::ExprKind::Loop(ref body, _, _) => {
                 terminating(body.hir_id.local_id);
             }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d835d872d76..2402d0eefde 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -23,7 +23,7 @@ use std::mem::replace;
 use syntax::ast;
 use syntax::attr;
 use syntax::ptr::P;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax_pos::Span;
 
 use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -1285,7 +1285,7 @@ fn compute_object_lifetime_defaults(
                 let result = object_lifetime_defaults_for_item(tcx, generics);
 
                 // Debugging aid.
-                if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") {
+                if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) {
                     let object_lifetime_default_reprs: String = result
                         .iter()
                         .map(|set| match *set {
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 5078bd7c594..abcf164cda6 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -11,7 +11,7 @@ use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::ty::query::Providers;
 use crate::middle::privacy::AccessLevels;
 use crate::session::{DiagnosticMessageId, Session};
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::{Span, MultiSpan};
 use syntax::ast::Attribute;
 use syntax::errors::Applicability;
@@ -195,7 +195,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
             // Emit errors for non-staged-api crates.
             for attr in attrs {
                 let name = attr.name_or_empty();
-                if ["unstable", "stable", "rustc_deprecated"].contains(&name.get()) {
+                if [sym::unstable, sym::stable, sym::rustc_deprecated].contains(&name) {
                     attr::mark_used(attr);
                     self.tcx.sess.span_err(attr.span, "stability attributes may not be used \
                                                         outside of the standard library");
@@ -669,7 +669,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         match stability {
             Some(&Stability { level: attr::Unstable { reason, issue }, feature, .. }) => {
-                if span.allows_unstable(&feature.as_str()) {
+                if span.allows_unstable(feature) {
                     debug!("stability: skipping span={:?} since it is internal", span);
                     return EvalResult::Allow;
                 }
@@ -686,7 +686,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 // the `-Z force-unstable-if-unmarked` flag present (we're
                 // compiling a compiler crate), then let this missing feature
                 // annotation slide.
-                if feature == "rustc_private" && issue == 27812 {
+                if feature == sym::rustc_private && issue == 27812 {
                     if self.sess.opts.debugging_opts.force_unstable_if_unmarked {
                         return EvalResult::Allow;
                     }
@@ -739,7 +739,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone());
                 let fresh = self.sess.one_time_diagnostics.borrow_mut().insert(error_id);
                 if fresh {
-                    emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span,
+                    emit_feature_err(&self.sess.parse_sess, feature, span,
                                      GateIssue::Library(Some(issue)), &msg);
                 }
             }
@@ -802,13 +802,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
 
                 if adt_def.has_dtor(self.tcx) {
                     emit_feature_err(&self.tcx.sess.parse_sess,
-                                     "untagged_unions", item.span, GateIssue::Language,
+                                     sym::untagged_unions, item.span, GateIssue::Language,
                                      "unions with `Drop` implementations are unstable");
                 } else {
                     let param_env = self.tcx.param_env(def_id);
                     if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
                         emit_feature_err(&self.tcx.sess.parse_sess,
-                                         "untagged_unions", item.span, GateIssue::Language,
+                                         sym::untagged_unions, item.span, GateIssue::Language,
                                          "unions with non-`Copy` fields are unstable");
                     }
                 }
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 312924e5e90..75c21c738f7 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -6,7 +6,7 @@ use crate::middle::lang_items;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_target::spec::PanicStrategy;
 use syntax::ast;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 use crate::hir::def_id::DefId;
 use crate::hir::intravisit::{Visitor, NestedVisitorMap};
@@ -46,8 +46,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
     lang_items::extract(attrs).and_then(|(name, _)| {
-        $(if name == stringify!($name) {
-            Some(Symbol::intern(stringify!($sym)))
+        $(if name == sym::$name {
+            Some(sym::$sym)
         } else)* {
             None
         }
diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs
index 75e0f704a58..59b7891b90f 100644
--- a/src/librustc/mir/interpret/pointer.rs
+++ b/src/librustc/mir/interpret/pointer.rs
@@ -78,7 +78,7 @@ pub struct Pointer<Tag=(),Id=AllocId> {
     pub tag: Tag,
 }
 
-static_assert!(POINTER_SIZE: ::std::mem::size_of::<Pointer>() == 16);
+static_assert_size!(Pointer, 16);
 
 /// Produces a `Pointer` which points to the beginning of the Allocation
 impl From<AllocId> for Pointer {
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 7e45568725f..551b86390db 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -54,7 +54,7 @@ pub enum ConstValue<'tcx> {
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue<'static>>() == 40);
+static_assert_size!(ConstValue<'_>, 40);
 
 impl<'tcx> ConstValue<'tcx> {
     #[inline]
@@ -111,7 +111,7 @@ pub enum Scalar<Tag=(), Id=AllocId> {
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert!(SCALAR_SIZE: ::std::mem::size_of::<Scalar>() == 24);
+static_assert_size!(Scalar, 24);
 
 impl<Tag> fmt::Display for Scalar<Tag> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index bd67aabfe8e..dd43cb2f18e 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1738,7 +1738,7 @@ pub struct Statement<'tcx> {
 
 // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::<Statement<'_>>() == 56);
+static_assert_size!(Statement<'_>, 56);
 
 impl<'tcx> Statement<'tcx> {
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -1997,10 +1997,9 @@ pub type PlaceProjection<'tcx> = Projection<Place<'tcx>, Local, Ty<'tcx>>;
 /// and the index is a local.
 pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 
-// at least on 64 bit systems, `PlaceElem` should not be larger than two pointers
-static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE:
-    mem::size_of::<PlaceElem<'_>>() <= 16
-);
+// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PlaceElem<'_>, 16);
 
 /// Alias for projections as they appear in `UserTypeProjection`, where we
 /// need neither the `V` parameter for `Index` nor the `T` for `Field`.
diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs
index e82e90ede8c..a26468b0fb6 100644
--- a/src/librustc/mir/mono.rs
+++ b/src/librustc/mir/mono.rs
@@ -1,6 +1,6 @@
 use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
 use crate::hir::HirId;
-use syntax::symbol::{Symbol, InternedString};
+use syntax::symbol::InternedString;
 use crate::ty::{Instance, TyCtxt};
 use crate::util::nodemap::FxHashMap;
 use rustc_data_structures::base_n;
@@ -280,7 +280,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
             cgu_name
         } else {
             let cgu_name = &cgu_name.as_str()[..];
-            Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
+            InternedString::intern(&CodegenUnit::mangle_name(cgu_name))
         }
     }
 
@@ -336,6 +336,6 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
             write!(cgu_name, ".{}", special_suffix).unwrap();
         }
 
-        Symbol::intern(&cgu_name[..]).as_interned_str()
+        InternedString::intern(&cgu_name[..])
     }
 }
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index d3fa5e84b6a..5135aeb2392 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -17,9 +17,9 @@ pub struct PlaceTy<'tcx> {
     pub variant_index: Option<VariantIdx>,
 }
 
-static_assert!(PLACE_TY_IS_3_PTRS_LARGE:
-    mem::size_of::<PlaceTy<'_>>() <= 24
-);
+// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(PlaceTy<'_>, 16);
 
 impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
     pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 0e7b66b7444..2fff4c3f109 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -1052,7 +1052,7 @@ rustc_queries! {
     }
 
     Other {
-        query target_features_whitelist(_: CrateNum) -> Lrc<FxHashMap<String, Option<String>>> {
+        query target_features_whitelist(_: CrateNum) -> Lrc<FxHashMap<String, Option<Symbol>>> {
             eval_always
             desc { "looking up the whitelist of target features" }
         }
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 12427daa383..b5e3c4cda0a 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1744,8 +1744,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
         opt::multi_s(
             "",
             "print",
-            "Comma separated list of compiler information to \
-             print on stdout",
+            "Compiler information to print on stdout",
             "[crate-name|file-names|sysroot|cfg|target-list|\
              target-cpus|target-features|relocation-models|\
              code-models|tls-models|target-spec-json|native-static-libs]",
@@ -2753,6 +2752,7 @@ mod tests {
     // another --cfg test
     #[test]
     fn test_switch_implies_cfg_test_unless_cfg_test() {
+        use syntax::symbol::sym;
         syntax::with_globals(|| {
             let matches = &match optgroups().parse(&["--test".to_string(),
                                                      "--cfg=test".to_string()]) {
@@ -2763,7 +2763,7 @@ mod tests {
             let (sessopts, cfg) = build_session_options_and_crate_config(matches);
             let sess = build_session(sessopts, None, registry);
             let cfg = build_configuration(&sess, to_crate_config(cfg));
-            let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
+            let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
             assert!(test_items.next().is_some());
             assert!(test_items.next().is_none());
         });
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index e8c7965ab4f..4d47491661e 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -29,6 +29,7 @@ use syntax::feature_gate::{self, AttributeType};
 use syntax::json::JsonEmitter;
 use syntax::source_map;
 use syntax::parse::{self, ParseSess};
+use syntax::symbol::Symbol;
 use syntax_pos::{MultiSpan, Span};
 use crate::util::profiling::SelfProfiler;
 
@@ -86,7 +87,7 @@ pub struct Session {
     /// in order to avoid redundantly verbose output (Issue #24690, #44953).
     pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
     pub plugin_llvm_passes: OneThread<RefCell<Vec<String>>>,
-    pub plugin_attributes: Lock<Vec<(String, AttributeType)>>,
+    pub plugin_attributes: Lock<Vec<(Symbol, AttributeType)>>,
     pub crate_types: Once<Vec<config::CrateType>>,
     pub dependency_formats: Once<dependency_format::Dependencies>,
     /// The crate_disambiguator is constructed out of all the `-C metadata`
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 35d8e2beef5..afbce5a4f0a 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -4,17 +4,16 @@
 //! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
 //! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html
 
-use crate::infer::CombinedSnapshot;
+use crate::infer::{CombinedSnapshot, InferOk};
 use crate::hir::def_id::{DefId, LOCAL_CRATE};
-use syntax_pos::DUMMY_SP;
 use crate::traits::{self, Normalized, SelectionContext, Obligation, ObligationCause};
 use crate::traits::IntercrateMode;
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::ty::{self, Ty, TyCtxt};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::Subst;
-
-use crate::infer::{InferOk};
+use syntax::symbol::sym;
+use syntax_pos::DUMMY_SP;
 
 /// Whether we do the orphan check relative to this crate or
 /// to some remote crate.
@@ -233,7 +232,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 pub fn trait_ref_is_local_or_fundamental<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                                          trait_ref: ty::TraitRef<'tcx>)
                                                          -> bool {
-    trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, "fundamental")
+    trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
 }
 
 pub enum OrphanCheckErr<'tcx> {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index d9ccbba69d5..9019c4a0575 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -35,6 +35,7 @@ use crate::util::nodemap::{FxHashMap, FxHashSet};
 use errors::{Applicability, DiagnosticBuilder};
 use std::fmt;
 use syntax::ast;
+use syntax::symbol::sym;
 use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnFormat};
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
@@ -329,7 +330,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return None
         };
 
-        if tcx.has_attr(impl_def_id, "rustc_on_unimplemented") {
+        if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) {
             Some(impl_def_id)
         } else {
             None
@@ -642,13 +643,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             .map(|s| &s == "?")
                             .unwrap_or(false);
                         let is_from = format!("{}", trait_ref).starts_with("std::convert::From<");
-                        let message = if is_try && is_from {
-                            Some(format!(
+                        let (message, note) = if is_try && is_from {
+                            (Some(format!(
                                 "`?` couldn't convert the error to `{}`",
                                 trait_ref.self_ty(),
+                            )), Some(
+                                "the question mark operation (`?`) implicitly performs a \
+                                 conversion on the error value using the `From` trait".to_owned()
                             ))
                         } else {
-                            message
+                            (message, note)
                         };
 
                         let mut err = struct_span_err!(
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 1c8ea5c7b9c..55216f644a1 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -18,7 +18,8 @@ use crate::ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate};
 use crate::ty::subst::{Subst, InternalSubsts};
 use std::borrow::Cow;
 use std::iter::{self};
-use syntax::ast::{self, Name};
+use syntax::ast::{self};
+use syntax::symbol::InternedString;
 use syntax_pos::Span;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -539,7 +540,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
         // are implemented
         let unsized_self_ty: Ty<'tcx> = self.mk_ty_param(
             ::std::u32::MAX,
-            Name::intern("RustaceansAreAwesome").as_interned_str(),
+            InternedString::intern("RustaceansAreAwesome"),
         );
 
         // `Receiver[Self => U]`
diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs
index 2b286ee1b97..7ba7429f465 100644
--- a/src/librustc/traits/on_unimplemented.rs
+++ b/src/librustc/traits/on_unimplemented.rs
@@ -7,6 +7,7 @@ use crate::util::nodemap::FxHashMap;
 
 use syntax::ast::{MetaItem, NestedMetaItem};
 use syntax::attr;
+use syntax::symbol::sym;
 use syntax_pos::Span;
 use syntax_pos::symbol::LocalInternedString;
 
@@ -84,25 +85,25 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
         let mut note = None;
         let mut subcommands = vec![];
         for item in item_iter {
-            if item.check_name("message") && message.is_none() {
+            if item.check_name(sym::message) && message.is_none() {
                 if let Some(message_) = item.value_str() {
                     message = Some(OnUnimplementedFormatString::try_parse(
                         tcx, trait_def_id, message_.as_str(), span)?);
                     continue;
                 }
-            } else if item.check_name("label") && label.is_none() {
+            } else if item.check_name(sym::label) && label.is_none() {
                 if let Some(label_) = item.value_str() {
                     label = Some(OnUnimplementedFormatString::try_parse(
                         tcx, trait_def_id, label_.as_str(), span)?);
                     continue;
                 }
-            } else if item.check_name("note") && note.is_none() {
+            } else if item.check_name(sym::note) && note.is_none() {
                 if let Some(note_) = item.value_str() {
                     note = Some(OnUnimplementedFormatString::try_parse(
                         tcx, trait_def_id, note_.as_str(), span)?);
                     continue;
                 }
-            } else if item.check_name("on") && is_root &&
+            } else if item.check_name(sym::on) && is_root &&
                 message.is_none() && label.is_none() && note.is_none()
             {
                 if let Some(items) = item.meta_item_list() {
@@ -139,7 +140,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
     {
         let attrs = tcx.get_attrs(impl_def_id);
 
-        let attr = if let Some(item) = attr::find_by_name(&attrs, "rustc_on_unimplemented") {
+        let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) {
             item
         } else {
             return Ok(None);
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index b5232e828c4..67e76f7625c 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -19,6 +19,7 @@ use crate::mir::interpret::{GlobalId, ConstValue};
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use rustc_macros::HashStable;
 use syntax::ast::Ident;
+use syntax::symbol::sym;
 use crate::ty::subst::{Subst, InternalSubsts};
 use crate::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
 use crate::ty::fold::{TypeFoldable, TypeFolder};
@@ -1318,9 +1319,9 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>(
                                             gen_sig)
         .map_bound(|(trait_ref, yield_ty, return_ty)| {
             let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
-            let ty = if name == "Return" {
+            let ty = if name == sym::Return {
                 return_ty
-            } else if name == "Yield" {
+            } else if name == sym::Yield {
                 yield_ty
             } else {
                 bug!()
@@ -1420,7 +1421,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
                 projection_ty: ty::ProjectionTy::from_ref_and_name(
                     tcx,
                     trait_ref,
-                    Ident::from_str(FN_OUTPUT_NAME),
+                    Ident::with_empty_ctxt(FN_OUTPUT_NAME),
                 ),
                 ty: ret_type
             }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index d68e2be9ea0..c4be85050db 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -43,6 +43,7 @@ use crate::hir;
 use rustc_data_structures::bit_set::GrowableBitSet;
 use rustc_data_structures::sync::Lock;
 use rustc_target::spec::abi::Abi;
+use std::cell::Cell;
 use std::cmp;
 use std::fmt::{self, Display};
 use std::iter;
@@ -153,6 +154,36 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
     /// selection-context's freshener. Used to check for recursion.
     fresh_trait_ref: ty::PolyTraitRef<'tcx>,
 
+    /// Starts out as false -- if, during evaluation, we encounter a
+    /// cycle, then we will set this flag to true for all participants
+    /// in the cycle (apart from the "head" node). These participants
+    /// will then forego caching their results. This is not the most
+    /// efficient solution, but it addresses #60010. The problem we
+    /// are trying to prevent:
+    ///
+    /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
+    /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
+    /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok)
+    ///
+    /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait`
+    /// is `EvaluatedToOk`; this is because they were only considered
+    /// ok on the premise that if `A: AutoTrait` held, but we indeed
+    /// encountered a problem (later on) with `A: AutoTrait. So we
+    /// currently set a flag on the stack node for `B: AutoTrait` (as
+    /// well as the second instance of `A: AutoTrait`) to supress
+    /// caching.
+    ///
+    /// This is a simple, targeted fix. A more-performant fix requires
+    /// deeper changes, but would permit more caching: we could
+    /// basically defer caching until we have fully evaluated the
+    /// tree, and then cache the entire tree at once. In any case, the
+    /// performance impact here shouldn't be so horrible: every time
+    /// this is hit, we do cache at least one trait, so we only
+    /// evaluate each member of a cycle up to N times, where N is the
+    /// length of the cycle. This means the performance impact is
+    /// bounded and we shouldn't have any terrible worst-cases.
+    in_cycle: Cell<bool>,
+
     previous: TraitObligationStackList<'prev, 'tcx>,
 }
 
@@ -840,8 +871,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
         let result = result?;
 
-        debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
-        self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+        if !stack.in_cycle.get() {
+            debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
+            self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+        } else {
+            debug!(
+                "evaluate_trait_predicate_recursively: skipping cache because {:?} \
+                 is a cycle participant",
+                fresh_trait_ref,
+            );
+        }
 
         Ok(result)
     }
@@ -948,6 +987,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         {
             debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref);
 
+            // If we have a stack like `A B C D E A`, where the top of
+            // the stack is the final `A`, then this will iterate over
+            // `A, E, D, C, B` -- i.e., all the participants apart
+            // from the cycle head. We mark them as participating in a
+            // cycle. This suppresses caching for those nodes. See
+            // `in_cycle` field for more details.
+            for item in stack.iter().take(rec_index + 1) {
+                debug!("evaluate_stack: marking {:?} as cycle participant", item.fresh_trait_ref);
+                item.in_cycle.set(true);
+            }
+
             // Subtle: when checking for a coinductive cycle, we do
             // not compare using the "freshened trait refs" (which
             // have erased regions) but rather the fully explicit
@@ -3690,6 +3740,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         TraitObligationStack {
             obligation,
             fresh_trait_ref,
+            in_cycle: Cell::new(false),
             previous: previous_stack,
         }
     }
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 2496419640c..fdd1a821e31 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -298,7 +298,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(
     // negated `CrateNum` (so remote definitions are visited first) and then
     // by a flattened version of the `DefIndex`.
     trait_impls.sort_unstable_by_key(|def_id| {
-        (-(def_id.krate.as_u32() as i64), def_id.index.as_array_index())
+        (-(def_id.krate.as_u32() as i64), def_id.index.index())
     });
 
     for impl_def_id in trait_impls {
@@ -319,29 +319,34 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(
                         String::new(), |ty| {
                             format!(" for type `{}`", ty)
                         }),
-                    if used_to_be_allowed.is_some() { " (E0119)" } else { "" }
+                    match used_to_be_allowed {
+                        Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)",
+                        _ => "",
+                    }
                 );
                 let impl_span = tcx.sess.source_map().def_span(
                     tcx.span_of_impl(impl_def_id).unwrap()
                 );
-                let mut err = if let Some(kind) = used_to_be_allowed {
-                    let lint = match kind {
-                        FutureCompatOverlapErrorKind::Issue43355 =>
-                            lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
-                        FutureCompatOverlapErrorKind::Issue33140 =>
-                            lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS,
-                    };
-                    tcx.struct_span_lint_hir(
-                        lint,
-                        tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
-                        impl_span,
-                        &msg)
-                } else {
-                    struct_span_err!(tcx.sess,
-                                     impl_span,
-                                     E0119,
-                                     "{}",
-                                     msg)
+                let mut err = match used_to_be_allowed {
+                    Some(FutureCompatOverlapErrorKind::Issue43355) | None =>
+                        struct_span_err!(tcx.sess,
+                                         impl_span,
+                                         E0119,
+                                         "{}",
+                                         msg),
+                    Some(kind) => {
+                        let lint = match kind {
+                            FutureCompatOverlapErrorKind::Issue43355 =>
+                                unreachable!("converted to hard error above"),
+                            FutureCompatOverlapErrorKind::Issue33140 =>
+                                lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS,
+                        };
+                        tcx.struct_span_lint_hir(
+                            lint,
+                            tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
+                            impl_span,
+                            &msg)
+                    }
                 };
 
                 match tcx.span_of_impl(overlap.with_impl) {
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 400a0f526c4..404fadbc78a 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -312,17 +312,15 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
-        use syntax::symbol::Symbol;
-
         match t.sty {
             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
                 self.types.insert(
                     bound_ty.var.as_u32(),
                     match bound_ty.kind {
                         ty::BoundTyKind::Param(name) => name,
-                        ty::BoundTyKind::Anon => Symbol::intern(
-                            &format!("^{}", bound_ty.var.as_u32())
-                        ).as_interned_str(),
+                        ty::BoundTyKind::Anon =>
+                            InternedString::intern(&format!("^{}", bound_ty.var.as_u32()),
+                        ),
                     }
                 );
             }
@@ -334,8 +332,6 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-        use syntax::symbol::Symbol;
-
         match r {
             ty::ReLateBound(index, br) if *index == self.binder_index => {
                 match br {
@@ -344,9 +340,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
                     }
 
                     ty::BoundRegion::BrAnon(var) => {
-                        self.regions.insert(Symbol::intern(
-                            &format!("'^{}", var)
-                        ).as_interned_str());
+                        self.regions.insert(InternedString::intern(&format!("'^{}", var)));
                     }
 
                     _ => (),
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 15524ca6e93..c9fee02f66b 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -74,7 +74,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::source_map::MultiSpan;
 use syntax::feature_gate;
-use syntax::symbol::{Symbol, keywords, InternedString};
+use syntax::symbol::{Symbol, keywords, InternedString, sym};
 use syntax_pos::Span;
 
 use crate::hir;
@@ -1213,7 +1213,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             }
             span_bug!(attr.span, "no arguments to `rustc_layout_scalar_valid_range` attribute");
         };
-        (get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end"))
+        (get(sym::rustc_layout_scalar_valid_range_start),
+         get(sym::rustc_layout_scalar_valid_range_end))
     }
 
     pub fn lift<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
@@ -3102,10 +3103,10 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
     };
     providers.is_panic_runtime = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        attr::contains_name(tcx.hir().krate_attrs(), "panic_runtime")
+        attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
     };
     providers.is_compiler_builtins = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        attr::contains_name(tcx.hir().krate_attrs(), "compiler_builtins")
+        attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
     };
 }
diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs
index 197d3325f51..be1d973c2cd 100644
--- a/src/librustc/ty/inhabitedness/mod.rs
+++ b/src/librustc/ty/inhabitedness/mod.rs
@@ -113,9 +113,14 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         substs: SubstsRef<'tcx>) -> DefIdForest
     {
-        DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
-            v.uninhabited_from(tcx, substs, self.adt_kind())
-        }))
+        // Non-exhaustive ADTs from other crates are always considered inhabited.
+        if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
+            DefIdForest::empty()
+        } else {
+            DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
+                v.uninhabited_from(tcx, substs, self.adt_kind())
+            }))
+        }
     }
 }
 
@@ -134,9 +139,14 @@ impl<'a, 'gcx, 'tcx> VariantDef {
             AdtKind::Enum => true,
             AdtKind::Struct => false,
         };
-        DefIdForest::union(tcx, self.fields.iter().map(|f| {
-            f.uninhabited_from(tcx, substs, is_enum)
-        }))
+        // Non-exhaustive variants from other crates are always considered inhabited.
+        if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
+            DefIdForest::empty()
+        } else {
+            DefIdForest::union(tcx, self.fields.iter().map(|f| {
+                f.uninhabited_from(tcx, substs, is_enum)
+            }))
+        }
     }
 }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index d1a8a9a34e1..6d7b0926c7a 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -19,6 +19,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                            StableHasherResult};
 
 pub use rustc_target::abi::*;
+use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi};
+use rustc_target::abi::call::{
+    ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind
+};
+
+
 
 pub trait IntegerExt {
     fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>;
@@ -2259,3 +2265,380 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx>
         }
     }
 }
+
+pub trait FnTypeExt<'tcx, C>
+where
+    C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+        + HasDataLayout
+        + HasTargetSpec
+        + HasTyCtxt<'tcx>
+        + HasParamEnv<'tcx>,
+{
+    fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self;
+    fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+    fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+    fn new_internal(
+        cx: &C,
+        sig: ty::FnSig<'tcx>,
+        extra_args: &[Ty<'tcx>],
+        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+    ) -> Self;
+    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
+}
+
+impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>>
+where
+    C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+        + HasDataLayout
+        + HasTargetSpec
+        + HasTyCtxt<'tcx>
+        + HasParamEnv<'tcx>,
+{
+    fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self {
+        let sig = instance.fn_sig(cx.tcx());
+        let sig = cx
+            .tcx()
+            .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+        call::FnType::new(cx, sig, &[])
+    }
+
+    fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+        call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty)))
+    }
+
+    fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+        FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+            let mut layout = cx.layout_of(ty);
+            // Don't pass the vtable, it's not an argument of the virtual fn.
+            // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+            // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+            if arg_idx == Some(0) {
+                let fat_pointer_ty = if layout.is_unsized() {
+                    // unsized `self` is passed as a pointer to `self`
+                    // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+                    cx.tcx().mk_mut_ptr(layout.ty)
+                } else {
+                    match layout.abi {
+                        Abi::ScalarPair(..) => (),
+                        _ => bug!("receiver type has unsupported layout: {:?}", layout),
+                    }
+
+                    // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+                    // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+                    // elsewhere in the compiler as a method on a `dyn Trait`.
+                    // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+                    // get a built-in pointer type
+                    let mut fat_pointer_layout = layout;
+                    'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+                        && !fat_pointer_layout.ty.is_region_ptr()
+                    {
+                        'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+                            let field_layout = fat_pointer_layout.field(cx, i);
+
+                            if !field_layout.is_zst() {
+                                fat_pointer_layout = field_layout;
+                                continue 'descend_newtypes;
+                            }
+                        }
+
+                        bug!(
+                            "receiver has no non-zero-sized fields {:?}",
+                            fat_pointer_layout
+                        );
+                    }
+
+                    fat_pointer_layout.ty
+                };
+
+                // we now have a type like `*mut RcBox<dyn Trait>`
+                // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+                // this is understood as a special case elsewhere in the compiler
+                let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
+                layout = cx.layout_of(unit_pointer_ty);
+                layout.ty = fat_pointer_ty;
+            }
+            ArgType::new(layout)
+        })
+    }
+
+    fn new_internal(
+        cx: &C,
+        sig: ty::FnSig<'tcx>,
+        extra_args: &[Ty<'tcx>],
+        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+    ) -> Self {
+        debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
+
+        use rustc_target::spec::abi::Abi::*;
+        let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
+            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C,
+
+            // It's the ABI's job to select this, not ours.
+            System => bug!("system abi should be selected elsewhere"),
+
+            Stdcall => Conv::X86Stdcall,
+            Fastcall => Conv::X86Fastcall,
+            Vectorcall => Conv::X86VectorCall,
+            Thiscall => Conv::X86ThisCall,
+            C => Conv::C,
+            Unadjusted => Conv::C,
+            Win64 => Conv::X86_64Win64,
+            SysV64 => Conv::X86_64SysV,
+            Aapcs => Conv::ArmAapcs,
+            PtxKernel => Conv::PtxKernel,
+            Msp430Interrupt => Conv::Msp430Intr,
+            X86Interrupt => Conv::X86Intr,
+            AmdGpuKernel => Conv::AmdGpuKernel,
+
+            // These API constants ought to be more specific...
+            Cdecl => Conv::C,
+        };
+
+        let mut inputs = sig.inputs();
+        let extra_args = if sig.abi == RustCall {
+            assert!(!sig.c_variadic && extra_args.is_empty());
+
+            match sig.inputs().last().unwrap().sty {
+                ty::Tuple(tupled_arguments) => {
+                    inputs = &sig.inputs()[0..sig.inputs().len() - 1];
+                    tupled_arguments.iter().map(|k| k.expect_ty()).collect()
+                }
+                _ => {
+                    bug!(
+                        "argument to function with \"rust-call\" ABI \
+                         is not a tuple"
+                    );
+                }
+            }
+        } else {
+            assert!(sig.c_variadic || extra_args.is_empty());
+            extra_args.to_vec()
+        };
+
+        let target = &cx.tcx().sess.target.target;
+        let win_x64_gnu =
+            target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
+        let linux_s390x =
+            target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu";
+        let linux_sparc64 =
+            target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu";
+        let rust_abi = match sig.abi {
+            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
+            _ => false,
+        };
+
+        // Handle safe Rust thin and fat pointers.
+        let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
+                                      scalar: &Scalar,
+                                      layout: TyLayout<'tcx>,
+                                      offset: Size,
+                                      is_return: bool| {
+            // Booleans are always an i1 that needs to be zero-extended.
+            if scalar.is_bool() {
+                attrs.set(ArgAttribute::ZExt);
+                return;
+            }
+
+            // Only pointer types handled below.
+            if scalar.value != Pointer {
+                return;
+            }
+
+            if scalar.valid_range.start() < scalar.valid_range.end() {
+                if *scalar.valid_range.start() > 0 {
+                    attrs.set(ArgAttribute::NonNull);
+                }
+            }
+
+            if let Some(pointee) = layout.pointee_info_at(cx, offset) {
+                if let Some(kind) = pointee.safe {
+                    attrs.pointee_size = pointee.size;
+                    attrs.pointee_align = Some(pointee.align);
+
+                    // `Box` pointer parameters never alias because ownership is transferred
+                    // `&mut` pointer parameters never alias other parameters,
+                    // or mutable global data
+                    //
+                    // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+                    // and can be marked as both `readonly` and `noalias`, as
+                    // LLVM's definition of `noalias` is based solely on memory
+                    // dependencies rather than pointer equality
+                    let no_alias = match kind {
+                        PointerKind::Shared => false,
+                        PointerKind::UniqueOwned => true,
+                        PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return,
+                    };
+                    if no_alias {
+                        attrs.set(ArgAttribute::NoAlias);
+                    }
+
+                    if kind == PointerKind::Frozen && !is_return {
+                        attrs.set(ArgAttribute::ReadOnly);
+                    }
+                }
+            }
+        };
+
+        // Store the index of the last argument. This is useful for working with
+        // C-compatible variadic arguments.
+        let last_arg_idx = if sig.inputs().is_empty() {
+            None
+        } else {
+            Some(sig.inputs().len() - 1)
+        };
+
+        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+            let is_return = arg_idx.is_none();
+            let mut arg = mk_arg_type(ty, arg_idx);
+            if arg.layout.is_zst() {
+                // For some forsaken reason, x86_64-pc-windows-gnu
+                // doesn't ignore zero-sized struct arguments.
+                // The same is true for s390x-unknown-linux-gnu
+                // and sparc64-unknown-linux-gnu.
+                if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
+                    arg.mode = PassMode::Ignore(IgnoreMode::Zst);
+                }
+            }
+
+            // If this is a C-variadic function, this is not the return value,
+            // and there is one or more fixed arguments; ensure that the `VaList`
+            // is ignored as an argument.
+            if sig.c_variadic {
+                match (last_arg_idx, arg_idx) {
+                    (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
+                        let va_list_did = match cx.tcx().lang_items().va_list() {
+                            Some(did) => did,
+                            None => bug!("`va_list` lang item required for C-variadic functions"),
+                        };
+                        match ty.sty {
+                            ty::Adt(def, _) if def.did == va_list_did => {
+                                // This is the "spoofed" `VaList`. Set the arguments mode
+                                // so that it will be ignored.
+                                arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
+                            }
+                            _ => (),
+                        }
+                    }
+                    _ => {}
+                }
+            }
+
+            // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
+            if !is_return && rust_abi {
+                if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
+                    let mut a_attrs = ArgAttributes::new();
+                    let mut b_attrs = ArgAttributes::new();
+                    adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
+                    adjust_for_rust_scalar(
+                        &mut b_attrs,
+                        b,
+                        arg.layout,
+                        a.value.size(cx).align_to(b.value.align(cx).abi),
+                        false,
+                    );
+                    arg.mode = PassMode::Pair(a_attrs, b_attrs);
+                    return arg;
+                }
+            }
+
+            if let Abi::Scalar(ref scalar) = arg.layout.abi {
+                if let PassMode::Direct(ref mut attrs) = arg.mode {
+                    adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
+                }
+            }
+
+            arg
+        };
+
+        let mut fn_ty = FnType {
+            ret: arg_of(sig.output(), None),
+            args: inputs
+                .iter()
+                .cloned()
+                .chain(extra_args)
+                .enumerate()
+                .map(|(i, ty)| arg_of(ty, Some(i)))
+                .collect(),
+            c_variadic: sig.c_variadic,
+            conv,
+        };
+        fn_ty.adjust_for_abi(cx, sig.abi);
+        fn_ty
+    }
+
+    fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
+        if abi == SpecAbi::Unadjusted {
+            return;
+        }
+
+        if abi == SpecAbi::Rust
+            || abi == SpecAbi::RustCall
+            || abi == SpecAbi::RustIntrinsic
+            || abi == SpecAbi::PlatformIntrinsic
+        {
+            let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
+                if arg.is_ignore() {
+                    return;
+                }
+
+                match arg.layout.abi {
+                    Abi::Aggregate { .. } => {}
+
+                    // This is a fun case! The gist of what this is doing is
+                    // that we want callers and callees to always agree on the
+                    // ABI of how they pass SIMD arguments. If we were to *not*
+                    // make these arguments indirect then they'd be immediates
+                    // in LLVM, which means that they'd used whatever the
+                    // appropriate ABI is for the callee and the caller. That
+                    // means, for example, if the caller doesn't have AVX
+                    // enabled but the callee does, then passing an AVX argument
+                    // across this boundary would cause corrupt data to show up.
+                    //
+                    // This problem is fixed by unconditionally passing SIMD
+                    // arguments through memory between callers and callees
+                    // which should get them all to agree on ABI regardless of
+                    // target feature sets. Some more information about this
+                    // issue can be found in #44367.
+                    //
+                    // Note that the platform intrinsic ABI is exempt here as
+                    // that's how we connect up to LLVM and it's unstable
+                    // anyway, we control all calls to it in libstd.
+                    Abi::Vector { .. }
+                        if abi != SpecAbi::PlatformIntrinsic
+                            && cx.tcx().sess.target.target.options.simd_types_indirect =>
+                    {
+                        arg.make_indirect();
+                        return;
+                    }
+
+                    _ => return,
+                }
+
+                let size = arg.layout.size;
+                if arg.layout.is_unsized() || size > Pointer.size(cx) {
+                    arg.make_indirect();
+                } else {
+                    // We want to pass small aggregates as immediates, but using
+                    // a LLVM aggregate type for this leads to bad optimizations,
+                    // so we pick an appropriately sized integer type instead.
+                    arg.cast_to(Reg {
+                        kind: RegKind::Integer,
+                        size,
+                    });
+                }
+            };
+            fixup(&mut self.ret);
+            for arg in &mut self.args {
+                fixup(arg);
+            }
+            if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
+                attrs.set(ArgAttribute::StructRet);
+            }
+            return;
+        }
+
+        if let Err(msg) = self.adjust_for_cabi(cx, abi) {
+            cx.tcx().sess.fatal(&msg);
+        }
+    }
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 7b749957c3f..91e996178e7 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -47,7 +47,7 @@ use std::ops::Range;
 use syntax::ast::{self, Name, Ident, NodeId};
 use syntax::attr;
 use syntax::ext::hygiene::Mark;
-use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString};
+use syntax::symbol::{keywords, sym, Symbol, LocalInternedString, InternedString};
 use syntax_pos::Span;
 
 use smallvec;
@@ -510,7 +510,7 @@ pub struct TyS<'tcx> {
 
 // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::<TyS<'_>>() == 32);
+static_assert_size!(TyS<'_>, 32);
 
 impl<'tcx> Ord for TyS<'tcx> {
     fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
@@ -1875,11 +1875,11 @@ impl<'a, 'gcx, 'tcx> VariantDef {
         );
 
         let mut flags = VariantFlags::NO_VARIANT_FLAGS;
-        if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") {
+        if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) {
             debug!("found non-exhaustive field list for {:?}", parent_did);
             flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
         } else if let Some(variant_did) = variant_did {
-            if tcx.has_attr(variant_did, "non_exhaustive") {
+            if tcx.has_attr(variant_did, sym::non_exhaustive) {
                 debug!("found non-exhaustive field list for {:?}", variant_did);
                 flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
             }
@@ -2156,7 +2156,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
         let mut flags = AdtFlags::NO_ADT_FLAGS;
 
-        if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
+        if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
             debug!("found non-exhaustive variant list for {:?}", did);
             flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
         }
@@ -2172,7 +2172,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
 
         let attrs = tcx.get_attrs(did);
-        if attr::contains_name(&attrs, "fundamental") {
+        if attr::contains_name(&attrs, sym::fundamental) {
             flags |= AdtFlags::IS_FUNDAMENTAL;
         }
         if Some(did) == tcx.lang_items().phantom_data() {
@@ -3030,7 +3030,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Determines whether an item is annotated with an attribute.
-    pub fn has_attr(self, did: DefId, attr: &str) -> bool {
+    pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
         attr::contains_name(&self.get_attrs(did), attr)
     }
 
@@ -3405,7 +3405,7 @@ impl_stable_hash_for!(struct self::SymbolName {
 impl SymbolName {
     pub fn new(name: &str) -> SymbolName {
         SymbolName {
-            name: Symbol::intern(name).as_interned_str()
+            name: InternedString::intern(name)
         }
     }
 
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 8e98d4d85b9..91b708d7dbe 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -7,10 +7,8 @@ use crate::middle::region;
 use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
 use crate::ty::subst::{Kind, Subst, UnpackedKind};
 use crate::mir::interpret::ConstValue;
-use syntax::symbol::{keywords, Symbol};
-
 use rustc_target::spec::abi::Abi;
-use syntax::symbol::InternedString;
+use syntax::symbol::{keywords, InternedString};
 
 use std::cell::Cell;
 use std::fmt::{self, Write as _};
@@ -1285,10 +1283,10 @@ impl<F: fmt::Write> FmtPrinter<'_, 'gcx, 'tcx, F> {
     {
         fn name_by_region_index(index: usize) -> InternedString {
             match index {
-                0 => Symbol::intern("'r"),
-                1 => Symbol::intern("'s"),
-                i => Symbol::intern(&format!("'t{}", i-2)),
-            }.as_interned_str()
+                0 => InternedString::intern("'r"),
+                1 => InternedString::intern("'s"),
+                i => InternedString::intern(&format!("'t{}", i-2)),
+            }
         }
 
         // Replace any anonymous late-bound regions with named
diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs
index a4b8d365a12..2fb318a47be 100644
--- a/src/librustc/ty/query/values.rs
+++ b/src/librustc/ty/query/values.rs
@@ -1,7 +1,7 @@
 use crate::ty::{self, Ty, TyCtxt, AdtSizedConstraint};
 use crate::ty::util::NeedsDrop;
 
-use syntax::symbol::Symbol;
+use syntax::symbol::InternedString;
 
 pub(super) trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
@@ -28,7 +28,7 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
 
 impl<'tcx> Value<'tcx> for ty::SymbolName {
     fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
-        ty::SymbolName { name: Symbol::intern("<error>").as_interned_str() }
+        ty::SymbolName { name: InternedString::intern("<error>") }
     }
 }
 
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 760f3d60d05..e8f3bad4d3e 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -211,7 +211,7 @@ pub enum TyKind<'tcx> {
 
 // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::<TyKind<'_>>() == 24);
+static_assert_size!(TyKind<'_>, 24);
 
 /// A closure can be modeled as a struct that looks like:
 ///
@@ -1136,7 +1136,7 @@ impl<'a, 'gcx, 'tcx> ParamTy {
         // FIXME(#50125): Ignoring `Self` with `index != 0` might lead to weird behavior elsewhere,
         // but this should only be possible when using `-Z continue-parse-after-error` like
         // `compile-fail/issue-36638.rs`.
-        self.name == keywords::SelfUpper.name().as_str() && self.index == 0
+        self.name.as_symbol() == keywords::SelfUpper.name() && self.index == 0
     }
 }
 
@@ -2207,7 +2207,7 @@ pub struct Const<'tcx> {
 }
 
 #[cfg(target_arch = "x86_64")]
-static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 48);
+static_assert_size!(Const<'_>, 48);
 
 impl<'tcx> Const<'tcx> {
     #[inline]
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 4c8ed71a57c..926c0f8b949 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -22,6 +22,7 @@ use rustc_macros::HashStable;
 use std::{cmp, fmt};
 use syntax::ast;
 use syntax::attr::{self, SignedInt, UnsignedInt};
+use syntax::symbol::sym;
 use syntax_pos::{Span, DUMMY_SP};
 
 #[derive(Copy, Clone, Debug)]
@@ -447,7 +448,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // Such access can be in plain sight (e.g., dereferencing
         // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
         // (e.g., calling `foo.0.clone()` of `Foo<T:Clone>`).
-        if self.has_attr(dtor, "unsafe_destructor_blind_to_params") {
+        if self.has_attr(dtor, sym::unsafe_destructor_blind_to_params) {
             debug!("destructor_constraint({:?}) - blind", def.did);
             return vec![];
         }
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index 26194176350..67eaa19c080 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -11,6 +11,7 @@ use std::time::{Duration, Instant};
 
 use std::sync::mpsc::{Sender};
 use syntax_pos::{SpanData};
+use syntax::symbol::{Symbol, sym};
 use rustc_macros::HashStable;
 use crate::ty::TyCtxt;
 use crate::dep_graph::{DepNode};
@@ -18,7 +19,7 @@ use lazy_static;
 use crate::session::Session;
 
 // The name of the associated type for `Fn` return types
-pub const FN_OUTPUT_NAME: &str = "Output";
+pub const FN_OUTPUT_NAME: Symbol = sym::Output;
 
 // Useful type to use with `Result<>` indicate that an error has already
 // been reported to the user, so no need to continue checking.
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index 758a0d63886..6931b3542f7 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -19,7 +19,7 @@ use syntax::{
     mut_visit::{self, MutVisitor},
     parse::ParseSess,
     ptr::P,
-    symbol::Symbol
+    symbol::{keywords, Symbol, sym}
 };
 use syntax_pos::Span;
 
@@ -58,7 +58,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
     fn flat_map_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 1]> {
         debug!("in submodule {}", self.in_submod);
 
-        let name = if attr::contains_name(&item.attrs, "global_allocator") {
+        let name = if attr::contains_name(&item.attrs, sym::global_allocator) {
             "global_allocator"
         } else {
             return mut_visit::noop_flat_map_item(item, self);
@@ -110,13 +110,14 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
             span,
             kind: AllocatorKind::Global,
             global: item.ident,
-            core: Ident::from_str("core"),
+            core: Ident::with_empty_ctxt(sym::core),
             cx: ExtCtxt::new(self.sess, ecfg, self.resolver),
         };
 
         // We will generate a new submodule. To `use` the static from that module, we need to get
         // the `super::...` path.
-        let super_path = f.cx.path(f.span, vec![Ident::from_str("super"), f.global]);
+        let super_path =
+            f.cx.path(f.span, vec![Ident::with_empty_ctxt(keywords::Super.name()), f.global]);
 
         // Generate the items in the submodule
         let mut items = vec![
@@ -139,7 +140,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
 
         // Generate the submodule itself
         let name = f.kind.fn_name("allocator_abi");
-        let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name));
+        let allocator_abi = Ident::from_str(&name).gensym();
         let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items);
         let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap();
 
@@ -236,7 +237,7 @@ impl AllocFnFactory<'_> {
     ) -> P<Expr> {
         match *ty {
             AllocatorTy::Layout => {
-                let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
+                let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize));
                 let ty_usize = self.cx.ty_path(usize);
                 let size = ident();
                 let align = ident();
@@ -298,12 +299,12 @@ impl AllocFnFactory<'_> {
     }
 
     fn usize(&self) -> P<Ty> {
-        let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
+        let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize));
         self.cx.ty_path(usize)
     }
 
     fn ptr_u8(&self) -> P<Ty> {
-        let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
+        let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8));
         let ty_u8 = self.cx.ty_path(u8);
         self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
     }
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 70d184240fc..38d4b7e3f9d 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -11,9 +11,9 @@ use rustc_target::abi::call::ArgType;
 
 use rustc_codegen_ssa::traits::*;
 
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
-use rustc::ty::{self, Ty, Instance};
-use rustc::ty::layout::{self, PointerKind};
+use rustc_target::abi::{HasDataLayout, LayoutOf};
+use rustc::ty::{Ty};
+use rustc::ty::layout::{self};
 
 use libc::c_uint;
 
@@ -294,23 +294,7 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     }
 }
 
-pub trait FnTypeExt<'tcx> {
-    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
-    fn new(cx: &CodegenCx<'ll, 'tcx>,
-           sig: ty::FnSig<'tcx>,
-           extra_args: &[Ty<'tcx>]) -> Self;
-    fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
-                  sig: ty::FnSig<'tcx>,
-                  extra_args: &[Ty<'tcx>]) -> Self;
-    fn new_internal(
-        cx: &CodegenCx<'ll, 'tcx>,
-        sig: ty::FnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
-        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
-    ) -> Self;
-    fn adjust_for_abi(&mut self,
-                      cx: &CodegenCx<'ll, 'tcx>,
-                      abi: Abi);
+pub trait FnTypeLlvmExt<'tcx> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
     fn llvm_cconv(&self) -> llvm::CallConv;
@@ -318,356 +302,7 @@ pub trait FnTypeExt<'tcx> {
     fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
 }
 
-impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
-    fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
-        let sig = instance.fn_sig(cx.tcx);
-        let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
-        FnType::new(cx, sig, &[])
-    }
-
-    fn new(cx: &CodegenCx<'ll, 'tcx>,
-           sig: ty::FnSig<'tcx>,
-           extra_args: &[Ty<'tcx>]) -> Self {
-        FnType::new_internal(cx, sig, extra_args, |ty, _| {
-            ArgType::new(cx.layout_of(ty))
-        })
-    }
-
-    fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
-                  sig: ty::FnSig<'tcx>,
-                  extra_args: &[Ty<'tcx>]) -> Self {
-        FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
-            let mut layout = cx.layout_of(ty);
-            // Don't pass the vtable, it's not an argument of the virtual fn.
-            // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
-            // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
-            if arg_idx == Some(0) {
-                let fat_pointer_ty = if layout.is_unsized() {
-                    // unsized `self` is passed as a pointer to `self`
-                    // FIXME (mikeyhew) change this to use &own if it is ever added to the language
-                    cx.tcx.mk_mut_ptr(layout.ty)
-                } else {
-                    match layout.abi {
-                        LayoutAbi::ScalarPair(..) => (),
-                        _ => bug!("receiver type has unsupported layout: {:?}", layout)
-                    }
-
-                    // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
-                    // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
-                    // elsewhere in the compiler as a method on a `dyn Trait`.
-                    // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
-                    // get a built-in pointer type
-                    let mut fat_pointer_layout = layout;
-                    'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
-                        && !fat_pointer_layout.ty.is_region_ptr()
-                    {
-                        'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
-                            let field_layout = fat_pointer_layout.field(cx, i);
-
-                            if !field_layout.is_zst() {
-                                fat_pointer_layout = field_layout;
-                                continue 'descend_newtypes
-                            }
-                        }
-
-                        bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
-                    }
-
-                    fat_pointer_layout.ty
-                };
-
-                // we now have a type like `*mut RcBox<dyn Trait>`
-                // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
-                // this is understood as a special case elsewhere in the compiler
-                let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
-                layout = cx.layout_of(unit_pointer_ty);
-                layout.ty = fat_pointer_ty;
-            }
-            ArgType::new(layout)
-        })
-    }
-
-    fn new_internal(
-        cx: &CodegenCx<'ll, 'tcx>,
-        sig: ty::FnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
-        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
-    ) -> Self {
-        debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
-
-        use self::Abi::*;
-        let conv = match cx.sess().target.target.adjust_abi(sig.abi) {
-            RustIntrinsic | PlatformIntrinsic |
-            Rust | RustCall => Conv::C,
-
-            // It's the ABI's job to select this, not ours.
-            System => bug!("system abi should be selected elsewhere"),
-
-            Stdcall => Conv::X86Stdcall,
-            Fastcall => Conv::X86Fastcall,
-            Vectorcall => Conv::X86VectorCall,
-            Thiscall => Conv::X86ThisCall,
-            C => Conv::C,
-            Unadjusted => Conv::C,
-            Win64 => Conv::X86_64Win64,
-            SysV64 => Conv::X86_64SysV,
-            Aapcs => Conv::ArmAapcs,
-            PtxKernel => Conv::PtxKernel,
-            Msp430Interrupt => Conv::Msp430Intr,
-            X86Interrupt => Conv::X86Intr,
-            AmdGpuKernel => Conv::AmdGpuKernel,
-
-            // These API constants ought to be more specific...
-            Cdecl => Conv::C,
-        };
-
-        let mut inputs = sig.inputs();
-        let extra_args = if sig.abi == RustCall {
-            assert!(!sig.c_variadic && extra_args.is_empty());
-
-            match sig.inputs().last().unwrap().sty {
-                ty::Tuple(tupled_arguments) => {
-                    inputs = &sig.inputs()[0..sig.inputs().len() - 1];
-                    tupled_arguments.iter().map(|k| k.expect_ty()).collect()
-                }
-                _ => {
-                    bug!("argument to function with \"rust-call\" ABI \
-                          is not a tuple");
-                }
-            }
-        } else {
-            assert!(sig.c_variadic || extra_args.is_empty());
-            extra_args.to_vec()
-        };
-
-        let target = &cx.sess().target.target;
-        let win_x64_gnu = target.target_os == "windows"
-                       && target.arch == "x86_64"
-                       && target.target_env == "gnu";
-        let linux_s390x = target.target_os == "linux"
-                       && target.arch == "s390x"
-                       && target.target_env == "gnu";
-        let linux_sparc64 = target.target_os == "linux"
-                       && target.arch == "sparc64"
-                       && target.target_env == "gnu";
-        let rust_abi = match sig.abi {
-            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
-            _ => false
-        };
-
-        // Handle safe Rust thin and fat pointers.
-        let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
-                                      scalar: &layout::Scalar,
-                                      layout: TyLayout<'tcx, Ty<'tcx>>,
-                                      offset: Size,
-                                      is_return: bool| {
-            // Booleans are always an i1 that needs to be zero-extended.
-            if scalar.is_bool() {
-                attrs.set(ArgAttribute::ZExt);
-                return;
-            }
-
-            // Only pointer types handled below.
-            if scalar.value != layout::Pointer {
-                return;
-            }
-
-            if scalar.valid_range.start() < scalar.valid_range.end() {
-                if *scalar.valid_range.start() > 0 {
-                    attrs.set(ArgAttribute::NonNull);
-                }
-            }
-
-            if let Some(pointee) = layout.pointee_info_at(cx, offset) {
-                if let Some(kind) = pointee.safe {
-                    attrs.pointee_size = pointee.size;
-                    attrs.pointee_align = Some(pointee.align);
-
-                    // `Box` pointer parameters never alias because ownership is transferred
-                    // `&mut` pointer parameters never alias other parameters,
-                    // or mutable global data
-                    //
-                    // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
-                    // and can be marked as both `readonly` and `noalias`, as
-                    // LLVM's definition of `noalias` is based solely on memory
-                    // dependencies rather than pointer equality
-                    let no_alias = match kind {
-                        PointerKind::Shared => false,
-                        PointerKind::UniqueOwned => true,
-                        PointerKind::Frozen |
-                        PointerKind::UniqueBorrowed => !is_return
-                    };
-                    if no_alias {
-                        attrs.set(ArgAttribute::NoAlias);
-                    }
-
-                    if kind == PointerKind::Frozen && !is_return {
-                        attrs.set(ArgAttribute::ReadOnly);
-                    }
-                }
-            }
-        };
-
-        // Store the index of the last argument. This is useful for working with
-        // C-compatible variadic arguments.
-        let last_arg_idx = if sig.inputs().is_empty() {
-            None
-        } else {
-            Some(sig.inputs().len() - 1)
-        };
-
-        let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
-            let is_return = arg_idx.is_none();
-            let mut arg = mk_arg_type(ty, arg_idx);
-            if arg.layout.is_zst() {
-                // For some forsaken reason, x86_64-pc-windows-gnu
-                // doesn't ignore zero-sized struct arguments.
-                // The same is true for s390x-unknown-linux-gnu
-                // and sparc64-unknown-linux-gnu.
-                if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
-                    arg.mode = PassMode::Ignore(IgnoreMode::Zst);
-                }
-            }
-
-            // If this is a C-variadic function, this is not the return value,
-            // and there is one or more fixed arguments; ensure that the `VaList`
-            // is ignored as an argument.
-            if sig.c_variadic {
-                match (last_arg_idx, arg_idx) {
-                    (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
-                        let va_list_did = match cx.tcx.lang_items().va_list() {
-                            Some(did) => did,
-                            None => bug!("`va_list` lang item required for C-variadic functions"),
-                        };
-                        match ty.sty {
-                            ty::Adt(def, _) if def.did == va_list_did => {
-                                // This is the "spoofed" `VaList`. Set the arguments mode
-                                // so that it will be ignored.
-                                arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
-                            },
-                            _ => (),
-                        }
-                    }
-                    _ => {}
-                }
-            }
-
-            // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
-            if !is_return && rust_abi {
-                if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
-                    let mut a_attrs = ArgAttributes::new();
-                    let mut b_attrs = ArgAttributes::new();
-                    adjust_for_rust_scalar(&mut a_attrs,
-                                           a,
-                                           arg.layout,
-                                           Size::ZERO,
-                                           false);
-                    adjust_for_rust_scalar(&mut b_attrs,
-                                           b,
-                                           arg.layout,
-                                           a.value.size(cx).align_to(b.value.align(cx).abi),
-                                           false);
-                    arg.mode = PassMode::Pair(a_attrs, b_attrs);
-                    return arg;
-                }
-            }
-
-            if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
-                if let PassMode::Direct(ref mut attrs) = arg.mode {
-                    adjust_for_rust_scalar(attrs,
-                                           scalar,
-                                           arg.layout,
-                                           Size::ZERO,
-                                           is_return);
-                }
-            }
-
-            arg
-        };
-
-        let mut fn_ty = FnType {
-            ret: arg_of(sig.output(), None),
-            args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| {
-                arg_of(ty, Some(i))
-            }).collect(),
-            c_variadic: sig.c_variadic,
-            conv,
-        };
-        fn_ty.adjust_for_abi(cx, sig.abi);
-        fn_ty
-    }
-
-    fn adjust_for_abi(&mut self,
-                      cx: &CodegenCx<'ll, 'tcx>,
-                      abi: Abi) {
-        if abi == Abi::Unadjusted { return }
-
-        if abi == Abi::Rust || abi == Abi::RustCall ||
-           abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
-                if arg.is_ignore() { return; }
-
-                match arg.layout.abi {
-                    layout::Abi::Aggregate { .. } => {}
-
-                    // This is a fun case! The gist of what this is doing is
-                    // that we want callers and callees to always agree on the
-                    // ABI of how they pass SIMD arguments. If we were to *not*
-                    // make these arguments indirect then they'd be immediates
-                    // in LLVM, which means that they'd used whatever the
-                    // appropriate ABI is for the callee and the caller. That
-                    // means, for example, if the caller doesn't have AVX
-                    // enabled but the callee does, then passing an AVX argument
-                    // across this boundary would cause corrupt data to show up.
-                    //
-                    // This problem is fixed by unconditionally passing SIMD
-                    // arguments through memory between callers and callees
-                    // which should get them all to agree on ABI regardless of
-                    // target feature sets. Some more information about this
-                    // issue can be found in #44367.
-                    //
-                    // Note that the platform intrinsic ABI is exempt here as
-                    // that's how we connect up to LLVM and it's unstable
-                    // anyway, we control all calls to it in libstd.
-                    layout::Abi::Vector { .. }
-                        if abi != Abi::PlatformIntrinsic &&
-                            cx.sess().target.target.options.simd_types_indirect =>
-                    {
-                        arg.make_indirect();
-                        return
-                    }
-
-                    _ => return
-                }
-
-                let size = arg.layout.size;
-                if arg.layout.is_unsized() || size > layout::Pointer.size(cx) {
-                    arg.make_indirect();
-                } else {
-                    // We want to pass small aggregates as immediates, but using
-                    // a LLVM aggregate type for this leads to bad optimizations,
-                    // so we pick an appropriately sized integer type instead.
-                    arg.cast_to(Reg {
-                        kind: RegKind::Integer,
-                        size
-                    });
-                }
-            };
-            fixup(&mut self.ret);
-            for arg in &mut self.args {
-                fixup(arg);
-            }
-            if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
-                attrs.set(ArgAttribute::StructRet);
-            }
-            return;
-        }
-
-        if let Err(msg) = self.adjust_for_cabi(cx, abi) {
-            cx.sess().fatal(&msg);
-        }
-    }
-
+impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
         let args_capacity: usize = self.args.iter().map(|arg|
             if arg.pad.is_some() { 1 } else { 0 } +
@@ -836,22 +471,6 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     }
 }
 
-impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> {
-    fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> {
-        FnType::new(&self, sig, extra_args)
-    }
-    fn new_vtable(
-        &self,
-        sig: ty::FnSig<'tcx>,
-        extra_args: &[Ty<'tcx>]
-    ) -> FnType<'tcx, Ty<'tcx>> {
-        FnType::new_vtable(&self, sig, extra_args)
-    }
-    fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> {
-        FnType::of_instance(&self, instance)
-    }
-}
-
 impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
     fn apply_attrs_callsite(
         &mut self,
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index b15a64c966b..f26684d9ef0 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -321,12 +321,12 @@ pub fn provide(providers: &mut Providers<'_>) {
             // rustdoc needs to be able to document functions that use all the features, so
             // whitelist them all
             Lrc::new(llvm_util::all_known_features()
-                .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
+                .map(|(a, b)| (a.to_string(), b))
                 .collect())
         } else {
             Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
                 .iter()
-                .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string())))
+                .map(|&(a, b)| (a.to_string(), b))
                 .collect())
         }
     };
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index cb59cf41a3c..66ba95810a6 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -795,10 +795,10 @@ fn create_msvc_imps(
         return
     }
     // The x86 ABI seems to require that leading underscores are added to symbol
-    // names, so we need an extra underscore on 32-bit. There's also a leading
+    // names, so we need an extra underscore on x86. There's also a leading
     // '\x01' here which disables LLVM's symbol mangling (e.g., no extra
     // underscores added in front).
-    let prefix = if cgcx.target_pointer_width == "32" {
+    let prefix = if cgcx.target_arch == "x86" {
         "\x01__imp__"
     } else {
         "\x01__imp_"
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index bc2bb97a19e..48808eea304 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -18,6 +18,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::base::to_immediate;
 use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
 use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
 use std::ops::{Deref, Range};
 use std::ptr;
@@ -72,6 +73,12 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
+impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.cx.target_spec()
+    }
+}
+
 impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> {
     type Ty = Ty<'tcx>;
     type TyLayout = TyLayout<'tcx>;
diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs
index 8c83e9ef538..5f47108309f 100644
--- a/src/librustc_codegen_llvm/consts.rs
+++ b/src/librustc_codegen_llvm/consts.rs
@@ -14,6 +14,7 @@ use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint,
 use rustc::hir::Node;
 use syntax_pos::Span;
 use rustc_target::abi::HasDataLayout;
+use syntax::symbol::sym;
 use syntax_pos::symbol::LocalInternedString;
 use rustc::ty::{self, Ty};
 use rustc_codegen_ssa::traits::*;
@@ -248,7 +249,7 @@ impl CodegenCx<'ll, 'tcx> {
             debug!("get_static: sym={} attrs={:?}", sym, attrs);
 
             for attr in attrs {
-                if attr.check_name("thread_local") {
+                if attr.check_name(sym::thread_local) {
                     llvm::set_thread_local_mode(g, self.tls_model);
                 }
             }
diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs
index 91496ffbe55..04c9e93c7a5 100644
--- a/src/librustc_codegen_llvm/debuginfo/gdb.rs
+++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs
@@ -9,6 +9,7 @@ use rustc::session::config::DebugInfo;
 use rustc_codegen_ssa::traits::*;
 
 use syntax::attr;
+use syntax::symbol::sym;
 
 
 /// Inserts a side-effect free instruction sequence that makes sure that the
@@ -66,8 +67,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>)
 
 pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
     let omit_gdb_pretty_printer_section =
-        attr::contains_name(&cx.tcx.hir().krate_attrs(),
-                            "omit_gdb_pretty_printer_section");
+        attr::contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
 
     !omit_gdb_pretty_printer_section &&
     cx.sess().opts.debuginfo != DebugInfo::None &&
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 3febcb019ce..bcb14b8899e 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -13,13 +13,13 @@
 
 use crate::llvm;
 use crate::llvm::AttributePlace::Function;
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType, FnTypeLlvmExt};
 use crate::attributes;
 use crate::context::CodegenCx;
 use crate::type_::Type;
 use crate::value::Value;
 use rustc::ty::{self, PolyFnSig};
-use rustc::ty::layout::LayoutOf;
+use rustc::ty::layout::{FnTypeExt, LayoutOf};
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index ceb08f94367..9ae0e26196d 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -20,7 +20,7 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc::hir;
 use syntax::ast::{self, FloatTy};
-use syntax::symbol::Symbol;
+use syntax::symbol::LocalInternedString;
 
 use rustc_codegen_ssa::traits::*;
 
@@ -213,7 +213,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
             }
             "type_name" => {
                 let tp_ty = substs.type_at(0);
-                let ty_name = Symbol::intern(&tp_ty.to_string()).as_str();
+                let ty_name = LocalInternedString::intern(&tp_ty.to_string());
                 self.const_str_slice(ty_name)
             }
             "type_id" => {
diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs
index f1b8d532eeb..274c8965962 100644
--- a/src/librustc_codegen_llvm/llvm_util.rs
+++ b/src/librustc_codegen_llvm/llvm_util.rs
@@ -7,6 +7,7 @@ use rustc_target::spec::MergeFunctions;
 use libc::c_int;
 use std::ffi::CString;
 use syntax::feature_gate::UnstableFeatures;
+use syntax::symbol::sym;
 
 use std::str;
 use std::slice;
@@ -93,106 +94,106 @@ unsafe fn configure_llvm(sess: &Session) {
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
 
-const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("aclass", Some("arm_target_feature")),
-    ("mclass", Some("arm_target_feature")),
-    ("rclass", Some("arm_target_feature")),
-    ("dsp", Some("arm_target_feature")),
-    ("neon", Some("arm_target_feature")),
-    ("v5te", Some("arm_target_feature")),
-    ("v6", Some("arm_target_feature")),
-    ("v6k", Some("arm_target_feature")),
-    ("v6t2", Some("arm_target_feature")),
-    ("v7", Some("arm_target_feature")),
-    ("v8", Some("arm_target_feature")),
-    ("vfp2", Some("arm_target_feature")),
-    ("vfp3", Some("arm_target_feature")),
-    ("vfp4", Some("arm_target_feature")),
+const ARM_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("aclass", Some(sym::arm_target_feature)),
+    ("mclass", Some(sym::arm_target_feature)),
+    ("rclass", Some(sym::arm_target_feature)),
+    ("dsp", Some(sym::arm_target_feature)),
+    ("neon", Some(sym::arm_target_feature)),
+    ("v5te", Some(sym::arm_target_feature)),
+    ("v6", Some(sym::arm_target_feature)),
+    ("v6k", Some(sym::arm_target_feature)),
+    ("v6t2", Some(sym::arm_target_feature)),
+    ("v7", Some(sym::arm_target_feature)),
+    ("v8", Some(sym::arm_target_feature)),
+    ("vfp2", Some(sym::arm_target_feature)),
+    ("vfp3", Some(sym::arm_target_feature)),
+    ("vfp4", Some(sym::arm_target_feature)),
 ];
 
-const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("fp", Some("aarch64_target_feature")),
-    ("neon", Some("aarch64_target_feature")),
-    ("sve", Some("aarch64_target_feature")),
-    ("crc", Some("aarch64_target_feature")),
-    ("crypto", Some("aarch64_target_feature")),
-    ("ras", Some("aarch64_target_feature")),
-    ("lse", Some("aarch64_target_feature")),
-    ("rdm", Some("aarch64_target_feature")),
-    ("fp16", Some("aarch64_target_feature")),
-    ("rcpc", Some("aarch64_target_feature")),
-    ("dotprod", Some("aarch64_target_feature")),
-    ("v8.1a", Some("aarch64_target_feature")),
-    ("v8.2a", Some("aarch64_target_feature")),
-    ("v8.3a", Some("aarch64_target_feature")),
+const AARCH64_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("fp", Some(sym::aarch64_target_feature)),
+    ("neon", Some(sym::aarch64_target_feature)),
+    ("sve", Some(sym::aarch64_target_feature)),
+    ("crc", Some(sym::aarch64_target_feature)),
+    ("crypto", Some(sym::aarch64_target_feature)),
+    ("ras", Some(sym::aarch64_target_feature)),
+    ("lse", Some(sym::aarch64_target_feature)),
+    ("rdm", Some(sym::aarch64_target_feature)),
+    ("fp16", Some(sym::aarch64_target_feature)),
+    ("rcpc", Some(sym::aarch64_target_feature)),
+    ("dotprod", Some(sym::aarch64_target_feature)),
+    ("v8.1a", Some(sym::aarch64_target_feature)),
+    ("v8.2a", Some(sym::aarch64_target_feature)),
+    ("v8.3a", Some(sym::aarch64_target_feature)),
 ];
 
-const X86_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("adx", Some("adx_target_feature")),
+const X86_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("adx", Some(sym::adx_target_feature)),
     ("aes", None),
     ("avx", None),
     ("avx2", None),
-    ("avx512bw", Some("avx512_target_feature")),
-    ("avx512cd", Some("avx512_target_feature")),
-    ("avx512dq", Some("avx512_target_feature")),
-    ("avx512er", Some("avx512_target_feature")),
-    ("avx512f", Some("avx512_target_feature")),
-    ("avx512ifma", Some("avx512_target_feature")),
-    ("avx512pf", Some("avx512_target_feature")),
-    ("avx512vbmi", Some("avx512_target_feature")),
-    ("avx512vl", Some("avx512_target_feature")),
-    ("avx512vpopcntdq", Some("avx512_target_feature")),
+    ("avx512bw", Some(sym::avx512_target_feature)),
+    ("avx512cd", Some(sym::avx512_target_feature)),
+    ("avx512dq", Some(sym::avx512_target_feature)),
+    ("avx512er", Some(sym::avx512_target_feature)),
+    ("avx512f", Some(sym::avx512_target_feature)),
+    ("avx512ifma", Some(sym::avx512_target_feature)),
+    ("avx512pf", Some(sym::avx512_target_feature)),
+    ("avx512vbmi", Some(sym::avx512_target_feature)),
+    ("avx512vl", Some(sym::avx512_target_feature)),
+    ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
     ("bmi1", None),
     ("bmi2", None),
-    ("cmpxchg16b", Some("cmpxchg16b_target_feature")),
-    ("f16c", Some("f16c_target_feature")),
+    ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
+    ("f16c", Some(sym::f16c_target_feature)),
     ("fma", None),
     ("fxsr", None),
     ("lzcnt", None),
-    ("mmx", Some("mmx_target_feature")),
-    ("movbe", Some("movbe_target_feature")),
+    ("mmx", Some(sym::mmx_target_feature)),
+    ("movbe", Some(sym::movbe_target_feature)),
     ("pclmulqdq", None),
     ("popcnt", None),
     ("rdrand", None),
     ("rdseed", None),
-    ("rtm", Some("rtm_target_feature")),
+    ("rtm", Some(sym::rtm_target_feature)),
     ("sha", None),
     ("sse", None),
     ("sse2", None),
     ("sse3", None),
     ("sse4.1", None),
     ("sse4.2", None),
-    ("sse4a", Some("sse4a_target_feature")),
+    ("sse4a", Some(sym::sse4a_target_feature)),
     ("ssse3", None),
-    ("tbm", Some("tbm_target_feature")),
+    ("tbm", Some(sym::tbm_target_feature)),
     ("xsave", None),
     ("xsavec", None),
     ("xsaveopt", None),
     ("xsaves", None),
 ];
 
-const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("hvx", Some("hexagon_target_feature")),
-    ("hvx-double", Some("hexagon_target_feature")),
+const HEXAGON_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("hvx", Some(sym::hexagon_target_feature)),
+    ("hvx-double", Some(sym::hexagon_target_feature)),
 ];
 
-const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("altivec", Some("powerpc_target_feature")),
-    ("power8-altivec", Some("powerpc_target_feature")),
-    ("power9-altivec", Some("powerpc_target_feature")),
-    ("power8-vector", Some("powerpc_target_feature")),
-    ("power9-vector", Some("powerpc_target_feature")),
-    ("vsx", Some("powerpc_target_feature")),
+const POWERPC_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("altivec", Some(sym::powerpc_target_feature)),
+    ("power8-altivec", Some(sym::powerpc_target_feature)),
+    ("power9-altivec", Some(sym::powerpc_target_feature)),
+    ("power8-vector", Some(sym::powerpc_target_feature)),
+    ("power9-vector", Some(sym::powerpc_target_feature)),
+    ("vsx", Some(sym::powerpc_target_feature)),
 ];
 
-const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("fp64", Some("mips_target_feature")),
-    ("msa", Some("mips_target_feature")),
+const MIPS_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("fp64", Some(sym::mips_target_feature)),
+    ("msa", Some(sym::mips_target_feature)),
 ];
 
-const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
-    ("simd128", Some("wasm_target_feature")),
-    ("atomics", Some("wasm_target_feature")),
+const WASM_WHITELIST: &[(&str, Option<Symbol>)] = &[
+    ("simd128", Some(sym::wasm_target_feature)),
+    ("atomics", Some(sym::wasm_target_feature)),
 ];
 
 /// When rustdoc is running, provide a list of all known features so that all their respective
@@ -200,7 +201,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[
 ///
 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
 /// iterator!
-pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
+pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<Symbol>)> {
     ARM_WHITELIST.iter().cloned()
         .chain(AARCH64_WHITELIST.iter().cloned())
         .chain(X86_WHITELIST.iter().cloned())
@@ -247,7 +248,7 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
 }
 
 pub fn target_feature_whitelist(sess: &Session)
-    -> &'static [(&'static str, Option<&'static str>)]
+    -> &'static [(&'static str, Option<Symbol>)]
 {
     match &*sess.target.target.arch {
         "arm" => ARM_WHITELIST,
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index a5ed64a66a3..a3d3f0756a5 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::*;
 
 use crate::common;
 use crate::type_of::LayoutLlvmExt;
-use crate::abi::{LlvmType, FnTypeExt};
+use crate::abi::{LlvmType, FnTypeLlvmExt};
 use syntax::ast;
 use rustc::ty::Ty;
 use rustc::ty::layout::{self, Align, Size, TyLayout};
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index ff25ed92566..800bf505125 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -1,8 +1,8 @@
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType};
 use crate::common::*;
 use crate::type_::Type;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout};
 use rustc_target::abi::{FloatTy, TyLayoutMethods};
 use rustc_mir::monomorphize::item::DefPathBasedNames;
 use rustc_codegen_ssa::traits::*;
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 576bcc8f38e..1c793996c83 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -28,7 +28,7 @@ use rustc_target::spec::MergeFunctions;
 use syntax::attr;
 use syntax::ext::hygiene::Mark;
 use syntax_pos::MultiSpan;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::{Symbol, sym};
 use jobserver::{Client, Acquired};
 
 use std::any::Any;
@@ -248,6 +248,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub tm_factory: TargetMachineFactory<B>,
     pub msvc_imps_needed: bool,
     pub target_pointer_width: String,
+    pub target_arch: String,
     pub debuginfo: config::DebugInfo,
 
     // Number of cgus excluding the allocator/metadata modules
@@ -382,11 +383,11 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     let sess = tcx.sess;
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
-    let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, "no_builtins");
+    let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins);
     let subsystem = attr::first_attr_value_str_by_name(&tcx.hir().krate().attrs,
-                                                       "windows_subsystem");
+                                                       sym::windows_subsystem);
     let windows_subsystem = subsystem.map(|subsystem| {
-        if subsystem != "windows" && subsystem != "console" {
+        if subsystem != sym::windows && subsystem != sym::console {
             tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \
                                      `windows` and `console` are allowed",
                                     subsystem));
@@ -1103,6 +1104,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         total_cgus,
         msvc_imps_needed: msvc_imps_needed(tcx),
         target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
+        target_arch: tcx.sess.target.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
         assembler_cmd,
     };
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 8021d4b11d0..06d7b6c78f1 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -243,9 +243,8 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
             }
 
             PlaceContext::MutatingUse(MutatingUseContext::Drop) => {
-                let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir,
-                                                                           self.fx.cx.tcx());
-                let ty = self.fx.monomorphize(&ty.ty);
+                let ty = self.fx.mir.local_decls[local].ty;
+                let ty = self.fx.monomorphize(&ty);
 
                 // Only need the place if we're actually dropping it.
                 if self.fx.cx.type_needs_drop(ty) {
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index e64c847db65..c7dd019fc3e 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -1,6 +1,6 @@
 use rustc::middle::lang_items;
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
 use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
 use rustc::mir::interpret::InterpError;
 use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
@@ -15,7 +15,7 @@ use crate::traits::*;
 
 use std::borrow::Cow;
 
-use syntax::symbol::Symbol;
+use syntax::symbol::LocalInternedString;
 use syntax_pos::Pos;
 
 use super::{FunctionCx, LocalRef};
@@ -334,14 +334,14 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     ty::ParamEnv::reveal_all(),
                     &sig,
                 );
-                let fn_ty = bx.new_vtable(sig, &[]);
+                let fn_ty = FnType::new_vtable(&bx, sig, &[]);
                 let vtable = args[1];
                 args = &args[..1];
                 (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty)
             }
             _ => {
                 (bx.get_fn(drop_fn),
-                 bx.fn_type_of_instance(&drop_fn))
+                 FnType::of_instance(&bx, &drop_fn))
             }
         };
         helper.do_call(self, &mut bx, fn_ty, drop_fn, args,
@@ -401,7 +401,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         // Get the location information.
         let loc = bx.sess().source_map().lookup_char_pos(span.lo());
-        let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
+        let filename = LocalInternedString::intern(&loc.file.name.to_string());
         let line = bx.const_u32(loc.line as u32);
         let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
 
@@ -423,7 +423,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
             _ => {
                 let str = msg.description();
-                let msg_str = Symbol::intern(str).as_str();
+                let msg_str = LocalInternedString::intern(str);
                 let msg_file_line_col = bx.static_panic_msg(
                     Some(msg_str),
                     filename,
@@ -439,7 +439,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // Obtain the panic entry point.
         let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
         let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_ty = bx.fn_type_of_instance(&instance);
+        let fn_ty = FnType::of_instance(&bx, &instance);
         let llfn = bx.get_fn(instance);
 
         // Codegen the actual panic invoke/call.
@@ -518,7 +518,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let fn_ty = match def {
             Some(ty::InstanceDef::Virtual(..)) => {
-                bx.new_vtable(sig, &extra_args)
+                FnType::new_vtable(&bx, sig, &extra_args)
             }
             Some(ty::InstanceDef::DropGlue(_, None)) => {
                 // Empty drop glue; a no-op.
@@ -526,7 +526,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 helper.funclet_br(self, &mut bx, target);
                 return;
             }
-            _ => bx.new_fn_type(sig, &extra_args)
+            _ => FnType::new(&bx, sig, &extra_args)
         };
 
         // Emit a panic or a no-op for `panic_if_uninhabited`.
@@ -535,7 +535,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let layout = bx.layout_of(ty);
             if layout.abi.is_uninhabited() {
                 let loc = bx.sess().source_map().lookup_char_pos(span.lo());
-                let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
+                let filename = LocalInternedString::intern(&loc.file.name.to_string());
                 let line = bx.const_u32(loc.line as u32);
                 let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
 
@@ -543,7 +543,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     "Attempted to instantiate uninhabited type {}",
                     ty
                 );
-                let msg_str = Symbol::intern(&str).as_str();
+                let msg_str = LocalInternedString::intern(&str);
                 let msg_file_line_col = bx.static_panic_msg(
                     Some(msg_str),
                     filename,
@@ -556,7 +556,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let def_id =
                     common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_ty = bx.fn_type_of_instance(&instance);
+                let fn_ty = FnType::of_instance(&bx, &instance);
                 let llfn = bx.get_fn(instance);
 
                 // Codegen the actual panic invoke/call.
diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs
index fcf099235aa..060d7d18625 100644
--- a/src/librustc_codegen_ssa/mir/mod.rs
+++ b/src/librustc_codegen_ssa/mir/mod.rs
@@ -1,5 +1,5 @@
 use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
-use rustc::ty::layout::{TyLayout, HasTyCtxt};
+use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
 use rustc::mir::{self, Mir};
 use rustc::session::config::DebugInfo;
 use rustc_mir::monomorphize::Instance;
@@ -202,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
 ) {
     assert!(!instance.substs.needs_infer());
 
-    let fn_ty = cx.new_fn_type(sig, &[]);
+    let fn_ty = FnType::new(cx, sig, &[]);
     debug!("fn_ty: {:?}", fn_ty);
     let mut debug_context =
         cx.create_function_debug_context(instance, sig, llfn, mir);
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index 8d3e64c1aa6..586db5cfabe 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -5,6 +5,7 @@ use rustc::mir;
 use rustc::middle::lang_items::ExchangeMallocFnLangItem;
 use rustc_apfloat::{ieee, Float, Status, Round};
 use std::{u128, i128};
+use syntax::symbol::sym;
 
 use crate::base;
 use crate::MemFlags;
@@ -181,9 +182,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
                         match operand.layout.ty.sty {
                             ty::FnDef(def_id, substs) => {
-                                if bx.cx().tcx().has_attr(def_id, "rustc_args_required_const") {
-                                    bug!("reifying a fn ptr that requires \
-                                          const arguments");
+                                if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) {
+                                    bug!("reifying a fn ptr that requires const arguments");
                                 }
                                 OperandValue::Immediate(
                                     callee::resolve_and_get_fn(bx.cx(), def_id, substs))
diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/src/librustc_codegen_ssa/traits/abi.rs
index a8fd4e1d2c7..509255c37be 100644
--- a/src/librustc_codegen_ssa/traits/abi.rs
+++ b/src/librustc_codegen_ssa/traits/abi.rs
@@ -1,13 +1,7 @@
 use super::BackendTypes;
-use rustc::ty::{FnSig, Instance, Ty};
+use rustc::ty::{Ty};
 use rustc_target::abi::call::FnType;
 
-pub trait AbiMethods<'tcx> {
-    fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
-    fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
-    fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>;
-}
-
 pub trait AbiBuilderMethods<'tcx>: BackendTypes {
     fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value);
     fn get_param(&self, index: usize) -> Self::Value;
diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs
index a3f99cd869e..0c4c4547a79 100644
--- a/src/librustc_codegen_ssa/traits/builder.rs
+++ b/src/librustc_codegen_ssa/traits/builder.rs
@@ -11,6 +11,7 @@ use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 use rustc::ty::Ty;
 use rustc::ty::layout::{Align, Size, HasParamEnv};
+use rustc_target::spec::{HasTargetSpec};
 use std::ops::Range;
 use std::iter::TrustedLen;
 
@@ -30,6 +31,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
     + AsmBuilderMethods<'tcx>
     + StaticBuilderMethods<'tcx>
     + HasParamEnv<'tcx>
+    + HasTargetSpec
 
 {
     fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs
index c237cd8bd26..2bb619e79f5 100644
--- a/src/librustc_codegen_ssa/traits/mod.rs
+++ b/src/librustc_codegen_ssa/traits/mod.rs
@@ -27,7 +27,7 @@ mod statics;
 mod type_;
 mod write;
 
-pub use self::abi::{AbiBuilderMethods, AbiMethods};
+pub use self::abi::{AbiBuilderMethods};
 pub use self::asm::{AsmBuilderMethods, AsmMethods};
 pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods};
 pub use self::builder::{BuilderMethods, OverflowOp};
@@ -41,7 +41,8 @@ pub use self::type_::{
     ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
 };
 pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
-use rustc::ty::layout::{HasParamEnv};
+use rustc::ty::layout::{HasParamEnv, HasTyCtxt};
+use rustc_target::spec::{HasTargetSpec};
 
 
 use std::fmt;
@@ -56,11 +57,12 @@ pub trait CodegenMethods<'tcx>:
     + ConstMethods<'tcx>
     + StaticMethods
     + DebugInfoMethods<'tcx>
-    + AbiMethods<'tcx>
     + DeclareMethods<'tcx>
     + AsmMethods<'tcx>
     + PreDefineMethods<'tcx>
     + HasParamEnv<'tcx>
+    + HasTyCtxt<'tcx>
+    + HasTargetSpec
 {
 }
 
@@ -71,11 +73,12 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
         + ConstMethods<'tcx>
         + StaticMethods
         + DebugInfoMethods<'tcx>
-        + AbiMethods<'tcx>
         + DeclareMethods<'tcx>
         + AsmMethods<'tcx>
         + PreDefineMethods<'tcx>
         + HasParamEnv<'tcx>
+        + HasTyCtxt<'tcx>
+        + HasTargetSpec
 {
 }
 
diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs
index 437515f1e9a..b4ba90c61f6 100644
--- a/src/librustc_codegen_utils/lib.rs
+++ b/src/librustc_codegen_utils/lib.rs
@@ -23,6 +23,7 @@ extern crate rustc;
 
 use rustc::ty::TyCtxt;
 use rustc::hir::def_id::LOCAL_CRATE;
+use syntax::symbol::sym;
 
 pub mod link;
 pub mod codegen_backend;
@@ -35,7 +36,7 @@ pub mod symbol_names_test;
 /// reporting an error.
 pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_, '_, '_>) {
     if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
-        if tcx.has_attr(def_id, "rustc_error") {
+        if tcx.has_attr(def_id, sym::rustc_error) {
             tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful");
         }
     }
diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs
index f3a1b219f8a..a2ac64fa7e0 100644
--- a/src/librustc_codegen_utils/link.rs
+++ b/src/librustc_codegen_utils/link.rs
@@ -2,6 +2,7 @@ use rustc::session::config::{self, OutputFilenames, Input, OutputType};
 use rustc::session::Session;
 use std::path::{Path, PathBuf};
 use syntax::{ast, attr};
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 pub fn out_filename(sess: &Session,
@@ -49,13 +50,13 @@ pub fn find_crate_name(sess: Option<&Session>,
     // as used. After doing this, however, we still prioritize a crate name from
     // the command line over one found in the #[crate_name] attribute. If we
     // find both we ensure that they're the same later on as well.
-    let attr_crate_name = attr::find_by_name(attrs, "crate_name")
+    let attr_crate_name = attr::find_by_name(attrs, sym::crate_name)
         .and_then(|at| at.value_str().map(|s| (at, s)));
 
     if let Some(sess) = sess {
         if let Some(ref s) = sess.opts.crate_name {
             if let Some((attr, name)) = attr_crate_name {
-                if name != &**s {
+                if name.as_str() != *s {
                     let msg = format!("--crate-name and #[crate_name] are \
                                        required to match, but `{}` != `{}`",
                                       s, name);
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index d50a9a1607b..6915687ceba 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -101,7 +101,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
 use rustc_mir::monomorphize::Instance;
 
-use syntax_pos::symbol::{Symbol, InternedString};
+use syntax_pos::symbol::InternedString;
 
 use log::debug;
 
@@ -238,13 +238,13 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) ->
     if def_id.is_local() {
         if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) {
             let disambiguator = tcx.sess.local_crate_disambiguator();
-            return Symbol::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator))
-                .as_interned_str();
+            return
+                InternedString::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator));
         }
         if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) {
             let disambiguator = tcx.sess.local_crate_disambiguator();
-            return Symbol::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator))
-                .as_interned_str();
+            return
+                InternedString::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator));
         }
     }
 
@@ -322,7 +322,7 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) ->
         let _ = printer.write_str("{{vtable-shim}}");
     }
 
-    Symbol::intern(&printer.path.finish(hash)).as_interned_str()
+    InternedString::intern(&printer.path.finish(hash))
 }
 
 // Follow C++ namespace-mangling style, see
diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs
index 6a2b6f1321b..27ae0b97e59 100644
--- a/src/librustc_codegen_utils/symbol_names_test.rs
+++ b/src/librustc_codegen_utils/symbol_names_test.rs
@@ -6,11 +6,11 @@
 
 use rustc::hir;
 use rustc::ty::TyCtxt;
-
 use rustc_mir::monomorphize::Instance;
+use syntax::symbol::{Symbol, sym};
 
-const SYMBOL_NAME: &'static str = "rustc_symbol_name";
-const DEF_PATH: &'static str = "rustc_def_path";
+const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
+const DEF_PATH: Symbol = sym::rustc_def_path;
 
 pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // if the `rustc_attrs` feature is not enabled, then the
diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs
index 255c5fd7fe7..b63701dbc09 100644
--- a/src/librustc_data_structures/flock.rs
+++ b/src/librustc_data_structures/flock.rs
@@ -44,7 +44,6 @@ cfg_if! {
         }
 
         #[cfg(any(target_os = "dragonfly",
-                  target_os = "bitrig",
                   target_os = "netbsd",
                   target_os = "openbsd"))]
         mod os {
diff --git a/src/librustc_data_structures/macros.rs b/src/librustc_data_structures/macros.rs
index 029e7267c82..7fc23999284 100644
--- a/src/librustc_data_structures/macros.rs
+++ b/src/librustc_data_structures/macros.rs
@@ -10,3 +10,12 @@ macro_rules! static_assert {
         static $name: () = [()][!($test: bool) as usize];
     }
 }
+
+/// Type size assertion. The first argument is a type and the second argument is its expected size.
+#[macro_export]
+#[allow_internal_unstable(underscore_const_names)]
+macro_rules! static_assert_size {
+    ($ty:ty, $size:expr) => {
+        const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
+    }
+}
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index fa573907d4c..2b844aa24d4 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -15,7 +15,6 @@ use crate::bit_set;
 /// extended to 64 bits if needed.
 pub struct StableHasher<W> {
     state: SipHasher128,
-    bytes_hashed: u64,
     width: PhantomData<W>,
 }
 
@@ -33,7 +32,6 @@ impl<W: StableHasherResult> StableHasher<W> {
     pub fn new() -> Self {
         StableHasher {
             state: SipHasher128::new_with_keys(0, 0),
-            bytes_hashed: 0,
             width: PhantomData,
         }
     }
@@ -61,11 +59,6 @@ impl<W> StableHasher<W> {
     pub fn finalize(self) -> (u64, u64) {
         self.state.finish128()
     }
-
-    #[inline]
-    pub fn bytes_hashed(&self) -> u64 {
-        self.bytes_hashed
-    }
 }
 
 impl<W> Hasher for StableHasher<W> {
@@ -76,37 +69,31 @@ impl<W> Hasher for StableHasher<W> {
     #[inline]
     fn write(&mut self, bytes: &[u8]) {
         self.state.write(bytes);
-        self.bytes_hashed += bytes.len() as u64;
     }
 
     #[inline]
     fn write_u8(&mut self, i: u8) {
         self.state.write_u8(i);
-        self.bytes_hashed += 1;
     }
 
     #[inline]
     fn write_u16(&mut self, i: u16) {
         self.state.write_u16(i.to_le());
-        self.bytes_hashed += 2;
     }
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
         self.state.write_u32(i.to_le());
-        self.bytes_hashed += 4;
     }
 
     #[inline]
     fn write_u64(&mut self, i: u64) {
         self.state.write_u64(i.to_le());
-        self.bytes_hashed += 8;
     }
 
     #[inline]
     fn write_u128(&mut self, i: u128) {
         self.state.write_u128(i.to_le());
-        self.bytes_hashed += 16;
     }
 
     #[inline]
@@ -115,37 +102,31 @@ impl<W> Hasher for StableHasher<W> {
         // platforms. This is important for symbol hashes when cross compiling,
         // for example.
         self.state.write_u64((i as u64).to_le());
-        self.bytes_hashed += 8;
     }
 
     #[inline]
     fn write_i8(&mut self, i: i8) {
         self.state.write_i8(i);
-        self.bytes_hashed += 1;
     }
 
     #[inline]
     fn write_i16(&mut self, i: i16) {
         self.state.write_i16(i.to_le());
-        self.bytes_hashed += 2;
     }
 
     #[inline]
     fn write_i32(&mut self, i: i32) {
         self.state.write_i32(i.to_le());
-        self.bytes_hashed += 4;
     }
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
         self.state.write_i64(i.to_le());
-        self.bytes_hashed += 8;
     }
 
     #[inline]
     fn write_i128(&mut self, i: i128) {
         self.state.write_i128(i.to_le());
-        self.bytes_hashed += 16;
     }
 
     #[inline]
@@ -154,12 +135,35 @@ impl<W> Hasher for StableHasher<W> {
         // platforms. This is important for symbol hashes when cross compiling,
         // for example.
         self.state.write_i64((i as i64).to_le());
-        self.bytes_hashed += 8;
     }
 }
 
 /// Something that implements `HashStable<CTX>` can be hashed in a way that is
 /// stable across multiple compilation sessions.
+///
+/// Note that `HashStable` imposes rather more strict requirements than usual
+/// hash functions:
+///
+/// - Stable hashes are sometimes used as identifiers. Therefore they must
+///   conform to the corresponding `PartialEq` implementations:
+///
+///     - `x == y` implies `hash_stable(x) == hash_stable(y)`, and
+///     - `x != y` implies `hash_stable(x) != hash_stable(y)`.
+///
+///   That second condition is usually not required for hash functions
+///   (e.g. `Hash`). In practice this means that `hash_stable` must feed any
+///   information into the hasher that a `PartialEq` comparision takes into
+///   account. See [#49300](https://github.com/rust-lang/rust/issues/49300)
+///   for an example where violating this invariant has caused trouble in the
+///   past.
+///
+/// - `hash_stable()` must be independent of the current
+///    compilation session. E.g. they must not hash memory addresses or other
+///    things that are "randomly" assigned per compilation session.
+///
+/// - `hash_stable()` must be independent of the host architecture. The
+///   `StableHasher` takes care of endianness and `isize`/`usize` platform
+///   differences.
 pub trait HashStable<CTX> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut CTX,
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 5b42b049b5b..02f8eee67b1 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -63,6 +63,7 @@ use syntax::ast;
 use syntax::source_map::FileLoader;
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
+use syntax::symbol::sym;
 use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
 
 pub mod pretty;
@@ -669,7 +670,7 @@ impl RustcDefaultCalls {
                         // through to build scripts.
                         let value = value.as_ref().map(|s| s.as_str());
                         let value = value.as_ref().map(|s| s.as_ref());
-                        if name != "target_feature" || value != Some("crt-static") {
+                        if name != sym::target_feature || value != Some("crt-static") {
                             if !allow_unstable_cfg && gated_cfg.is_some() {
                                 return None
                             }
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index fc8bf0baa99..812321ff5e6 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -648,7 +648,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
     // have to be user friendly.
     let name = format!(
         "hir_id_{}_{}",
-        hir_id.owner.as_array_index(),
+        hir_id.owner.index(),
         hir_id.local_id.index(),
     );
     let lcfg = LabelledCFG {
@@ -805,8 +805,7 @@ pub fn print_after_hir_lowering<'tcx>(
                                             src_name,
                                             &mut rdr,
                                             box out,
-                                            annotation.pp_ann(),
-                                            true)
+                                            annotation.pp_ann())
                 })
             }
 
@@ -829,8 +828,7 @@ pub fn print_after_hir_lowering<'tcx>(
                                                                          src_name,
                                                                          &mut rdr,
                                                                          box out,
-                                                                         annotation.pp_ann(),
-                                                                         true);
+                                                                         annotation.pp_ann());
                     for node_id in uii.all_matching_node_ids(hir_map) {
                         let node = hir_map.get(node_id);
                         pp_state.print_node(node)?;
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index f74dcd6070c..31f697a724a 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -100,6 +100,18 @@ impl<'a> DiagnosticBuilder<'a> {
         self.cancel();
     }
 
+    /// Emit the diagnostic unless `delay` is true,
+    /// in which case the emission will be delayed as a bug.
+    ///
+    /// See `emit` and `delay_as_bug` for details.
+    pub fn emit_unless(&mut self, delay: bool) {
+        if delay {
+            self.delay_as_bug()
+        } else {
+            self.emit()
+        }
+    }
+
     /// Buffers the diagnostic for later emission, unless handler
     /// has disabled such buffering.
     pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
index 2c83501c86f..04dad9c5355 100644
--- a/src/librustc_incremental/assert_module_sources.rs
+++ b/src/librustc_incremental/assert_module_sources.rs
@@ -27,12 +27,13 @@ use rustc::mir::mono::CodegenUnitNameBuilder;
 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};
 
-const MODULE: &str = "module";
-const CFG: &str = "cfg";
-const KIND: &str = "kind";
+const MODULE: Symbol = sym::module;
+const CFG: Symbol = sym::cfg;
+const KIND: Symbol = sym::kind;
 
 pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.dep_graph.with_ignore(|| {
@@ -146,7 +147,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
                                                         comp_kind);
     }
 
-    fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name {
+    fn field(&self, attr: &ast::Attribute, name: Symbol) -> ast::Name {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
             if item.check_name(name) {
                 if let Some(value) = item.value_str() {
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 6f5b411946c..f404a4f82e6 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -23,14 +23,15 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::intravisit;
 use rustc::ich::{ATTR_DIRTY, ATTR_CLEAN};
-use syntax::ast::{self, Attribute, NestedMetaItem};
+use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashSet;
+use syntax::ast::{self, Attribute, NestedMetaItem};
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
-use rustc::ty::TyCtxt;
 
-const EXCEPT: &str = "except";
-const LABEL: &str = "label";
-const CFG: &str = "cfg";
+const EXCEPT: Symbol = sym::except;
+const LABEL: Symbol = sym::label;
+const CFG: Symbol = sym::cfg;
 
 // Base and Extra labels to build up the labels
 
@@ -591,7 +592,7 @@ fn expect_associated_value(tcx: TyCtxt<'_, '_, '_>, item: &NestedMetaItem) -> as
 // nodes.
 pub struct FindAllAttrs<'a, 'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    attr_names: Vec<&'static str>,
+    attr_names: Vec<Symbol>,
     found_attrs: Vec<&'tcx Attribute>,
 }
 
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 54b3e734205..c5ac8860ccd 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -230,7 +230,7 @@ impl BoxedResolver {
 
 pub struct PluginInfo {
     syntax_exts: Vec<NamedSyntaxExtension>,
-    attributes: Vec<(String, AttributeType)>,
+    attributes: Vec<(Symbol, AttributeType)>,
 }
 
 pub fn register_plugins<'a>(
diff --git a/src/librustc_interface/proc_macro_decls.rs b/src/librustc_interface/proc_macro_decls.rs
index 8ed03efd1a7..e9f2f0410d4 100644
--- a/src/librustc_interface/proc_macro_decls.rs
+++ b/src/librustc_interface/proc_macro_decls.rs
@@ -4,6 +4,7 @@ use rustc::hir;
 use rustc::ty::TyCtxt;
 use rustc::ty::query::Providers;
 use syntax::attr;
+use syntax::symbol::sym;
 
 pub fn find<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> Option<DefId> {
     tcx.proc_macro_decls_static(LOCAL_CRATE)
@@ -27,7 +28,7 @@ struct Finder {
 
 impl<'v> ItemLikeVisitor<'v> for Finder {
     fn visit_item(&mut self, item: &hir::Item) {
-        if attr::contains_name(&item.attrs, "rustc_proc_macro_decls") {
+        if attr::contains_name(&item.attrs, sym::rustc_proc_macro_decls) {
             self.decls = Some(item.hir_id);
         }
     }
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 17523aedffb..d2d0d191807 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -35,7 +35,7 @@ use syntax::mut_visit::{*, MutVisitor, visit_clobber};
 use syntax::ast::BlockCheckMode;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::source_map::{FileLoader, RealFileLoader, SourceMap};
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::{self, ast, attr};
 #[cfg(not(parallel_compiler))]
 use std::{thread, panic};
@@ -495,24 +495,24 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
     let attr_types: Vec<config::CrateType> = attrs
         .iter()
         .filter_map(|a| {
-            if a.check_name("crate_type") {
+            if a.check_name(sym::crate_type) {
                 match a.value_str() {
-                    Some(ref n) if *n == "rlib" => Some(config::CrateType::Rlib),
-                    Some(ref n) if *n == "dylib" => Some(config::CrateType::Dylib),
-                    Some(ref n) if *n == "cdylib" => Some(config::CrateType::Cdylib),
-                    Some(ref n) if *n == "lib" => Some(config::default_lib_output()),
-                    Some(ref n) if *n == "staticlib" => Some(config::CrateType::Staticlib),
-                    Some(ref n) if *n == "proc-macro" => Some(config::CrateType::ProcMacro),
-                    Some(ref n) if *n == "bin" => Some(config::CrateType::Executable),
-                    Some(ref n) => {
+                    Some(sym::rlib) => Some(config::CrateType::Rlib),
+                    Some(sym::dylib) => Some(config::CrateType::Dylib),
+                    Some(sym::cdylib) => Some(config::CrateType::Cdylib),
+                    Some(sym::lib) => Some(config::default_lib_output()),
+                    Some(sym::staticlib) => Some(config::CrateType::Staticlib),
+                    Some(sym::proc_dash_macro) => Some(config::CrateType::ProcMacro),
+                    Some(sym::bin) => Some(config::CrateType::Executable),
+                    Some(n) => {
                         let crate_types = vec![
-                            Symbol::intern("rlib"),
-                            Symbol::intern("dylib"),
-                            Symbol::intern("cdylib"),
-                            Symbol::intern("lib"),
-                            Symbol::intern("staticlib"),
-                            Symbol::intern("proc-macro"),
-                            Symbol::intern("bin")
+                            sym::rlib,
+                            sym::dylib,
+                            sym::cdylib,
+                            sym::lib,
+                            sym::staticlib,
+                            sym::proc_dash_macro,
+                            sym::bin
                         ];
 
                         if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().node {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index f7a89271ec5..af4f1b88b0f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -42,7 +42,7 @@ use syntax::edition::Edition;
 use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType};
 use syntax::feature_gate::{Stability, deprecated_attributes};
 use syntax_pos::{BytePos, Span, SyntaxContext};
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::{Symbol, keywords, sym};
 use syntax::errors::{Applicability, DiagnosticBuilder};
 use syntax::print::pprust::expr_to_string;
 use syntax::visit::FnKind;
@@ -207,7 +207,7 @@ impl UnsafeCode {
 
 impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
-        if attr.check_name("allow_internal_unsafe") {
+        if attr.check_name(sym::allow_internal_unsafe) {
             self.report_unsafe(cx, attr.span, "`allow_internal_unsafe` allows defining \
                                                macros using unsafe without triggering \
                                                the `unsafe_code` lint at their call site");
@@ -285,7 +285,7 @@ pub struct MissingDoc {
 impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
 
 fn has_doc(attr: &ast::Attribute) -> bool {
-    if !attr.check_name("doc") {
+    if !attr.check_name(sym::doc) {
         return false;
     }
 
@@ -295,7 +295,7 @@ fn has_doc(attr: &ast::Attribute) -> bool {
 
     if let Some(list) = attr.meta_item_list() {
         for meta in list {
-            if meta.check_name("include") || meta.check_name("hidden") {
+            if meta.check_name(sym::include) || meta.check_name(sym::hidden) {
                 return true;
             }
         }
@@ -355,10 +355,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
     fn enter_lint_attrs(&mut self, _: &LateContext<'_, '_>, attrs: &[ast::Attribute]) {
         let doc_hidden = self.doc_hidden() ||
                          attrs.iter().any(|attr| {
-            attr.check_name("doc") &&
+            attr.check_name(sym::doc) &&
             match attr.meta_item_list() {
                 None => false,
-                Some(l) => attr::list_contains_name(&l, "hidden"),
+                Some(l) => attr::list_contains_name(&l, sym::hidden),
             }
         });
         self.doc_hidden_stack.push(doc_hidden);
@@ -723,7 +723,7 @@ impl UnusedDocComment {
 
             let span = sugared_span.take().unwrap_or_else(|| attr.span);
 
-            if attr.check_name("doc") {
+            if attr.check_name(sym::doc) {
                 let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment");
 
                 err.span_label(
@@ -829,7 +829,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
         match it.node {
             hir::ItemKind::Fn(.., ref generics, _) => {
-                if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, "no_mangle") {
+                if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
                     for param in &generics.params {
                         match param.kind {
                             GenericParamKind::Lifetime { .. } => {}
@@ -856,7 +856,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
                 }
             }
             hir::ItemKind::Const(..) => {
-                if attr::contains_name(&it.attrs, "no_mangle") {
+                if attr::contains_name(&it.attrs, sym::no_mangle) {
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
                     let msg = "const items should never be #[no_mangle]";
@@ -947,7 +947,7 @@ declare_lint_pass!(
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures {
     fn check_attribute(&mut self, ctx: &LateContext<'_, '_>, attr: &ast::Attribute) {
-        if attr.check_name("feature") {
+        if attr.check_name(sym::feature) {
             if let Some(items) = attr.meta_item_list() {
                 for item in items {
                     ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature");
@@ -1382,7 +1382,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems {
             return;
         }
 
-        if let Some(attr) = attr::find_by_name(&it.attrs, "rustc_test_marker") {
+        if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) {
             cx.struct_span_lint(
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 0bb9d4389dd..ba72beecc1a 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -372,11 +372,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             edition: None,
         },
         FutureIncompatibleInfo {
-            id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
-            reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
-            edition: None,
-        },
-        FutureIncompatibleInfo {
             id: LintId::of(ORDER_DEPENDENT_TRAIT_OBJECTS),
             reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>",
             edition: None,
@@ -491,6 +486,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         "replaced with a generic attribute input check");
     store.register_removed("duplicate_matcher_binding_name",
         "converted into hard error, see https://github.com/rust-lang/rust/issues/57742");
+    store.register_removed("incoherent_fundamental_impls",
+        "converted into hard error, see https://github.com/rust-lang/rust/issues/46205");
 }
 
 pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) {
diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs
index 7a003d14b2b..551eded9858 100644
--- a/src/librustc_lint/nonstandard_style.rs
+++ b/src/librustc_lint/nonstandard_style.rs
@@ -9,6 +9,7 @@ use lint::{EarlyLintPass, LintPass, LateLintPass};
 use syntax::ast;
 use syntax::attr;
 use syntax::errors::Applicability;
+use syntax::symbol::sym;
 use syntax_pos::{BytePos, symbol::Ident, Span};
 
 #[derive(PartialEq)]
@@ -253,7 +254,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
         let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
             Some(Ident::from_str(name))
         } else {
-            attr::find_by_name(&cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID), "crate_name")
+            attr::find_by_name(&cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID), sym::crate_name)
                 .and_then(|attr| attr.meta())
                 .and_then(|meta| {
                     meta.name_value_literal().and_then(|lit| {
@@ -315,7 +316,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
             }
             FnKind::ItemFn(ident, _, header, _, attrs) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
-                if header.abi != Abi::Rust && attr::contains_name(attrs, "no_mangle") {
+                if header.abi != Abi::Rust && attr::contains_name(attrs, sym::no_mangle) {
                     return;
                 }
                 self.check_snake_case(cx, "function", ident);
@@ -390,7 +391,7 @@ impl NonUpperCaseGlobals {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) {
         match it.node {
-            hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, "no_mangle") => {
+            hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, sym::no_mangle) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
             }
             hir::ItemKind::Const(..) => {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index f4ebfd79fe1..38b6e2c1979 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -62,7 +62,7 @@ impl TypeLimits {
 /// Returns `true` iff the lint was overridden.
 fn lint_overflowing_range_endpoint<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
-    lit: &ast::Lit,
+    lit: &hir::Lit,
     lit_val: u128,
     max: u128,
     expr: &'tcx hir::Expr,
@@ -132,7 +132,7 @@ fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
     }
 }
 
-fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &ast::Lit) -> Option<String> {
+fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &hir::Lit) -> Option<String> {
     let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?;
     let firstch = src.chars().next()?;
 
@@ -249,7 +249,7 @@ fn lint_int_literal<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     type_limits: &TypeLimits,
     e: &'tcx hir::Expr,
-    lit: &ast::Lit,
+    lit: &hir::Lit,
     t: ast::IntTy,
     v: u128,
 ) {
@@ -301,7 +301,7 @@ fn lint_int_literal<'a, 'tcx>(
 fn lint_uint_literal<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     e: &'tcx hir::Expr,
-    lit: &ast::Lit,
+    lit: &hir::Lit,
     t: ast::UintTy,
 ) {
     let uint_type = if let ast::UintTy::Usize = t {
@@ -363,7 +363,7 @@ fn lint_literal<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     type_limits: &TypeLimits,
     e: &'tcx hir::Expr,
-    lit: &ast::Lit,
+    lit: &hir::Lit,
 ) {
     match cx.tables.node_type(e.hir_id).sty {
         ty::Int(t) => {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 92508ad51f1..c3dfd44ad85 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -12,7 +12,7 @@ use syntax::attr;
 use syntax::errors::Applicability;
 use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use syntax::print::pprust;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax::symbol::Symbol;
 use syntax::util::parser;
 use syntax_pos::Span;
@@ -170,7 +170,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
             descr_post_path: &str,
         ) -> bool {
             for attr in cx.tcx.get_attrs(def_id).iter() {
-                if attr.check_name("must_use") {
+                if attr.check_name(sym::must_use) {
                     let msg = format!("unused {}`{}`{} that must be used",
                         descr_pre_path, cx.tcx.def_path_str(def_id), descr_post_path);
                     let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg);
@@ -243,8 +243,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
         }
 
         let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
-        for &(ref name, ty) in plugin_attributes.iter() {
-            if ty == AttributeType::Whitelisted && attr.check_name(&**name) {
+        for &(name, ty) in plugin_attributes.iter() {
+            if ty == AttributeType::Whitelisted && attr.check_name(name) {
                 debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
                 break;
             }
@@ -262,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
             // Has a plugin registered this attribute as one that must be used at
             // the crate level?
             let plugin_crate = plugin_attributes.iter()
-                .find(|&&(ref x, t)| name == x.as_str() && AttributeType::CrateLevel == t)
+                .find(|&&(x, t)| name == x && AttributeType::CrateLevel == t)
                 .is_some();
             if known_crate || plugin_crate {
                 let msg = match attr.style {
diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs
index 169c5e13718..a4c7daf088f 100644
--- a/src/librustc_macros/src/symbols.rs
+++ b/src/librustc_macros/src/symbols.rs
@@ -11,7 +11,7 @@ use quote::quote;
 #[allow(non_camel_case_types)]
 mod kw {
     syn::custom_keyword!(Keywords);
-    syn::custom_keyword!(Other);
+    syn::custom_keyword!(Symbols);
 }
 
 struct Keyword {
@@ -33,14 +33,24 @@ impl Parse for Keyword {
     }
 }
 
-struct Symbol(Ident);
+struct Symbol {
+    name: Ident,
+    value: Option<LitStr>,
+}
 
 impl Parse for Symbol {
     fn parse(input: ParseStream<'_>) -> Result<Self> {
-        let ident: Ident = input.parse()?;
+        let name = input.parse()?;
+        let value = match input.parse::<Token![:]>() {
+            Ok(_) => Some(input.parse()?),
+            Err(_) => None,
+        };
         input.parse::<Token![,]>()?;
 
-        Ok(Symbol(ident))
+        Ok(Symbol {
+            name,
+            value,
+        })
     }
 }
 
@@ -69,7 +79,7 @@ impl Parse for Input {
         braced!(content in input);
         let keywords = content.parse()?;
 
-        input.parse::<kw::Other>()?;
+        input.parse::<kw::Symbols>()?;
         let content;
         braced!(content in input);
         let symbols = content.parse()?;
@@ -116,19 +126,22 @@ pub fn symbols(input: TokenStream) -> TokenStream {
     }
 
     for symbol in &input.symbols.0 {
-        let value = &symbol.0;
-        let value_str = value.to_string();
-        check_dup(&value_str);
+        let name = &symbol.name;
+        let value = match &symbol.value {
+            Some(value) => value.value(),
+            None => name.to_string(),
+        };
+        check_dup(&value);
         prefill_stream.extend(quote! {
-            #value_str,
+            #value,
         });
         symbols_stream.extend(quote! {
-            pub const #value: Symbol = Symbol::new(#counter);
+            pub const #name: Symbol = Symbol::new(#counter);
         });
         counter += 1;
     }
 
-    TokenStream::from(quote! {
+    let tt = TokenStream::from(quote! {
         macro_rules! keywords {
             () => {
                 #keyword_stream
@@ -159,5 +172,11 @@ pub fn symbols(input: TokenStream) -> TokenStream {
                 ])
             }
         }
-    })
+    });
+
+    // To see the generated code generated, uncomment this line, recompile, and
+    // run the resulting output through `rustfmt`.
+    //eprintln!("{}", tt);
+
+    tt
 }
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index c47d7d85a37..3e00ba3c620 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -27,7 +27,7 @@ use std::{cmp, fs};
 use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::visit;
 use syntax::{span_err, span_fatal};
 use syntax_pos::{Span, DUMMY_SP};
@@ -95,7 +95,7 @@ enum LoadError<'a> {
 impl<'a> LoadError<'a> {
     fn report(self) -> ! {
         match self {
-            LoadError::LocatorError(mut locate_ctxt) => locate_ctxt.report_errs(),
+            LoadError::LocatorError(locate_ctxt) => locate_ctxt.report_errs(),
         }
     }
 }
@@ -365,8 +365,8 @@ impl<'a> CrateLoader<'a> {
                 span,
                 ident,
                 crate_name: name,
-                hash: hash.map(|a| &*a),
-                extra_filename: extra_filename,
+                hash,
+                extra_filename,
                 filesearch: self.sess.target_filesearch(path_kind),
                 target: &self.sess.target.target,
                 triple: self.sess.opts.target_triple.clone(),
@@ -650,9 +650,8 @@ impl<'a> CrateLoader<'a> {
     /// SVH and DefIndex of the registrar function.
     pub fn find_plugin_registrar(&mut self,
                                  span: Span,
-                                 name: &str)
+                                 name: Symbol)
                                  -> Option<(PathBuf, CrateDisambiguator)> {
-        let name = Symbol::intern(name);
         let ekrate = self.read_extension_crate(span, name, name);
 
         if ekrate.target_only {
@@ -704,7 +703,7 @@ impl<'a> CrateLoader<'a> {
         let desired_strategy = self.sess.panic_strategy();
         let mut runtime_found = false;
         let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
-                                                          "needs_panic_runtime");
+                                                          sym::needs_panic_runtime);
 
         self.cstore.iter_crate_data(|cnum, data| {
             needs_panic_runtime = needs_panic_runtime ||
@@ -837,7 +836,7 @@ impl<'a> CrateLoader<'a> {
 
             let mut uses_std = false;
             self.cstore.iter_crate_data(|_, data| {
-                if data.name == "std" {
+                if data.name == sym::std {
                     uses_std = true;
                 }
             });
@@ -898,7 +897,7 @@ impl<'a> CrateLoader<'a> {
         // about through the `#![needs_allocator]` attribute and is typically
         // written down in liballoc.
         let mut needs_allocator = attr::contains_name(&krate.attrs,
-                                                      "needs_allocator");
+                                                      sym::needs_allocator);
         self.cstore.iter_crate_data(|_, data| {
             needs_allocator = needs_allocator || data.root.needs_allocator;
         });
@@ -964,7 +963,7 @@ impl<'a> CrateLoader<'a> {
         // allocator. At this point our allocator request is typically fulfilled
         // by the standard library, denoted by the `#![default_lib_allocator]`
         // attribute.
-        let mut has_default = attr::contains_name(&krate.attrs, "default_lib_allocator");
+        let mut has_default = attr::contains_name(&krate.attrs, sym::default_lib_allocator);
         self.cstore.iter_crate_data(|_, data| {
             if data.root.has_default_lib_allocator {
                 has_default = true;
@@ -987,7 +986,7 @@ impl<'a> CrateLoader<'a> {
 
             impl<'ast> visit::Visitor<'ast> for Finder {
                 fn visit_item(&mut self, i: &'ast ast::Item) {
-                    if attr::contains_name(&i.attrs, "global_allocator") {
+                    if attr::contains_name(&i.attrs, sym::global_allocator) {
                         self.0 = true;
                     }
                     visit::walk_item(self, i)
@@ -1065,7 +1064,7 @@ impl<'a> CrateLoader<'a> {
                     }
                     None => item.ident.name,
                 };
-                let dep_kind = if attr::contains_name(&item.attrs, "no_link") {
+                let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
                     DepKind::UnexportedMacrosOnly
                 } else {
                     DepKind::Explicit
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index dfeaeca323f..087256a9710 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -31,7 +31,7 @@ use syntax::source_map;
 use syntax::edition::Edition;
 use syntax::parse::source_file_to_stream;
 use syntax::parse::parser::emit_unclosed_delims;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::{Span, NO_EXPANSION, FileName};
 use rustc_data_structures::bit_set::BitSet;
 
@@ -432,7 +432,7 @@ impl cstore::CStore {
         let data = self.get_crate_data(id.krate);
         if let Some(ref proc_macros) = data.proc_macros {
             return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
-        } else if data.name == "proc_macro" && data.item_name(id.index) == "quote" {
+        } else if data.name == sym::proc_macro && data.item_name(id.index) == "quote" {
             use syntax::ext::base::SyntaxExtension;
             use syntax_ext::proc_macro_impl::BangProcMacro;
 
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 4b9db466da8..d882fe6f27e 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -29,7 +29,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
 use syntax::attr;
 use syntax::ast::{self, Ident};
 use syntax::source_map;
-use syntax::symbol::InternedString;
+use syntax::symbol::{InternedString, sym};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::hygiene::Mark;
 use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION};
@@ -264,7 +264,7 @@ impl<'a, 'tcx> SpecializedDecoder<DefId> for DecodeContext<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedDecoder<DefIndex> for DecodeContext<'a, 'tcx> {
     #[inline]
     fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
-        Ok(DefIndex::from_raw_u32(self.read_u32()?))
+        Ok(DefIndex::from_u32(self.read_u32()?))
     }
 }
 
@@ -841,7 +841,7 @@ impl<'a, 'tcx> CrateMetadata {
                                 // for other constructors correct visibilities
                                 // were already encoded in metadata.
                                 let attrs = self.get_item_attrs(def_id.index, sess);
-                                if attr::contains_name(&attrs, "non_exhaustive") {
+                                if attr::contains_name(&attrs, sym::non_exhaustive) {
                                     let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
                                     vis = ty::Visibility::Restricted(crate_def_id);
                                 }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 0946dad5320..939aadcc9ec 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -33,7 +33,7 @@ use std::u32;
 use syntax::ast;
 use syntax::attr;
 use syntax::source_map::Spanned;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax_pos::{self, hygiene, FileName, SourceFile, Span};
 use log::{debug, trace};
 
@@ -134,7 +134,7 @@ impl<'a, 'tcx> SpecializedEncoder<DefId> for EncodeContext<'a, 'tcx> {
 impl<'a, 'tcx> SpecializedEncoder<DefIndex> for EncodeContext<'a, 'tcx> {
     #[inline]
     fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> {
-        self.emit_u32(def_index.as_raw_u32())
+        self.emit_u32(def_index.as_u32())
     }
 }
 
@@ -469,7 +469,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let attrs = tcx.hir().krate_attrs();
         let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
-        let has_default_lib_allocator = attr::contains_name(&attrs, "default_lib_allocator");
+        let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
         let has_global_allocator = *tcx.sess.has_global_allocator.get();
         let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false);
 
@@ -496,13 +496,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             } else {
                 None
             },
-            compiler_builtins: attr::contains_name(&attrs, "compiler_builtins"),
-            needs_allocator: attr::contains_name(&attrs, "needs_allocator"),
-            needs_panic_runtime: attr::contains_name(&attrs, "needs_panic_runtime"),
-            no_builtins: attr::contains_name(&attrs, "no_builtins"),
-            panic_runtime: attr::contains_name(&attrs, "panic_runtime"),
-            profiler_runtime: attr::contains_name(&attrs, "profiler_runtime"),
-            sanitizer_runtime: attr::contains_name(&attrs, "sanitizer_runtime"),
+            compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
+            needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
+            needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
+            no_builtins: attr::contains_name(&attrs, sym::no_builtins),
+            panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
+            profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
+            sanitizer_runtime: attr::contains_name(&attrs, sym::sanitizer_runtime),
 
             crate_deps,
             dylib_dependency_formats,
diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs
index 4c1e39cd0a9..934e871559c 100644
--- a/src/librustc_metadata/index.rs
+++ b/src/librustc_metadata/index.rs
@@ -93,7 +93,7 @@ impl Index {
     pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'_>>) {
         assert!(entry.position < (u32::MAX as usize));
         let position = entry.position as u32;
-        let array_index = item.as_array_index();
+        let array_index = item.index();
 
         let positions = &mut self.positions;
         assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX,
@@ -126,7 +126,7 @@ impl<'tcx> LazySeq<Index> {
                def_index,
                self.len);
 
-        let position = u32::read_from_bytes_at(bytes, 1 + def_index.as_array_index());
+        let position = u32::read_from_bytes_at(bytes, 1 + def_index.index());
         if position == u32::MAX {
             debug!("Index::lookup: position=u32::MAX");
             None
diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs
index 6741b5235db..f4682465a65 100644
--- a/src/librustc_metadata/link_args.rs
+++ b/src/librustc_metadata/link_args.rs
@@ -2,6 +2,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
 use rustc::ty::TyCtxt;
 use rustc_target::spec::abi::Abi;
+use syntax::symbol::sym;
 
 pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<String> {
     let mut collector = Collector {
@@ -10,7 +11,7 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<String> {
     tcx.hir().krate().visit_all_item_likes(&mut collector);
 
     for attr in tcx.hir().krate().attrs.iter() {
-        if attr.path == "link_args" {
+        if attr.path == sym::link_args {
             if let Some(linkarg) = attr.value_str() {
                 collector.add_link_args(&linkarg.as_str());
             }
@@ -37,7 +38,7 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector {
         }
 
         // First, add all of the custom #[link_args] attributes
-        for m in it.attrs.iter().filter(|a| a.check_name("link_args")) {
+        for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) {
             if let Some(linkarg) = m.value_str() {
                 self.add_link_args(&linkarg.as_str());
             }
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index 116042c53fb..3832c8ee227 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -225,7 +225,7 @@ use rustc::session::search_paths::PathKind;
 use rustc::util::nodemap::FxHashMap;
 
 use errors::DiagnosticBuilder;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::struct_span_err;
 use syntax_pos::Span;
 use rustc_target::spec::{Target, TargetTriple};
@@ -321,7 +321,7 @@ impl<'a> Context<'a> {
         }
     }
 
-    pub fn report_errs(&mut self) -> ! {
+    pub fn report_errs(self) -> ! {
         let add = match self.root {
             &None => String::new(),
             &Some(ref r) => format!(" which `{}` depends on", r.ident),
@@ -408,7 +408,7 @@ impl<'a> Context<'a> {
                                            self.ident,
                                            add);
 
-            if (self.ident == "std" || self.ident == "core")
+            if (self.ident == sym::std || self.ident == sym::core)
                 && self.triple != TargetTriple::from_triple(config::host_triple()) {
                 err.note(&format!("the `{}` target may not be installed", self.triple));
             }
@@ -901,8 +901,7 @@ fn get_metadata_section_imp(target: &Target,
             let mut inflated = Vec::new();
             match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
                 Ok(_) => {
-                    let buf = unsafe { OwningRef::new_assert_stable_address(inflated) };
-                    rustc_erase_owner!(buf.map_owner_box())
+                    rustc_erase_owner!(OwningRef::new(inflated).map_owner_box())
                 }
                 Err(_) => {
                     return Err(format!("failed to decompress metadata: {}", filename.display()));
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index e0665127c0f..fee08f42154 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -8,7 +8,7 @@ use rustc_target::spec::abi::Abi;
 use syntax::attr;
 use syntax::source_map::Span;
 use syntax::feature_gate::{self, GateIssue};
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::{span_err, struct_span_err};
 
 pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<NativeLibrary> {
@@ -47,7 +47,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
         }
 
         // Process all of the #[link(..)]-style arguments
-        for m in it.attrs.iter().filter(|a| a.check_name("link")) {
+        for m in it.attrs.iter().filter(|a| a.check_name(sym::link)) {
             let items = match m.meta_item_list() {
                 Some(item) => item,
                 None => continue,
@@ -62,7 +62,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
             let mut kind_specified = false;
 
             for item in items.iter() {
-                if item.check_name("kind") {
+                if item.check_name(sym::kind) {
                     kind_specified = true;
                     let kind = match item.value_str() {
                         Some(name) => name,
@@ -81,9 +81,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
                             cstore::NativeUnknown
                         }
                     };
-                } else if item.check_name("name") {
+                } else if item.check_name(sym::name) {
                     lib.name = item.value_str();
-                } else if item.check_name("cfg") {
+                } else if item.check_name(sym::cfg) {
                     let cfg = match item.meta_item_list() {
                         Some(list) => list,
                         None => continue, // skip like historical compilers
@@ -98,7 +98,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
                     } else {
                         self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
                     }
-                } else if item.check_name("wasm_import_module") {
+                } else if item.check_name(sym::wasm_import_module) {
                     match item.value_str() {
                         Some(s) => lib.wasm_import_module = Some(s),
                         None => {
@@ -156,7 +156,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
         }
         if lib.cfg.is_some() && !self.tcx.features().link_cfg {
             feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           "link_cfg",
+                                           sym::link_cfg,
                                            span.unwrap(),
                                            GateIssue::Language,
                                            "is feature gated");
@@ -164,7 +164,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
         if lib.kind == cstore::NativeStaticNobundle &&
            !self.tcx.features().static_nobundle {
             feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           "static_nobundle",
+                                           sym::static_nobundle,
                                            span.unwrap_or_else(|| syntax_pos::DUMMY_SP),
                                            GateIssue::Language,
                                            "kind=\"static-nobundle\" is feature gated");
@@ -181,7 +181,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
                 let any_duplicate = self.libs
                     .iter()
                     .filter_map(|lib| lib.name.as_ref())
-                    .any(|n| n == name);
+                    .any(|n| n.as_str() == *name);
                 if new_name.is_empty() {
                     self.tcx.sess.err(
                         &format!("an empty renaming target was specified for library `{}`",name));
@@ -212,7 +212,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
             // can move them to the end of the list below.
             let mut existing = self.libs.drain_filter(|lib| {
                 if let Some(lib_name) = lib.name {
-                    if lib_name == name as &str {
+                    if lib_name.as_str() == *name {
                         if let Some(k) = kind {
                             lib.kind = k;
                         }
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 8aa6456ebe7..1a1000f0bb4 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::Idx;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use syntax_pos::Span;
 use syntax::source_map::CompilerDesugaringKind;
+use syntax::symbol::sym;
 
 use super::borrow_set::BorrowData;
 use super::{MirBorrowckCtxt};
@@ -825,18 +826,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
         let borrow_span = borrow_spans.var_or_use();
         if let BorrowExplanation::MustBeValidFor {
-            category: ConstraintCategory::Return,
+            category,
             span,
             ref opt_place_desc,
             from_closure: false,
             ..
         } = explanation {
-            return self.report_cannot_return_reference_to_local(
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
                 borrow,
                 borrow_span,
                 span,
+                category,
                 opt_place_desc.as_ref(),
-            );
+            ) {
+                return diag;
+            }
         }
 
         let mut err = self.infcx.tcx.path_does_not_live_long_enough(
@@ -1014,17 +1018,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         );
 
         if let BorrowExplanation::MustBeValidFor {
-            category: ConstraintCategory::Return,
+            category,
             span,
             from_closure: false,
             ..
         } = explanation {
-            return self.report_cannot_return_reference_to_local(
+            if let Some(diag) = self.try_report_cannot_return_reference_to_local(
                 borrow,
                 proper_span,
                 span,
+                category,
                 None,
-            );
+            ) {
+                return diag;
+            }
         }
 
         let tcx = self.infcx.tcx;
@@ -1063,15 +1070,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         err
     }
 
-    fn report_cannot_return_reference_to_local(
+    fn try_report_cannot_return_reference_to_local(
         &self,
         borrow: &BorrowData<'tcx>,
         borrow_span: Span,
         return_span: Span,
+        category: ConstraintCategory,
         opt_place_desc: Option<&String>,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> Option<DiagnosticBuilder<'cx>> {
         let tcx = self.infcx.tcx;
 
+        let return_kind = match category {
+            ConstraintCategory::Return => "return",
+            ConstraintCategory::Yield => "yield",
+            _ => return None,
+        };
+
         // FIXME use a better heuristic than Spans
         let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span {
             "reference to"
@@ -1109,7 +1123,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             let local = if let Place::Base(PlaceBase::Local(local)) = *root_place {
                 local
             } else {
-                bug!("report_cannot_return_reference_to_local: not a local")
+                bug!("try_report_cannot_return_reference_to_local: not a local")
             };
             match self.mir.local_kind(local) {
                 LocalKind::ReturnPointer | LocalKind::Temp => {
@@ -1130,6 +1144,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
         let mut err = tcx.cannot_return_reference_to_local(
             return_span,
+            return_kind,
             reference_desc,
             &place_desc,
             Origin::Mir,
@@ -1139,7 +1154,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             err.span_label(borrow_span, note);
         }
 
-        err
+        Some(err)
     }
 
     fn report_escaping_closure_capture(
@@ -1839,7 +1854,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })
         ) = place {
             let attrs = self.infcx.tcx.get_attrs(*def_id);
-            let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local"));
+            let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local));
 
             debug!(
                 "is_place_thread_local: attrs={:?} is_thread_local={:?}",
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index c64d4b4a531..35efc6195be 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -310,9 +310,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                             opt_place_desc,
                         }
                     } else {
+                        debug!("explain_why_borrow_contains_point: \
+                                Could not generate a region name");
                         BorrowExplanation::Unexplained
                     }
                 } else {
+                    debug!("explain_why_borrow_contains_point: \
+                            Could not generate an error region vid");
                     BorrowExplanation::Unexplained
                 }
             }
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index ad43c8ef66f..fa490c108c8 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -20,6 +20,7 @@ use std::io;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::str::FromStr;
+use syntax::symbol::sym;
 
 use self::mir_util::PassWhere;
 use polonius_engine::{Algorithm, Output};
@@ -280,7 +281,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>(
 ) {
     let tcx = infcx.tcx;
     let base_def_id = tcx.closure_base_def_id(mir_def_id);
-    if !tcx.has_attr(base_def_id, "rustc_regions") {
+    if !tcx.has_attr(base_def_id, sym::rustc_regions) {
         return;
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index 4e197867bfb..4d8acd241ac 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -12,7 +12,6 @@ use rustc::ty::subst::{SubstsRef, UnpackedKind};
 use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
 use rustc::ty::print::RegionHighlightMode;
 use rustc_errors::DiagnosticBuilder;
-use syntax::ast::Name;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 use syntax_pos::symbol::InternedString;
@@ -34,6 +33,7 @@ crate enum RegionNameSource {
     MatchedAdtAndSegment(Span),
     AnonRegionFromUpvar(Span, String),
     AnonRegionFromOutput(Span, String, String),
+    AnonRegionFromYieldTy(Span, String),
 }
 
 impl RegionName {
@@ -48,7 +48,8 @@ impl RegionName {
             RegionNameSource::MatchedHirTy(..) |
             RegionNameSource::MatchedAdtAndSegment(..) |
             RegionNameSource::AnonRegionFromUpvar(..) |
-            RegionNameSource::AnonRegionFromOutput(..) => false,
+            RegionNameSource::AnonRegionFromOutput(..) |
+            RegionNameSource::AnonRegionFromYieldTy(..) => false,
         }
     }
 
@@ -58,8 +59,8 @@ impl RegionName {
     }
 
     #[allow(dead_code)]
-    crate fn name(&self) -> &InternedString {
-        &self.name
+    crate fn name(&self) -> InternedString {
+        self.name
     }
 
     crate fn highlight_region_name(
@@ -105,6 +106,12 @@ impl RegionName {
                     format!("return type{} is {}", mir_description, type_name),
                 );
             },
+            RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
+                diag.span_label(
+                    *span,
+                    format!("yield type is {}", type_name),
+                );
+            }
             RegionNameSource::Static => {},
         }
     }
@@ -170,6 +177,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 self.give_name_if_anonymous_region_appears_in_output(
                     infcx, mir, mir_def_id, fr, counter,
                 )
+            })
+            .or_else(|| {
+                self.give_name_if_anonymous_region_appears_in_yield_ty(
+                    infcx, mir, mir_def_id, fr, counter,
+                )
             });
 
         debug!("give_region_a_name: gave name {:?}", value);
@@ -193,7 +205,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         match error_region {
             ty::ReEarlyBound(ebr) => {
                 if ebr.has_name() {
-                    let span = self.get_named_span(tcx, error_region, &ebr.name);
+                    let span = self.get_named_span(tcx, error_region, ebr.name);
                     Some(RegionName {
                         name: ebr.name,
                         source: RegionNameSource::NamedEarlyBoundRegion(span)
@@ -210,7 +222,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             ty::ReFree(free_region) => match free_region.bound_region {
                 ty::BoundRegion::BrNamed(_, name) => {
-                    let span = self.get_named_span(tcx, error_region, &name);
+                    let span = self.get_named_span(tcx, error_region, name);
                     Some(RegionName {
                         name,
                         source: RegionNameSource::NamedFreeRegion(span),
@@ -293,7 +305,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         &self,
         tcx: TyCtxt<'_, '_, 'tcx>,
         error_region: &RegionKind,
-        name: &InternedString,
+        name: InternedString,
     ) -> Span {
         let scope = error_region.free_region_binding_scope(tcx);
         let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID);
@@ -676,10 +688,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}",
             return_ty
         );
-        if !infcx
-            .tcx
-            .any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr)
-        {
+        if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
             return None;
         }
 
@@ -724,12 +733,63 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         })
     }
 
+    fn give_name_if_anonymous_region_appears_in_yield_ty(
+        &self,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        mir: &Mir<'tcx>,
+        mir_def_id: DefId,
+        fr: RegionVid,
+        counter: &mut usize,
+    ) -> Option<RegionName> {
+        // Note: generators from `async fn` yield `()`, so we don't have to
+        // worry about them here.
+        let yield_ty = self.universal_regions.yield_ty?;
+        debug!(
+            "give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}",
+            yield_ty,
+        );
+
+        let tcx = infcx.tcx;
+
+        if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) {
+            return None;
+        }
+
+        let mut highlight = RegionHighlightMode::default();
+        highlight.highlighting_region_vid(fr, *counter);
+        let type_name = infcx.extract_type_name(&yield_ty, Some(highlight));
+
+        let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir");
+
+        let yield_span = match tcx.hir().get(mir_node_id) {
+            hir::Node::Expr(hir::Expr {
+                node: hir::ExprKind::Closure(_, _, _, span, _),
+                ..
+            }) => (
+                tcx.sess.source_map().end_point(*span)
+            ),
+            _ => mir.span,
+        };
+
+        debug!(
+            "give_name_if_anonymous_region_appears_in_yield_ty: \
+             type_name = {:?}, yield_span = {:?}",
+            yield_span,
+            type_name,
+        );
+
+        Some(RegionName {
+            name: self.synthesize_region_name(counter),
+            source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name),
+        })
+    }
+
     /// Creates a synthetic region named `'1`, incrementing the
     /// counter.
     fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
         let c = *counter;
         *counter += 1;
 
-        Name::intern(&format!("'{:?}", c)).as_interned_str()
+        InternedString::intern(&format!("'{:?}", c))
     }
 }
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 713e3fe0218..5f444d4ceeb 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -192,7 +192,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             | ExprKind::Pointer { .. }
             | ExprKind::Repeat { .. }
             | ExprKind::Borrow { .. }
-            | ExprKind::If { .. }
             | ExprKind::Match { .. }
             | ExprKind::Loop { .. }
             | ExprKind::Block { .. }
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index e745ee0f190..fbc4835a655 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -345,7 +345,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Literal { .. }
             | ExprKind::Block { .. }
             | ExprKind::Match { .. }
-            | ExprKind::If { .. }
             | ExprKind::NeverToAny { .. }
             | ExprKind::Use { .. }
             | ExprKind::Loop { .. }
diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs
index 4e24b6853d6..222ce6d1c96 100644
--- a/src/librustc_mir/build/expr/category.rs
+++ b/src/librustc_mir/build/expr/category.rs
@@ -45,7 +45,6 @@ impl Category {
             | ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
 
             ExprKind::LogicalOp { .. }
-            | ExprKind::If { .. }
             | ExprKind::Match { .. }
             | ExprKind::NeverToAny { .. }
             | ExprKind::Use { .. }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 30ed9cef36f..15795a64e3b 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -76,43 +76,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     end_block.unit()
                 }
             }
-            ExprKind::If {
-                condition: cond_expr,
-                then: then_expr,
-                otherwise: else_expr,
-            } => {
-                let operand = unpack!(block = this.as_local_operand(block, cond_expr));
-
-                let mut then_block = this.cfg.start_new_block();
-                let mut else_block = this.cfg.start_new_block();
-                let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
-                this.cfg.terminate(block, source_info, term);
-
-                unpack!(then_block = this.into(destination, then_block, then_expr));
-                else_block = if let Some(else_expr) = else_expr {
-                    unpack!(this.into(destination, else_block, else_expr))
-                } else {
-                    // Body of the `if` expression without an `else` clause must return `()`, thus
-                    // we implicitly generate a `else {}` if it is not specified.
-                    this.cfg
-                        .push_assign_unit(else_block, source_info, destination);
-                    else_block
-                };
-
-                let join_block = this.cfg.start_new_block();
-                this.cfg.terminate(
-                    then_block,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-                this.cfg.terminate(
-                    else_block,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-
-                join_block.unit()
-            }
             ExprKind::LogicalOp { op, lhs, rhs } => {
                 // And:
                 //
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index 83221aca6c5..a9d23a0afea 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -1,4 +1,5 @@
 use syntax::ast::{self, MetaItem};
+use syntax::symbol::{Symbol, sym};
 
 use rustc_data_structures::bit_set::{BitSet, BitSetOperator, HybridBitSet};
 use rustc_data_structures::indexed_vec::Idx;
@@ -100,9 +101,9 @@ where
     fn propagate(&mut self) { self.flow_state.propagate(); }
 }
 
-pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
+pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
     for attr in attrs {
-        if attr.check_name("rustc_mir") {
+        if attr.check_name(sym::rustc_mir) {
             let items = attr.meta_item_list();
             for item in items.iter().flat_map(|l| l.iter()) {
                 match item.meta_item() {
@@ -158,10 +159,8 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD
             return None;
         };
 
-        let print_preflow_to =
-            name_found(tcx.sess, attributes, "borrowck_graphviz_preflow");
-        let print_postflow_to =
-            name_found(tcx.sess, attributes, "borrowck_graphviz_postflow");
+        let print_preflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_preflow);
+        let print_postflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_postflow);
 
         let mut mbcx = DataflowBuilder {
             def_id,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 5e646a49e0e..50140880a36 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -601,13 +601,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
             }
         }
-        hir::ExprKind::If(ref cond, ref then, ref otherwise) => {
-            ExprKind::If {
-                condition: cond.to_ref(),
-                then: then.to_ref(),
-                otherwise: otherwise.to_ref(),
-            }
-        }
         hir::ExprKind::While(ref cond, ref body, _) => {
             ExprKind::Loop {
                 condition: Some(cond.to_ref()),
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 7aed0bace8c..e8070b21bb8 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -16,7 +16,7 @@ use rustc::ty::subst::{Kind, InternalSubsts};
 use rustc::ty::layout::VariantIdx;
 use syntax::ast;
 use syntax::attr;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use rustc::hir;
 use crate::hair::constant::{lit_to_const, LitToConstError};
 
@@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         // Some functions always have overflow checks enabled,
         // however, they may not get codegen'd, depending on
         // the settings for the crate they are codegened in.
-        let mut check_overflow = attr::contains_name(attrs, "rustc_inherit_overflow_checks");
+        let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
 
         // Respect -C overflow-checks.
         check_overflow |= tcx.sess.overflow_checks();
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 2e53bee3f3d..d4f139e103a 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -185,11 +185,6 @@ pub enum ExprKind<'tcx> {
         cast: PointerCast,
         source: ExprRef<'tcx>,
     },
-    If {
-        condition: ExprRef<'tcx>,
-        then: ExprRef<'tcx>,
-        otherwise: Option<ExprRef<'tcx>>,
-    },
     Loop {
         condition: Option<ExprRef<'tcx>>,
         body: ExprRef<'tcx>,
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index edd36abc0b8..fd4416fc2b7 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -388,6 +388,18 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
         }
     }
 
+    fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pattern<'tcx>) -> bool
+        where 'a: 'p
+    {
+        match *pattern.kind {
+            PatternKind::Variant { adt_def, variant_index, .. } => {
+                let ref variant = adt_def.variants[variant_index];
+                variant.is_field_list_non_exhaustive()
+            }
+            _ => false,
+        }
+    }
+
     fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
             ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(),
@@ -1097,10 +1109,17 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]);
 
     if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
-        debug!("is_useful - expanding constructors: {:#?}", constructors);
-        split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c|
-            is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
-        ).find(|result| result.is_useful()).unwrap_or(NotUseful)
+        let is_declared_nonexhaustive = cx.is_non_exhaustive_variant(v[0]) && !cx.is_local(pcx.ty);
+        debug!("is_useful - expanding constructors: {:#?}, is_declared_nonexhaustive: {:?}",
+               constructors, is_declared_nonexhaustive);
+
+        if is_declared_nonexhaustive {
+            Useful
+        } else {
+            split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c|
+                is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
+            ).find(|result| result.is_useful()).unwrap_or(NotUseful)
+        }
     } else {
         debug!("is_useful - expanding wildcard");
 
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 1a7266859ad..a1b2e6461e5 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -208,7 +208,11 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                                     .map(|variant| variant.ident)
                                     .collect();
                             }
-                            def.variants.is_empty()
+
+                            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
                     }
@@ -365,6 +369,7 @@ fn check_arms<'a, 'tcx>(
             match is_useful(cx, &seen, &v, LeaveOutWitness) {
                 NotUseful => {
                     match source {
+                        hir::MatchSource::IfDesugar { .. } => bug!(),
                         hir::MatchSource::IfLetDesugar { .. } => {
                             cx.tcx.lint_hir(
                                 lint::builtin::IRREFUTABLE_LET_PATTERNS,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 01b1780a205..0576bb53d8f 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -27,6 +27,7 @@ use std::cmp::Ordering;
 use std::fmt;
 use syntax::ast;
 use syntax::ptr::P;
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 #[derive(Clone, Debug)]
@@ -978,7 +979,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 self.tcx.sess.span_err(span, "cannot use unions in constant patterns");
                 PatternKind::Wild
             }
-            ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => {
+            ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => {
                 let path = self.tcx.def_path_str(adt_def.did);
                 let msg = format!(
                     "to use a constant of type `{}` in a pattern, \
@@ -990,7 +991,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 PatternKind::Wild
             }
             ty::Ref(_, ty::TyS { sty: ty::Adt(adt_def, _), .. }, _)
-            if !self.tcx.has_attr(adt_def.did, "structural_match") => {
+            if !self.tcx.has_attr(adt_def.did, sym::structural_match) => {
                 // HACK(estebank): Side-step ICE #53708, but anything other than erroring here
                 // would be wrong. Returnging `PatternKind::Wild` is not technically correct.
                 let path = self.tcx.def_path_str(adt_def.did);
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 58e474658ea..2512525b4bb 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -2,6 +2,7 @@ use rustc::ty::{self, Ty, TypeAndMut};
 use rustc::ty::layout::{self, TyLayout, Size};
 use rustc::ty::adjustment::{PointerCast};
 use syntax::ast::{FloatTy, IntTy, UintTy};
+use syntax::symbol::sym;
 
 use rustc_apfloat::ieee::{Single, Double};
 use rustc::mir::interpret::{
@@ -76,9 +77,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
                 // The src operand does not matter, just its type
                 match src.layout.ty.sty {
                     ty::FnDef(def_id, substs) => {
-                        if self.tcx.has_attr(def_id, "rustc_args_required_const") {
-                            bug!("reifying a fn ptr that requires \
-                                    const arguments");
+                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
+                            bug!("reifying a fn ptr that requires const arguments");
                         }
                         let instance: EvalResult<'tcx, _> = ty::Instance::resolve(
                             *self.tcx,
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index db827afdb94..d4c1e5416d5 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -613,7 +613,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
         trace!("{:?} is now live", local);
 
         let local_val = LocalValue::Uninitialized;
-        // StorageLive *always* kills the value that's currently stored
+        // StorageLive *always* kills the value that's currently stored.
+        // However, we do not error if the variable already is live;
+        // see <https://github.com/rust-lang/rust/issues/42371>.
         Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
     }
 
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index 999e7402afd..6b40245d39a 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -10,7 +10,7 @@ use syntax::attr::InlineAttr;
 use std::fmt::{self, Write};
 use std::iter;
 use rustc::mir::mono::Linkage;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::InternedString;
 use syntax::source_map::Span;
 pub use rustc::mir::mono::MonoItem;
 
@@ -61,7 +61,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
             MonoItem::GlobalAsm(hir_id) => {
                 let def_id = tcx.hir().local_def_id_from_hir_id(hir_id);
                 ty::SymbolName {
-                    name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_interned_str()
+                    name: InternedString::intern(&format!("global_asm_{:?}", def_id))
                 }
             }
         }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 078b347fb3f..394d1f06029 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -12,7 +12,7 @@ use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSA
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
 
-use syntax::symbol::Symbol;
+use syntax::symbol::{InternedString, sym};
 
 use std::ops::Bound;
 
@@ -167,9 +167,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     (CastTy::FnPtr, CastTy::Int(_)) => {
                         self.register_violations(&[UnsafetyViolation {
                             source_info: self.source_info,
-                            description: Symbol::intern("cast of pointer to int").as_interned_str(),
-                            details: Symbol::intern("casting pointers to integers in constants")
-                                     .as_interned_str(),
+                            description: InternedString::intern("cast of pointer to int"),
+                            details: InternedString::intern(
+                                "casting pointers to integers in constants"),
                             kind: UnsafetyViolationKind::General,
                         }], &[]);
                     },
@@ -185,9 +185,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                 if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty {
                     self.register_violations(&[UnsafetyViolation {
                         source_info: self.source_info,
-                        description: Symbol::intern("pointer operation").as_interned_str(),
-                        details: Symbol::intern("operations on pointers in constants")
-                                 .as_interned_str(),
+                        description: InternedString::intern("pointer operation"),
+                        details: InternedString::intern("operations on pointers in constants"),
                         kind: UnsafetyViolationKind::General,
                     }], &[]);
                 }
@@ -212,13 +211,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                             self.source_scope_local_data[source_info.scope].lint_root;
                         self.register_violations(&[UnsafetyViolation {
                             source_info,
-                            description: Symbol::intern("borrow of packed field").as_interned_str(),
-                            details:
-                                Symbol::intern("fields of packed structs might be misaligned: \
-                                                dereferencing a misaligned pointer or even just \
-                                                creating a misaligned reference is undefined \
-                                                behavior")
-                                    .as_interned_str(),
+                            description: InternedString::intern("borrow of packed field"),
+                            details: InternedString::intern(
+                                "fields of packed structs might be misaligned: dereferencing a \
+                                misaligned pointer or even just creating a misaligned reference \
+                                is undefined behavior"),
                             kind: UnsafetyViolationKind::BorrowPacked(lint_root)
                         }], &[]);
                     }
@@ -315,12 +312,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                         self.source_scope_local_data[source_info.scope].lint_root;
                     self.register_violations(&[UnsafetyViolation {
                         source_info,
-                        description: Symbol::intern("use of extern static").as_interned_str(),
-                        details:
-                            Symbol::intern("extern statics are not controlled by the Rust type \
-                                            system: invalid data, aliasing violations or data \
-                                            races will cause undefined behavior")
-                                .as_interned_str(),
+                        description: InternedString::intern("use of extern static"),
+                        details: InternedString::intern(
+                            "extern statics are not controlled by the Rust type system: invalid \
+                            data, aliasing violations or data races will cause undefined behavior"),
                         kind: UnsafetyViolationKind::ExternStatic(lint_root)
                     }], &[]);
                 }
@@ -340,8 +335,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
         let source_info = self.source_info;
         self.register_violations(&[UnsafetyViolation {
             source_info,
-            description: Symbol::intern(description).as_interned_str(),
-            details: Symbol::intern(details).as_interned_str(),
+            description: InternedString::intern(description),
+            details: InternedString::intern(details),
             kind,
         }], &[]);
     }
@@ -441,8 +436,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
                                 let source_info = self.source_info;
                                 self.register_violations(&[UnsafetyViolation {
                                     source_info,
-                                    description: Symbol::intern(description).as_interned_str(),
-                                    details: Symbol::intern(details).as_interned_str(),
+                                    description: InternedString::intern(description),
+                                    details: InternedString::intern(details),
                                     kind: UnsafetyViolationKind::GeneralAndConstFn,
                                 }], &[]);
                             }
@@ -612,7 +607,7 @@ fn report_unused_unsafe(tcx: TyCtxt<'_, '_, '_>,
 fn builtin_derive_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId> {
     debug!("builtin_derive_def_id({:?})", def_id);
     if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
-        if tcx.has_attr(impl_def_id, "automatically_derived") {
+        if tcx.has_attr(impl_def_id, sym::automatically_derived) {
             debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id);
             Some(impl_def_id)
         } else {
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 72af0278201..8f3dd72c4f2 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -3,15 +3,17 @@
 
 use rustc::hir::def::DefKind;
 use rustc::mir::{
-    Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local,
+    AggregateKind, Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local,
     NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind,
     TerminatorKind, Terminator,  ClearCrossCrate, SourceInfo, BinOp, ProjectionElem,
     SourceScope, SourceScopeLocalData, LocalDecl, Promoted,
 };
-use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
+use rustc::mir::visit::{
+    Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
+};
 use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult};
 use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
-use syntax::source_map::DUMMY_SP;
+use syntax_pos::{Span, DUMMY_SP};
 use rustc::ty::subst::InternalSubsts;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc::ty::layout::{
@@ -19,7 +21,7 @@ use rustc::ty::layout::{
     HasTyCtxt, TargetDataLayout, HasDataLayout,
 };
 
-use crate::interpret::{InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
+use crate::interpret::{self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
 use crate::const_eval::{
     CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
 };
@@ -497,6 +499,57 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
             },
         }
     }
+
+    fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> {
+        Operand::Constant(Box::new(
+            Constant {
+                span,
+                ty,
+                user_ty: None,
+                literal: self.tcx.mk_const(ty::Const::from_scalar(
+                    scalar,
+                    ty,
+                ))
+            }
+        ))
+    }
+
+    fn replace_with_const(&self, rval: &mut Rvalue<'tcx>, value: Const<'tcx>, span: Span) {
+        self.ecx.validate_operand(
+            value,
+            vec![],
+            None,
+            true,
+        ).expect("value should already be a valid const");
+
+        if let interpret::Operand::Immediate(im) = *value {
+            match im {
+                interpret::Immediate::Scalar(ScalarMaybeUndef::Scalar(scalar)) => {
+                    *rval = Rvalue::Use(self.operand_from_scalar(scalar, value.layout.ty, span));
+                },
+                Immediate::ScalarPair(
+                    ScalarMaybeUndef::Scalar(one),
+                    ScalarMaybeUndef::Scalar(two)
+                ) => {
+                    let ty = &value.layout.ty.sty;
+                    if let ty::Tuple(substs) = ty {
+                        *rval = Rvalue::Aggregate(
+                            Box::new(AggregateKind::Tuple),
+                            vec![
+                                self.operand_from_scalar(one, substs[0].expect_ty(), span),
+                                self.operand_from_scalar(two, substs[1].expect_ty(), span),
+                            ],
+                        );
+                    }
+                },
+                _ => { }
+            }
+        }
+    }
+
+    fn should_const_prop(&self) -> bool {
+        self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2
+    }
 }
 
 fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -560,10 +613,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
     }
 }
 
-impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
+impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
     fn visit_constant(
         &mut self,
-        constant: &Constant<'tcx>,
+        constant: &mut Constant<'tcx>,
         location: Location,
     ) {
         trace!("visit_constant: {:?}", constant);
@@ -573,11 +626,11 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
 
     fn visit_statement(
         &mut self,
-        statement: &Statement<'tcx>,
+        statement: &mut Statement<'tcx>,
         location: Location,
     ) {
         trace!("visit_statement: {:?}", statement);
-        if let StatementKind::Assign(ref place, ref rval) = statement.kind {
+        if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
             let place_ty: Ty<'tcx> = place
                 .ty(&self.local_decls, self.tcx)
                 .ty;
@@ -589,6 +642,10 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
                             trace!("storing {:?} to {:?}", value, local);
                             assert!(self.places[local].is_none());
                             self.places[local] = Some(value);
+
+                            if self.should_const_prop() {
+                                self.replace_with_const(rval, value, statement.source_info.span);
+                            }
                         }
                     }
                 }
@@ -599,79 +656,116 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
 
     fn visit_terminator(
         &mut self,
-        terminator: &Terminator<'tcx>,
+        terminator: &mut Terminator<'tcx>,
         location: Location,
     ) {
         self.super_terminator(terminator, location);
-        let source_info = terminator.source_info;;
-        if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind {
-            if let Some(value) = self.eval_operand(&cond, source_info) {
-                trace!("assertion on {:?} should be {:?}", value, expected);
-                let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
-                if expected != self.ecx.read_scalar(value).unwrap() {
-                    // poison all places this operand references so that further code
-                    // doesn't use the invalid value
-                    match cond {
-                        Operand::Move(ref place) | Operand::Copy(ref place) => {
-                            let mut place = place;
-                            while let Place::Projection(ref proj) = *place {
-                                place = &proj.base;
-                            }
-                            if let Place::Base(PlaceBase::Local(local)) = *place {
-                                self.places[local] = None;
+        let source_info = terminator.source_info;
+        match &mut terminator.kind {
+            TerminatorKind::Assert { expected, msg, ref mut cond, .. } => {
+                if let Some(value) = self.eval_operand(&cond, source_info) {
+                    trace!("assertion on {:?} should be {:?}", value, expected);
+                    let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
+                    let value_const = self.ecx.read_scalar(value).unwrap();
+                    if expected != value_const {
+                        // poison all places this operand references so that further code
+                        // doesn't use the invalid value
+                        match cond {
+                            Operand::Move(ref place) | Operand::Copy(ref place) => {
+                                let mut place = place;
+                                while let Place::Projection(ref proj) = *place {
+                                    place = &proj.base;
+                                }
+                                if let Place::Base(PlaceBase::Local(local)) = *place {
+                                    self.places[local] = None;
+                                }
+                            },
+                            Operand::Constant(_) => {}
+                        }
+                        let span = terminator.source_info.span;
+                        let hir_id = self
+                            .tcx
+                            .hir()
+                            .as_local_hir_id(self.source.def_id())
+                            .expect("some part of a failing const eval must be local");
+                        use rustc::mir::interpret::InterpError::*;
+                        let msg = match msg {
+                            Overflow(_) |
+                            OverflowNeg |
+                            DivisionByZero |
+                            RemainderByZero => msg.description().to_owned(),
+                            BoundsCheck { ref len, ref index } => {
+                                let len = self
+                                    .eval_operand(len, source_info)
+                                    .expect("len must be const");
+                                let len = match self.ecx.read_scalar(len) {
+                                    Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
+                                        bits, ..
+                                    })) => bits,
+                                    other => bug!("const len not primitive: {:?}", other),
+                                };
+                                let index = self
+                                    .eval_operand(index, source_info)
+                                    .expect("index must be const");
+                                let index = match self.ecx.read_scalar(index) {
+                                    Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
+                                        bits, ..
+                                    })) => bits,
+                                    other => bug!("const index not primitive: {:?}", other),
+                                };
+                                format!(
+                                    "index out of bounds: \
+                                    the len is {} but the index is {}",
+                                    len,
+                                    index,
+                                )
+                            },
+                            // Need proper const propagator for these
+                            _ => return,
+                        };
+                        self.tcx.lint_hir(
+                            ::rustc::lint::builtin::CONST_ERR,
+                            hir_id,
+                            span,
+                            &msg,
+                        );
+                    } else {
+                        if self.should_const_prop() {
+                            if let ScalarMaybeUndef::Scalar(scalar) = value_const {
+                                *cond = self.operand_from_scalar(
+                                    scalar,
+                                    self.tcx.types.bool,
+                                    source_info.span,
+                                );
                             }
-                        },
-                        Operand::Constant(_) => {}
+                        }
                     }
-                    let span = terminator.source_info.span;
-                    let hir_id = self
-                        .tcx
-                        .hir()
-                        .as_local_hir_id(self.source.def_id())
-                        .expect("some part of a failing const eval must be local");
-                    use rustc::mir::interpret::InterpError::*;
-                    let msg = match msg {
-                        Overflow(_) |
-                        OverflowNeg |
-                        DivisionByZero |
-                        RemainderByZero => msg.description().to_owned(),
-                        BoundsCheck { ref len, ref index } => {
-                            let len = self
-                                .eval_operand(len, source_info)
-                                .expect("len must be const");
-                            let len = match self.ecx.read_scalar(len) {
-                                Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
-                                    bits, ..
-                                })) => bits,
-                                other => bug!("const len not primitive: {:?}", other),
-                            };
-                            let index = self
-                                .eval_operand(index, source_info)
-                                .expect("index must be const");
-                            let index = match self.ecx.read_scalar(index) {
-                                Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
-                                    bits, ..
-                                })) => bits,
-                                other => bug!("const index not primitive: {:?}", other),
-                            };
-                            format!(
-                                "index out of bounds: \
-                                the len is {} but the index is {}",
-                                len,
-                                index,
-                            )
-                        },
-                        // Need proper const propagator for these
-                        _ => return,
-                    };
-                    self.tcx.lint_hir(
-                        ::rustc::lint::builtin::CONST_ERR,
-                        hir_id,
-                        span,
-                        &msg,
-                    );
                 }
-            }
+            },
+            TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => {
+                if self.should_const_prop() {
+                    if let Some(value) = self.eval_operand(&discr, source_info) {
+                        if let ScalarMaybeUndef::Scalar(scalar) =
+                                self.ecx.read_scalar(value).unwrap() {
+                            *discr = self.operand_from_scalar(scalar, switch_ty, source_info.span);
+                        }
+                    }
+                }
+            },
+            //none of these have Operands to const-propagate
+            TerminatorKind::Goto { .. } |
+            TerminatorKind::Resume |
+            TerminatorKind::Abort |
+            TerminatorKind::Return |
+            TerminatorKind::Unreachable |
+            TerminatorKind::Drop { .. } |
+            TerminatorKind::DropAndReplace { .. } |
+            TerminatorKind::Yield { .. } |
+            TerminatorKind::GeneratorDrop |
+            TerminatorKind::FalseEdges { .. } |
+            TerminatorKind::FalseUnwind { .. } => { }
+            //FIXME(wesleywiser) Call does have Operands that could be const-propagated
+            TerminatorKind::Call { .. } => { }
         }
     }
 }
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 9a39e071721..579f75ba516 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -22,6 +22,7 @@ use rustc::middle::lang_items;
 use rustc::session::config::nightly_options;
 use syntax::ast::LitKind;
 use syntax::feature_gate::{emit_feature_err, GateIssue};
+use syntax::symbol::sym;
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::fmt;
@@ -380,8 +381,8 @@ impl Qualif for IsNotPromotable {
 
                 !allowed ||
                     cx.tcx.get_attrs(def_id).iter().any(
-                        |attr| attr.check_name("thread_local"
-                    ))
+                        |attr| attr.check_name(sym::thread_local)
+                    )
             }
         }
     }
@@ -939,7 +940,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                 if self.tcx
                        .get_attrs(def_id)
                        .iter()
-                       .any(|attr| attr.check_name("thread_local")) {
+                       .any(|attr| attr.check_name(sym::thread_local)) {
                     if self.mode != Mode::Fn {
                         span_err!(self.tcx.sess, self.span, E0625,
                                   "thread-local statics cannot be \
@@ -994,7 +995,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                 if let ty::RawPtr(_) = base_ty.sty {
                                     if !self.tcx.features().const_raw_ptr_deref {
                                         emit_feature_err(
-                                            &self.tcx.sess.parse_sess, "const_raw_ptr_deref",
+                                            &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref,
                                             self.span, GateIssue::Language,
                                             &format!(
                                                 "dereferencing raw pointers in {}s is unstable",
@@ -1018,7 +1019,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                     Mode::ConstFn => {
                                         if !self.tcx.features().const_fn_union {
                                             emit_feature_err(
-                                                &self.tcx.sess.parse_sess, "const_fn_union",
+                                                &self.tcx.sess.parse_sess, sym::const_fn_union,
                                                 self.span, GateIssue::Language,
                                                 "unions in const fn are unstable",
                                             );
@@ -1123,7 +1124,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                             // in const fn and constants require the feature gate
                             // FIXME: make it unsafe inside const fn and constants
                             emit_feature_err(
-                                &self.tcx.sess.parse_sess, "const_raw_ptr_to_usize_cast",
+                                &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast,
                                 self.span, GateIssue::Language,
                                 &format!(
                                     "casting pointers to integers in {}s is unstable",
@@ -1149,7 +1150,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                         // FIXME: make it unsafe to use these operations
                         emit_feature_err(
                             &self.tcx.sess.parse_sess,
-                            "const_compare_raw_pointers",
+                            sym::const_compare_raw_pointers,
                             self.span,
                             GateIssue::Language,
                             &format!("comparing raw pointers inside {}", self.mode),
@@ -1210,7 +1211,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                         // const eval transmute calls only with the feature gate
                                         if !self.tcx.features().const_transmute {
                                             emit_feature_err(
-                                                &self.tcx.sess.parse_sess, "const_transmute",
+                                                &self.tcx.sess.parse_sess, sym::const_transmute,
                                                 self.span, GateIssue::Language,
                                                 &format!("The use of std::mem::transmute() \
                                                 is gated in {}s", self.mode));
@@ -1249,7 +1250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                         // Don't allow panics in constants without the feature gate.
                                         emit_feature_err(
                                             &self.tcx.sess.parse_sess,
-                                            "const_panic",
+                                            sym::const_panic,
                                             self.span,
                                             GateIssue::Language,
                                             &format!("panicking in {}s is unstable", self.mode),
@@ -1260,7 +1261,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
                                     // Check `#[unstable]` const fns or `#[rustc_const_unstable]`
                                     // functions without the feature gate active in this crate in
                                     // order to report a better error message than the one below.
-                                    if !self.span.allows_unstable(&feature.as_str()) {
+                                    if !self.span.allows_unstable(feature) {
                                         let mut err = self.tcx.sess.struct_span_err(self.span,
                                             &format!("`{}` is not yet stable as a const fn",
                                                     self.tcx.def_path_str(def_id)));
@@ -1592,7 +1593,7 @@ impl MirPass for QualifyAndPromoteConstants {
         if mode == Mode::Static {
             // `#[thread_local]` statics don't have to be `Sync`.
             for attr in &tcx.get_attrs(def_id)[..] {
-                if attr.check_name("thread_local") {
+                if attr.check_name(sym::thread_local) {
                     return;
                 }
             }
@@ -1616,7 +1617,7 @@ impl MirPass for QualifyAndPromoteConstants {
 
 fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<FxHashSet<usize>> {
     let attrs = tcx.get_attrs(def_id);
-    let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?;
+    let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
     let mut ret = FxHashSet::default();
     for meta in attr.meta_item_list()? {
         match meta.literal()?.node {
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 246f876235d..815821f6ff0 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -1,5 +1,6 @@
 use rustc_target::spec::abi::{Abi};
 use syntax::ast;
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 use rustc::ty::{self, TyCtxt};
@@ -27,7 +28,7 @@ impl MirPass for SanityCheck {
     fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           src: MirSource<'tcx>, mir: &mut Mir<'tcx>) {
         let def_id = src.def_id();
-        if !tcx.has_attr(def_id, "rustc_mir") {
+        if !tcx.has_attr(def_id, sym::rustc_mir) {
             debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
             return;
         } else {
@@ -52,16 +53,16 @@ impl MirPass for SanityCheck {
                         DefinitelyInitializedPlaces::new(tcx, mir, &mdpe),
                         |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]));
 
-        if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() {
+        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() {
             sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_inits);
         }
-        if has_rustc_mir_with(&attributes, "rustc_peek_maybe_uninit").is_some() {
+        if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() {
             sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_uninits);
         }
-        if has_rustc_mir_with(&attributes, "rustc_peek_definite_init").is_some() {
+        if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() {
             sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_def_inits);
         }
-        if has_rustc_mir_with(&attributes, "stop_after_dataflow").is_some() {
+        if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() {
             tcx.sess.fatal("stop_after_dataflow ended compilation");
         }
     }
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 4563c9f18a3..a5dfb736b81 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -634,6 +634,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
     fn cannot_return_reference_to_local(
         self,
         span: Span,
+        return_kind: &str,
         reference_desc: &str,
         path_desc: &str,
         o: Origin,
@@ -642,7 +643,8 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
             self,
             span,
             E0515,
-            "cannot return {REFERENCE} {LOCAL}{OGN}",
+            "cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
+            RETURN=return_kind,
             REFERENCE=reference_desc,
             LOCAL=path_desc,
             OGN = o
@@ -650,7 +652,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
 
         err.span_label(
             span,
-            format!("returns a {} data owned by the current function", reference_desc),
+            format!("{}s a {} data owned by the current function", return_kind, reference_desc),
         );
 
         self.cancel_if_wrong_origin(err, o)
diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs
index 04b0e16cd9a..fc4c6b3fd3f 100644
--- a/src/librustc_mir/util/graphviz.rs
+++ b/src/librustc_mir/util/graphviz.rs
@@ -27,7 +27,7 @@ pub fn graphviz_safe_def_name(def_id: DefId) -> String {
     format!(
         "{}_{}",
         def_id.krate.index(),
-        def_id.index.as_array_index(),
+        def_id.index.index(),
     )
 }
 
@@ -167,7 +167,7 @@ fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
                    Place::Base(PlaceBase::Local(local)), escape(&decl.ty), name)?;
         } else {
-            write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
+            write!(w, r#"{:?}: {};<br align="left"/>"#,
                    Place::Base(PlaceBase::Local(local)), escape(&decl.ty))?;
         }
     }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 6cb3161382a..2bea1db841a 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::*;
 use syntax::attr;
 use syntax::source_map::Spanned;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax::ptr::P;
 use syntax::visit::{self, Visitor};
 use syntax::{span_err, struct_span_err, walk_list};
@@ -54,21 +54,21 @@ struct AstValidator<'a> {
     has_proc_macro_decls: bool,
     has_global_allocator: bool,
 
-    // Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
-    // Nested `impl Trait` _is_ allowed in associated type position,
-    // e.g `impl Iterator<Item=impl Debug>`
+    /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
+    /// Nested `impl Trait` _is_ allowed in associated type position,
+    /// e.g `impl Iterator<Item=impl Debug>`
     outer_impl_trait: Option<OuterImplTrait>,
 
-    // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
-    // or `Foo::Bar<impl Trait>`
+    /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
+    /// or `Foo::Bar<impl Trait>`
     is_impl_trait_banned: bool,
 
-    // rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
-    // until PRs #57730 and #57981 landed: it would jump directly to
-    // walk_ty rather than visit_ty (or skip recurring entirely for
-    // impl trait in projections), and thus miss some cases. We track
-    // whether we should downgrade to a warning for short-term via
-    // these booleans.
+    /// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
+    /// until PRs #57730 and #57981 landed: it would jump directly to
+    /// walk_ty rather than visit_ty (or skip recurring entirely for
+    /// impl trait in projections), and thus miss some cases. We track
+    /// whether we should downgrade to a warning for short-term via
+    /// these booleans.
     warning_period_57979_didnt_record_next_impl_trait: bool,
     warning_period_57979_impl_trait_in_proj: bool,
 }
@@ -565,7 +565,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             self.has_proc_macro_decls = true;
         }
 
-        if attr::contains_name(&item.attrs, "global_allocator") {
+        if attr::contains_name(&item.attrs, sym::global_allocator) {
             self.has_global_allocator = true;
         }
 
@@ -676,8 +676,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                attr::first_attr_value_str_by_name(&item.attrs, "path");
-                if attr::contains_name(&item.attrs, "warn_directory_ownership") {
+                attr::first_attr_value_str_by_name(&item.attrs, sym::path);
+                if attr::contains_name(&item.attrs, sym::warn_directory_ownership) {
                     let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
                     let msg = "cannot declare a new module at this location";
                     self.session.buffer_lint(lint, item.id, item.span, msg);
diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs
index 7041a5593ab..dea5774aa6e 100644
--- a/src/librustc_passes/layout_test.rs
+++ b/src/librustc_passes/layout_test.rs
@@ -12,6 +12,7 @@ use rustc::ty::ParamEnv;
 use rustc::ty::Ty;
 use rustc::ty::TyCtxt;
 use syntax::ast::Attribute;
+use syntax::symbol::sym;
 
 pub fn test_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     if tcx.features().rustc_attrs {
@@ -32,7 +33,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> {
 
         if let ItemKind::Ty(..) = item.node {
             for attr in self.tcx.get_attrs(item_def_id).iter() {
-                if attr.check_name("rustc_layout") {
+                if attr.check_name(sym::rustc_layout) {
                     self.dump_layout_of(item_def_id, item, attr);
                 }
             }
@@ -54,26 +55,26 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> {
                 // The `..` are the names of fields to dump.
                 let meta_items = attr.meta_item_list().unwrap_or_default();
                 for meta_item in meta_items {
-                    match meta_item.name_or_empty().get() {
-                        "abi" => {
+                    match meta_item.name_or_empty() {
+                        sym::abi => {
                             self.tcx
                                 .sess
                                 .span_err(item.span, &format!("abi: {:?}", ty_layout.abi));
                         }
 
-                        "align" => {
+                        sym::align => {
                             self.tcx
                                 .sess
                                 .span_err(item.span, &format!("align: {:?}", ty_layout.align));
                         }
 
-                        "size" => {
+                        sym::size => {
                             self.tcx
                                 .sess
                                 .span_err(item.span, &format!("size: {:?}", ty_layout.size));
                         }
 
-                        "homogeneous_aggregate" => {
+                        sym::homogeneous_aggregate => {
                             self.tcx.sess.span_err(
                                 item.span,
                                 &format!(
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index 0f651fafcd2..37917aaa4a8 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -25,6 +25,7 @@ use rustc::ty::query::Providers;
 use rustc::ty::subst::{InternalSubsts, SubstsRef};
 use rustc::util::nodemap::{ItemLocalSet, HirIdSet};
 use rustc::hir;
+use syntax::symbol::sym;
 use syntax_pos::{Span, DUMMY_SP};
 use log::debug;
 use Promotability::*;
@@ -335,7 +336,7 @@ fn check_expr_kind<'a, 'tcx>(
 
                     if v.in_static {
                         for attr in &v.tcx.get_attrs(did)[..] {
-                            if attr.check_name("thread_local") {
+                            if attr.check_name(sym::thread_local) {
                                 debug!("Reference to Static(id={:?}) is unpromotable \
                                        due to a #[thread_local] attribute", did);
                                 return NotPromotable;
@@ -518,15 +519,6 @@ fn check_expr_kind<'a, 'tcx>(
             NotPromotable
         }
 
-        hir::ExprKind::If(ref lhs, ref rhs, ref option_expr) => {
-            let _ = v.check_expr(lhs);
-            let _ = v.check_expr(rhs);
-            if let Some(ref expr) = option_expr {
-                let _ = v.check_expr(&expr);
-            }
-            NotPromotable
-        }
-
         // Loops (not very meaningful in constants).
         hir::ExprKind::While(ref expr, ref box_block, ref _option_label) => {
             let _ = v.check_expr(expr);
diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs
index 31018a7cd7a..8259419c64a 100644
--- a/src/librustc_plugin/build.rs
+++ b/src/librustc_plugin/build.rs
@@ -1,6 +1,7 @@
 //! Used by `rustc` when compiling a plugin crate.
 
 use syntax::attr;
+use syntax::symbol::sym;
 use syntax_pos::Span;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir;
@@ -15,8 +16,7 @@ struct RegistrarFinder {
 impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
     fn visit_item(&mut self, item: &hir::Item) {
         if let hir::ItemKind::Fn(..) = item.node {
-            if attr::contains_name(&item.attrs,
-                                   "plugin_registrar") {
+            if attr::contains_name(&item.attrs, sym::plugin_registrar) {
                 self.registrars.push((item.hir_id, item.span));
             }
         }
diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs
index 8b86bddb29f..680bdcc4bbe 100644
--- a/src/librustc_plugin/load.rs
+++ b/src/librustc_plugin/load.rs
@@ -11,6 +11,7 @@ use std::mem;
 use std::path::PathBuf;
 use syntax::ast;
 use syntax::span_err;
+use syntax::symbol::{Symbol, keywords, sym};
 use syntax_pos::{Span, DUMMY_SP};
 
 /// Pointer to a registrar function.
@@ -45,7 +46,7 @@ pub fn load_plugins(sess: &Session,
     // the feature enabled will result in an error later...
     if sess.features_untracked().plugin {
         for attr in &krate.attrs {
-            if !attr.check_name("plugin") {
+            if !attr.check_name(sym::plugin) {
                 continue;
             }
 
@@ -57,9 +58,9 @@ pub fn load_plugins(sess: &Session,
             for plugin in plugins {
                 // plugins must have a name and can't be key = value
                 let name = plugin.name_or_empty();
-                if !name.is_empty() && !plugin.is_value_str() {
+                if name != keywords::Invalid.name() && !plugin.is_value_str() {
                     let args = plugin.meta_item_list().map(ToOwned::to_owned);
-                    loader.load_plugin(plugin.span(), &name, args.unwrap_or_default());
+                    loader.load_plugin(plugin.span(), name, args.unwrap_or_default());
                 } else {
                     call_malformed_plugin_attribute(sess, attr.span);
                 }
@@ -69,7 +70,7 @@ pub fn load_plugins(sess: &Session,
 
     if let Some(plugins) = addl_plugins {
         for plugin in plugins {
-            loader.load_plugin(DUMMY_SP, &plugin, vec![]);
+            loader.load_plugin(DUMMY_SP, Symbol::intern(&plugin), vec![]);
         }
     }
 
@@ -85,7 +86,7 @@ impl<'a> PluginLoader<'a> {
         }
     }
 
-    fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
+    fn load_plugin(&mut self, span: Span, name: Symbol, args: Vec<ast::NestedMetaItem>) {
         let registrar = self.reader.find_plugin_registrar(span, name);
 
         if let Some((lib, disambiguator)) = registrar {
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 5c5b6f232b2..c2d1d5fa65a 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -7,7 +7,7 @@ use rustc::util::nodemap::FxHashMap;
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
 use syntax::ext::base::MacroExpanderFn;
 use syntax::ext::hygiene;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
 use syntax_pos::Span;
@@ -49,7 +49,7 @@ pub struct Registry<'a> {
     pub llvm_passes: Vec<String>,
 
     #[doc(hidden)]
-    pub attributes: Vec<(String, AttributeType)>,
+    pub attributes: Vec<(Symbol, AttributeType)>,
 }
 
 impl<'a> Registry<'a> {
@@ -86,7 +86,7 @@ impl<'a> Registry<'a> {
     ///
     /// This is the most general hook into `libsyntax`'s expansion behavior.
     pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
-        if name == "macro_rules" {
+        if name == sym::macro_rules {
             panic!("user-defined macros may not be named `macro_rules`");
         }
         self.syntax_exts.push((name, match extension {
@@ -169,7 +169,7 @@ impl<'a> Registry<'a> {
     /// Registered attributes will bypass the `custom_attribute` feature gate.
     /// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
     /// lint. `CrateLevel` attributes will not be allowed on anything other than a crate.
-    pub fn register_attribute(&mut self, name: String, ty: AttributeType) {
+    pub fn register_attribute(&mut self, name: Symbol, ty: AttributeType) {
         self.attributes.push((name, ty));
     }
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index e561b387389..cd21713cddf 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -27,7 +27,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast::Ident;
 use syntax::attr;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax_pos::Span;
 
 use std::{cmp, fmt, mem};
@@ -260,7 +260,8 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                                 ctor_vis = ty::Visibility::Restricted(
                                     DefId::local(CRATE_DEF_INDEX));
                                 let attrs = tcx.get_attrs(variant.def_id);
-                                span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span;
+                                span = attr::find_by_name(&attrs, sym::non_exhaustive)
+                                    .unwrap().span;
                                 descr = "crate-visible";
                             }
 
@@ -291,7 +292,7 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
                                 if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
                                     ctor_vis =
                                         ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
-                                    span = attr::find_by_name(&item.attrs, "non_exhaustive")
+                                    span = attr::find_by_name(&item.attrs, sym::non_exhaustive)
                                                 .unwrap().span;
                                     descr = "crate-visible";
                                 }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 3c5760c746f..3b58a99d19f 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -37,7 +37,7 @@ use syntax::feature_gate::is_builtin_attr;
 use syntax::parse::token::{self, Token};
 use syntax::span_err;
 use syntax::std_inject::injected_crate_name;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
@@ -257,7 +257,7 @@ impl<'a> Resolver<'a> {
             }
             ast::UseTreeKind::Glob => {
                 let subclass = GlobImport {
-                    is_prelude: attr::contains_name(&item.attrs, "prelude_import"),
+                    is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
                     max_vis: Cell::new(ty::Visibility::Invisible),
                 };
                 self.add_import_directive(
@@ -314,7 +314,7 @@ impl<'a> Resolver<'a> {
                             Ident::new(keywords::SelfLower.name(), new_span)
                         ),
                         kind: ast::UseTreeKind::Simple(
-                            Some(Ident::new(Name::gensym("__dummy"), new_span)),
+                            Some(Ident::from_str_and_span("__dummy", new_span).gensym()),
                             ast::DUMMY_NODE_ID,
                             ast::DUMMY_NODE_ID,
                         ),
@@ -369,7 +369,7 @@ impl<'a> Resolver<'a> {
                 };
 
                 self.populate_module_if_necessary(module);
-                if injected_crate_name().map_or(false, |name| ident.name == name) {
+                if injected_crate_name().map_or(false, |name| ident.name.as_str() == name) {
                     self.injected_crate = Some(module);
                 }
 
@@ -427,7 +427,7 @@ impl<'a> Resolver<'a> {
                 let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name);
                 let module = self.arenas.alloc_module(ModuleData {
                     no_implicit_prelude: parent.no_implicit_prelude || {
-                        attr::contains_name(&item.attrs, "no_implicit_prelude")
+                        attr::contains_name(&item.attrs, sym::no_implicit_prelude)
                     },
                     ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span)
                 });
@@ -456,12 +456,12 @@ impl<'a> Resolver<'a> {
 
                 // Functions introducing procedural macros reserve a slot
                 // in the macro namespace as well (see #52225).
-                if attr::contains_name(&item.attrs, "proc_macro") ||
-                   attr::contains_name(&item.attrs, "proc_macro_attribute") {
+                if attr::contains_name(&item.attrs, sym::proc_macro) ||
+                   attr::contains_name(&item.attrs, sym::proc_macro_attribute) {
                     let res = Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), res.def_id());
                     self.define(parent, ident, MacroNS, (res, vis, sp, expansion));
                 }
-                if let Some(attr) = attr::find_by_name(&item.attrs, "proc_macro_derive") {
+                if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) {
                     if let Some(trait_attr) =
                             attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
                         if let Some(ident) = trait_attr.ident() {
@@ -518,7 +518,7 @@ impl<'a> Resolver<'a> {
 
                 let mut ctor_vis = vis;
 
-                let has_non_exhaustive = attr::contains_name(&item.attrs, "non_exhaustive");
+                let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive);
 
                 // If the structure is marked as non_exhaustive then lower the visibility
                 // to within the crate.
@@ -599,7 +599,7 @@ impl<'a> Resolver<'a> {
         // If the variant is marked as non_exhaustive then lower the visibility to within the
         // crate.
         let mut ctor_vis = vis;
-        let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive");
+        let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive);
         if has_non_exhaustive && vis == ty::Visibility::Public {
             ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
         }
@@ -825,7 +825,7 @@ impl<'a> Resolver<'a> {
         let mut import_all = None;
         let mut single_imports = Vec::new();
         for attr in &item.attrs {
-            if attr.check_name("macro_use") {
+            if attr.check_name(sym::macro_use) {
                 if self.current_module.parent.is_some() {
                     span_err!(self.session, item.span, E0468,
                         "an `extern crate` loading macros must be at the crate root");
@@ -908,7 +908,7 @@ impl<'a> Resolver<'a> {
     /// Returns `true` if this attribute list contains `macro_use`.
     fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
         for attr in attrs {
-            if attr.check_name("macro_escape") {
+            if attr.check_name(sym::macro_escape) {
                 let msg = "macro_escape is a deprecated synonym for macro_use";
                 let mut err = self.session.struct_span_warn(attr.span, msg);
                 if let ast::AttrStyle::Inner = attr.style {
@@ -916,7 +916,7 @@ impl<'a> Resolver<'a> {
                 } else {
                     err.emit();
                 }
-            } else if !attr.check_name("macro_use") {
+            } else if !attr.check_name(sym::macro_use) {
                 continue;
             }
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 18da89b9099..c4a4dd30605 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -43,7 +43,7 @@ use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
 use syntax::ext::base::SyntaxExtension;
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::base::MacroKind;
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::{Symbol, keywords, sym};
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use syntax::visit::{self, FnKind, Visitor};
@@ -1812,8 +1812,8 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
     fn resolve_str_path(
         &mut self,
         span: Span,
-        crate_root: Option<&str>,
-        components: &[&str],
+        crate_root: Option<Symbol>,
+        components: &[Symbol],
         is_value: bool
     ) -> hir::Path {
         let root = if crate_root.is_some() {
@@ -1825,7 +1825,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
             .chain(
                 crate_root.into_iter()
                     .chain(components.iter().cloned())
-                    .map(Ident::from_str)
+                    .map(Ident::with_empty_ctxt)
             ).map(|i| self.new_ast_path_segment(i)).collect::<Vec<_>>();
 
 
@@ -1964,7 +1964,7 @@ impl<'a> Resolver<'a> {
             keywords::Invalid.name(),
         );
         let graph_root = arenas.alloc_module(ModuleData {
-            no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
+            no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
             ..ModuleData::new(None, root_module_kind, root_def_id, Mark::root(), krate.span)
         });
         let mut module_map = FxHashMap::default();
@@ -1978,12 +1978,12 @@ impl<'a> Resolver<'a> {
             session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default()))
                                        .collect();
 
-        if !attr::contains_name(&krate.attrs, "no_core") {
-            extern_prelude.insert(Ident::from_str("core"), Default::default());
-            if !attr::contains_name(&krate.attrs, "no_std") {
-                extern_prelude.insert(Ident::from_str("std"), Default::default());
+        if !attr::contains_name(&krate.attrs, sym::no_core) {
+            extern_prelude.insert(Ident::with_empty_ctxt(sym::core), Default::default());
+            if !attr::contains_name(&krate.attrs, sym::no_std) {
+                extern_prelude.insert(Ident::with_empty_ctxt(sym::std), Default::default());
                 if session.rust_2018() {
-                    extern_prelude.insert(Ident::from_str("meta"), Default::default());
+                    extern_prelude.insert(Ident::with_empty_ctxt(sym::meta), Default::default());
                 }
             }
         }
@@ -3374,7 +3374,7 @@ impl<'a> Resolver<'a> {
                     self.trait_map.insert(id, traits);
                 }
 
-                let mut std_path = vec![Segment::from_ident(Ident::from_str("std"))];
+                let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))];
                 std_path.extend(path);
                 if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
                     let cl = CrateLint::No;
@@ -4225,7 +4225,7 @@ impl<'a> Resolver<'a> {
         let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
             for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
                 if let Some(binding) = resolution.borrow().binding {
-                    if !ident.name.is_gensymed() && filter_fn(binding.res()) {
+                    if !ident.is_gensymed() && filter_fn(binding.res()) {
                         names.push(TypoSuggestion {
                             candidate: ident.name,
                             article: binding.res().article(),
@@ -4243,7 +4243,7 @@ impl<'a> Resolver<'a> {
             for rib in self.ribs[ns].iter().rev() {
                 // Locals and type parameters
                 for (ident, &res) in &rib.bindings {
-                    if !ident.name.is_gensymed() && filter_fn(res) {
+                    if !ident.is_gensymed() && filter_fn(res) {
                         names.push(TypoSuggestion {
                             candidate: ident.name,
                             article: res.article(),
@@ -4273,7 +4273,7 @@ impl<'a> Resolver<'a> {
                                             },
                                         );
 
-                                        if !ident.name.is_gensymed() && filter_fn(crate_mod) {
+                                        if !ident.is_gensymed() && filter_fn(crate_mod) {
                                             Some(TypoSuggestion {
                                                 candidate: ident.name,
                                                 article: "a",
@@ -4298,7 +4298,6 @@ impl<'a> Resolver<'a> {
                 names.extend(
                     self.primitive_type_table.primitive_types
                         .iter()
-                        .filter(|(name, _)| !name.is_gensymed())
                         .map(|(name, _)| {
                             TypoSuggestion {
                                 candidate: *name,
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 79a92d595c2..e34a33ef8fa 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -22,7 +22,7 @@ use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{
     feature_err, is_builtin_attr_name, AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES,
 };
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::{Symbol, keywords, sym};
 use syntax::visit::Visitor;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{Span, DUMMY_SP};
@@ -172,7 +172,7 @@ impl<'a> base::Resolver for Resolver<'a> {
     fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
         let def_id = DefId {
             krate: CrateNum::BuiltinMacros,
-            index: DefIndex::from_array_index(self.macro_map.len()),
+            index: DefIndex::from(self.macro_map.len()),
         };
         let kind = ext.kind();
         self.macro_map.insert(def_id, ext);
@@ -313,7 +313,8 @@ impl<'a> Resolver<'a> {
                             if !features.rustc_attrs {
                                 let msg = "unless otherwise specified, attributes with the prefix \
                                            `rustc_` are reserved for internal compiler diagnostics";
-                                self.report_unknown_attribute(path.span, &name, msg, "rustc_attrs");
+                                self.report_unknown_attribute(path.span, &name, msg,
+                                                              sym::rustc_attrs);
                             }
                         } else if !features.custom_attribute {
                             let msg = format!("The attribute `{}` is currently unknown to the \
@@ -323,7 +324,7 @@ impl<'a> Resolver<'a> {
                                 path.span,
                                 &name,
                                 &msg,
-                                "custom_attribute",
+                                sym::custom_attribute,
                             );
                         }
                     }
@@ -345,7 +346,7 @@ impl<'a> Resolver<'a> {
         Ok((res, self.get_macro(res)))
     }
 
-    fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: &str) {
+    fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: Symbol) {
         let mut err = feature_err(
             &self.session.parse_sess,
             feature,
@@ -693,7 +694,7 @@ impl<'a> Resolver<'a> {
                 WhereToResolve::LegacyPluginHelpers => {
                     if (use_prelude || rust_2015) &&
                        self.session.plugin_attributes.borrow().iter()
-                                                     .any(|(name, _)| ident.name == &**name) {
+                                                     .any(|(name, _)| ident.name == *name) {
                         let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
                                        ty::Visibility::Public, DUMMY_SP, Mark::root())
                                        .to_name_binding(self.arenas);
@@ -981,7 +982,7 @@ impl<'a> Resolver<'a> {
                     let msg =
                         format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang);
                     let mut err = self.session.struct_span_err(ident.span, &msg);
-                    self.suggest_macro_name(&ident.as_str(), kind, &mut err, ident.span);
+                    self.suggest_macro_name(ident.name, kind, &mut err, ident.span);
                     err.emit();
                 }
             }
@@ -1009,11 +1010,12 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
+    fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind,
                           err: &mut DiagnosticBuilder<'a>, span: Span) {
         // First check if this is a locally-defined bang macro.
         let suggestion = if let MacroKind::Bang = kind {
-            find_best_match_for_name(self.macro_names.iter().map(|ident| &ident.name), name, None)
+            find_best_match_for_name(
+                self.macro_names.iter().map(|ident| &ident.name), &name.as_str(), None)
         } else {
             None
         // Then check global macros.
@@ -1022,7 +1024,7 @@ impl<'a> Resolver<'a> {
                                                   .filter_map(|(name, binding)| {
                 if binding.macro_kind() == Some(kind) { Some(name) } else { None }
             });
-            find_best_match_for_name(names, name, None)
+            find_best_match_for_name(names, &name.as_str(), None)
         // Then check modules.
         }).or_else(|| {
             let is_macro = |res| {
@@ -1032,7 +1034,7 @@ impl<'a> Resolver<'a> {
                     false
                 }
             };
-            let ident = Ident::new(Symbol::intern(name), span);
+            let ident = Ident::new(name, span);
             self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span)
                 .map(|suggestion| suggestion.candidate)
         });
@@ -1091,7 +1093,7 @@ impl<'a> Resolver<'a> {
                         current_legacy_scope: &mut LegacyScope<'a>) {
         self.local_macro_def_scopes.insert(item.id, self.current_module);
         let ident = item.ident;
-        if ident.name == "macro_rules" {
+        if ident.name == sym::macro_rules {
             self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`");
         }
 
@@ -1106,7 +1108,7 @@ impl<'a> Resolver<'a> {
             let ident = ident.modern();
             self.macro_names.insert(ident);
             let res = Res::Def(DefKind::Macro(MacroKind::Bang), def_id);
-            let is_macro_export = attr::contains_name(&item.attrs, "macro_export");
+            let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
@@ -1124,7 +1126,7 @@ impl<'a> Resolver<'a> {
                 self.define(module, ident, MacroNS,
                             (res, vis, item.span, expansion, IsMacroExport));
             } else {
-                if !attr::contains_name(&item.attrs, "rustc_doc_only_macro") {
+                if !attr::contains_name(&item.attrs, sym::rustc_doc_only_macro) {
                     self.check_reserved_macro_name(ident, MacroNS);
                 }
                 self.unused_macros.insert(def_id);
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 9e6b8d03545..3a6a8b56ff3 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -29,7 +29,7 @@ use rustc::{bug, span_bug};
 use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::hygiene::Mark;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax::{struct_span_err, unwrap_or};
 use syntax_pos::{MultiSpan, Span};
@@ -496,7 +496,8 @@ impl<'a> Resolver<'a> {
         // Reserve some names that are not quite covered by the general check
         // performed on `Resolver::builtin_attrs`.
         if ns == MacroNS &&
-           (ident.name == "cfg" || ident.name == "cfg_attr" || ident.name == "derive") {
+           (ident.name == sym::cfg || ident.name == sym::cfg_attr ||
+            ident.name == sym::derive) {
             self.session.span_err(ident.span,
                                   &format!("name `{}` is reserved in macro namespace", ident));
         }
@@ -706,7 +707,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 has_errors = true;
 
                 if let SingleImport { source, ref source_bindings, .. } = import.subclass {
-                    if source.name == "self" {
+                    if source.name == keywords::SelfLower.name() {
                         // Silence `unresolved import` error if E0429 is already emitted
                         if let Err(Determined) = source_bindings.value_ns.get() {
                             continue;
@@ -1041,7 +1042,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                     let initial_res = source_bindings[ns].get().map(|initial_binding| {
                         all_ns_err = false;
                         if let Some(target_binding) = target_bindings[ns].get() {
-                            if target.name == "_" &&
+                            // Note that as_str() de-gensyms the Symbol
+                            if target.name.as_str() == "_" &&
                                initial_binding.is_extern_crate() && !initial_binding.is_import() {
                                 this.record_use(ident, ns, target_binding,
                                                 directive.module_path.is_empty());
@@ -1392,7 +1394,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             // (e.g. implicitly injected `std`) cannot be properly encoded in metadata,
             // so they can cause name conflict errors downstream.
             let is_good_import = binding.is_import() && !binding.is_ambiguity() &&
-                                 !(ident.name.is_gensymed() && ident.name != "_");
+                                 // Note that as_str() de-gensyms the Symbol
+                                 !(ident.is_gensymed() && ident.name.as_str() != "_");
             if is_good_import || binding.is_macro_def() {
                 let res = binding.res();
                 if res != Res::Err {
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index a45e32ddb66..1e65f868eba 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -463,10 +463,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         }
 
         // walk type and init value
-        self.visit_ty(typ);
-        if let Some(expr) = expr {
-            self.visit_expr(expr);
-        }
+        self.nest_tables(id, |v| {
+            v.visit_ty(typ);
+            if let Some(expr) = expr {
+                v.visit_expr(expr);
+            }
+        });
     }
 
     // FIXME tuple structs should generate tuple-specific data.
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index f3e0fb32ec2..d34f5633946 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -879,7 +879,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let mut result = String::new();
 
         for attr in attrs {
-            if attr.check_name("doc") {
+            if attr.check_name(sym::doc) {
                 if let Some(val) = attr.value_str() {
                     if attr.is_sugared_doc {
                         result.push_str(&strip_doc_comment_decoration(&val.as_str()));
@@ -889,10 +889,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     result.push('\n');
                 } else if let Some(meta_list) = attr.meta_item_list() {
                     meta_list.into_iter()
-                             .filter(|it| it.check_name("include"))
+                             .filter(|it| it.check_name(sym::include))
                              .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
                              .flat_map(|it| it)
-                             .filter(|meta| meta.check_name("contents"))
+                             .filter(|meta| meta.check_name(sym::contents))
                              .filter_map(|meta| meta.value_str())
                              .for_each(|val| {
                                  result.push_str(&val.as_str());
@@ -1170,7 +1170,7 @@ fn generated_code(span: Span) -> bool {
 fn id_from_def_id(id: DefId) -> rls_data::Id {
     rls_data::Id {
         krate: id.krate.as_u32(),
-        index: id.index.as_raw_u32(),
+        index: id.index.as_u32(),
     }
 }
 
@@ -1197,7 +1197,7 @@ fn null_id() -> rls_data::Id {
 fn lower_attributes(attrs: Vec<Attribute>, scx: &SaveContext<'_, '_>) -> Vec<rls_data::Attribute> {
     attrs.into_iter()
     // Only retain real attributes. Doc comments are lowered separately.
-    .filter(|attr| attr.path != "doc")
+    .filter(|attr| attr.path != sym::doc)
     .map(|mut attr| {
         // Remove the surrounding '#[..]' or '#![..]' of the pretty printed
         // attribute. First normalize all inner attribute (#![..]) to outer
diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs
index 9dd343b6c8d..53364e72bfe 100644
--- a/src/librustc_target/spec/apple_base.rs
+++ b/src/librustc_target/spec/apple_base.rs
@@ -14,7 +14,7 @@ pub fn opts() -> TargetOptions {
     //
     // Here we detect what version is being requested, defaulting to 10.7. ELF
     // TLS is flagged as enabled if it looks to be supported.
-    let version = macos_deployment_target().unwrap_or((10, 7));
+    let version = macos_deployment_target();
 
     TargetOptions {
         // macOS has -dead_strip, which doesn't rely on function_sections
@@ -35,7 +35,7 @@ pub fn opts() -> TargetOptions {
     }
 }
 
-fn macos_deployment_target() -> Option<(u32, u32)> {
+fn macos_deployment_target() -> (u32, u32) {
     let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
     let version = deployment_target.as_ref().and_then(|s| {
         let mut i = s.splitn(2, '.');
@@ -44,17 +44,10 @@ fn macos_deployment_target() -> Option<(u32, u32)> {
         a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok()
     });
 
-    version
+    version.unwrap_or((10, 7))
 }
 
 pub fn macos_llvm_target(arch: &str) -> String {
-    let version = macos_deployment_target();
-    let llvm_target = match version {
-        Some((major, minor)) => {
-            format!("{}-apple-macosx{}.{}.0", arch, major, minor)
-        },
-        None => format!("{}-apple-darwin", arch)
-    };
-
-    llvm_target
+    let (major, minor) = macos_deployment_target();
+    format!("{}-apple-macosx{}.{}.0", arch, major, minor)
 }
diff --git a/src/librustc_target/spec/bitrig_base.rs b/src/librustc_target/spec/bitrig_base.rs
deleted file mode 100644
index 9b34119fc00..00000000000
--- a/src/librustc_target/spec/bitrig_base.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use crate::spec::{TargetOptions, RelroLevel};
-use std::default::Default;
-
-pub fn opts() -> TargetOptions {
-    TargetOptions {
-        dynamic_linking: true,
-        executables: true,
-        target_family: Some("unix".to_string()),
-        linker_is_gnu: true,
-        has_rpath: true,
-        position_independent_executables: true,
-        relro_level: RelroLevel::Full,
-
-        .. Default::default()
-    }
-}
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 46fefd78f45..844edbb946a 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -47,7 +47,6 @@ mod android_base;
 mod apple_base;
 mod apple_ios_base;
 mod arm_base;
-mod bitrig_base;
 mod cloudabi_base;
 mod dragonfly_base;
 mod freebsd_base;
@@ -390,8 +389,6 @@ supported_targets! {
     ("i686-unknown-dragonfly", i686_unknown_dragonfly),
     ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
 
-    ("x86_64-unknown-bitrig", x86_64_unknown_bitrig),
-
     ("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
     ("i686-unknown-openbsd", i686_unknown_openbsd),
     ("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
@@ -444,7 +441,7 @@ supported_targets! {
     ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-unknown-unknown", wasm32_unknown_unknown),
-    ("wasm32-unknown-wasi", wasm32_unknown_wasi),
+    ("wasm32-wasi", wasm32_wasi),
     ("wasm32-experimental-emscripten", wasm32_experimental_emscripten),
 
     ("thumbv6m-none-eabi", thumbv6m_none_eabi),
diff --git a/src/librustc_target/spec/wasm32_unknown_wasi.rs b/src/librustc_target/spec/wasm32_wasi.rs
index 0412635bfe2..bb33493a773 100644
--- a/src/librustc_target/spec/wasm32_unknown_wasi.rs
+++ b/src/librustc_target/spec/wasm32_wasi.rs
@@ -1,4 +1,4 @@
-//! The `wasm32-unknown-wasi` target is a new and still (as of March 2019)
+//! The `wasm32-wasi` target is a new and still (as of April 2019) an
 //! experimental target. The definition in this file is likely to be tweaked
 //! over time and shouldn't be relied on too much.
 //!
@@ -13,14 +13,14 @@
 //! serve two use cases here with this target:
 //!
 //! * First, we want Rust usage of the target to be as hassle-free as possible,
-//!   ideally avoiding the need to configure and install a local
-//!   wasm32-unknown-wasi toolchain.
+//!   ideally avoiding the need to configure and install a local wasm32-wasi
+//!   toolchain.
 //!
 //! * Second, one of the primary use cases of LLVM's new wasm backend and the
 //!   wasm support in LLD is that any compiled language can interoperate with
-//!   any other. To that the `wasm32-unknown-wasi` target is the first with a
-//!   viable C standard library and sysroot common definition, so we want Rust
-//!   and C/C++ code to interoperate when compiled to `wasm32-unknown-unknown`.
+//!   any other. To that the `wasm32-wasi` target is the first with a viable C
+//!   standard library and sysroot common definition, so we want Rust and C/C++
+//!   code to interoperate when compiled to `wasm32-unknown-unknown`.
 //!
 //! You'll note, however, that the two goals above are somewhat at odds with one
 //! another. To attempt to solve both use cases in one go we define a target
@@ -39,8 +39,8 @@
 //! necessary.
 //!
 //! All in all, by default, no external dependencies are required. You can
-//! compile `wasm32-unknown-wasi` binaries straight out of the box. You can't,
-//! however, reliably interoperate with C code in this mode (yet).
+//! compile `wasm32-wasi` binaries straight out of the box. You can't, however,
+//! reliably interoperate with C code in this mode (yet).
 //!
 //! ## Interop with C required
 //!
@@ -53,17 +53,17 @@
 //!
 //! 2. If you're using rustc to build a linked artifact then you'll need to
 //!    specify `-C linker` to a `clang` binary that supports
-//!    `wasm32-unknown-wasi` and is configured with the `wasm32-unknown-wasi`
-//!    sysroot. This will cause Rust code to be linked against the libc.a that
-//!    the specified `clang` provides.
+//!    `wasm32-wasi` and is configured with the `wasm32-wasi` sysroot. This
+//!    will cause Rust code to be linked against the libc.a that the specified
+//!    `clang` provides.
 //!
 //! 3. If you're building a staticlib and integrating Rust code elsewhere, then
 //!    compiling with `-C target-feature=-crt-static` is all you need to do.
 //!
 //! You can configure the linker via Cargo using the
-//! `CARGO_TARGET_WASM32_UNKNOWN_WASI_LINKER` env var. Be sure to also set
-//! `CC_wasm32-unknown-wasi` if any crates in the dependency graph are using
-//! the `cc` crate.
+//! `CARGO_TARGET_WASM32_WASI_LINKER` env var. Be sure to also set
+//! `CC_wasm32-wasi` if any crates in the dependency graph are using the `cc`
+//! crate.
 //!
 //! ## Remember, this is all in flux
 //!
@@ -82,7 +82,7 @@ pub fn target() -> Result<Target, String> {
         .pre_link_args
         .entry(LinkerFlavor::Gcc)
         .or_insert(Vec::new())
-        .push("--target=wasm32-unknown-wasi".to_string());
+        .push("--target=wasm32-wasi".to_string());
 
     // When generating an executable be sure to put the startup object at the
     // front so the main function is correctly hooked up.
@@ -98,13 +98,13 @@ pub fn target() -> Result<Target, String> {
     options.crt_static_respected = true;
 
     Ok(Target {
-        llvm_target: "wasm32-unknown-wasi".to_string(),
+        llvm_target: "wasm32-wasi".to_string(),
         target_endian: "little".to_string(),
         target_pointer_width: "32".to_string(),
         target_c_int_width: "32".to_string(),
         target_os: "wasi".to_string(),
         target_env: String::new(),
-        target_vendor: "unknown".to_string(),
+        target_vendor: String::new(),
         data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
diff --git a/src/librustc_target/spec/x86_64_unknown_bitrig.rs b/src/librustc_target/spec/x86_64_unknown_bitrig.rs
deleted file mode 100644
index 999d93a7e60..00000000000
--- a/src/librustc_target/spec/x86_64_unknown_bitrig.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
-
-pub fn target() -> TargetResult {
-    let mut base = super::bitrig_base::opts();
-    base.cpu = "x86-64".to_string();
-    base.max_atomic_width = Some(64);
-    base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
-    base.stack_probes = true;
-
-    Ok(Target {
-        llvm_target: "x86_64-unknown-bitrig".to_string(),
-        target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
-        target_c_int_width: "32".to_string(),
-        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
-        arch: "x86_64".to_string(),
-        target_os: "bitrig".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: base,
-    })
-}
diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs
index 50c21302632..580b1571e52 100644
--- a/src/librustc_traits/lowering/mod.rs
+++ b/src/librustc_traits/lowering/mod.rs
@@ -21,6 +21,7 @@ use rustc::ty::query::Providers;
 use rustc::ty::{self, List, TyCtxt};
 use rustc::ty::subst::{Subst, InternalSubsts};
 use syntax::ast;
+use syntax::symbol::sym;
 
 use std::iter;
 
@@ -640,11 +641,11 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx> {
         for attr in attrs {
             let mut clauses = None;
 
-            if attr.check_name("rustc_dump_program_clauses") {
+            if attr.check_name(sym::rustc_dump_program_clauses) {
                 clauses = Some(self.tcx.program_clauses_for(def_id));
             }
 
-            if attr.check_name("rustc_dump_env_program_clauses") {
+            if attr.check_name(sym::rustc_dump_env_program_clauses) {
                 let environment = self.tcx.environment(def_id);
                 clauses = Some(self.tcx.program_clauses_for_env(environment));
             }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 16033c6c50f..4b052aec5fc 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -25,6 +25,7 @@ use syntax::ast;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
+use syntax::symbol::sym;
 use syntax_pos::{DUMMY_SP, Span, MultiSpan};
 use crate::util::common::ErrorReported;
 use crate::util::nodemap::FxHashMap;
@@ -289,6 +290,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         }
 
         // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present.
+        let mut reported_late_bound_region_err = None;
         if !infer_lifetimes {
             if let Some(span_late) = def.has_late_bound_regions {
                 let msg = "cannot specify lifetime arguments explicitly \
@@ -300,13 +302,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     let mut err = tcx.sess.struct_span_err(span, msg);
                     err.span_note(span_late, note);
                     err.emit();
-                    return (true, None);
+                    reported_late_bound_region_err = Some(true);
                 } else {
                     let mut multispan = MultiSpan::from_span(span);
                     multispan.push_span_label(span_late, note.to_string());
                     tcx.lint_hir(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
                                  args.args[0].id(), multispan, msg);
-                    return (false, None);
+                    reported_late_bound_region_err = Some(false);
                 }
             }
         }
@@ -324,7 +326,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             // For kinds without defaults (i.e., lifetimes), `required == permitted`.
             // For other kinds (i.e., types), `permitted` may be greater than `required`.
             if required <= provided && provided <= permitted {
-                return (false, None);
+                return (reported_late_bound_region_err.unwrap_or(false), None);
             }
 
             // Unfortunately lifetime and type parameter mismatches are typically styled
@@ -379,7 +381,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
              potential_assoc_types)
         };
 
-        if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes {
+        if reported_late_bound_region_err.is_none()
+            && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) {
             check_kind_count(
                 "lifetime",
                 param_counts.lifetimes,
@@ -409,7 +412,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 arg_counts.lifetimes,
             )
         } else {
-            (false, None)
+            (reported_late_bound_region_err.unwrap_or(false), None)
         }
     }
 
@@ -802,7 +805,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             } else {
                 "parenthetical notation is only stable when used with `Fn`-family traits"
             };
-            emit_feature_err(&self.tcx().sess.parse_sess, "unboxed_closures",
+            emit_feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures,
                              span, GateIssue::Language, msg);
         }
 
@@ -1902,7 +1905,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             ty,
         };
 
-        let expr = &tcx.hir().body(ast_const.body).value;
+        let mut expr = &tcx.hir().body(ast_const.body).value;
+
+        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+        if let ExprKind::Block(block, _) = &expr.node {
+            if block.stmts.is_empty() {
+                if let Some(trailing) = &block.expr {
+                    expr = &trailing;
+                }
+            }
+        }
+
         if let ExprKind::Path(ref qpath) = expr.node {
             if let hir::QPath::Resolved(_, ref path) = qpath {
                 if let Res::Def(DefKind::ConstParam, def_id) = path.res {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index e9e202ce379..a69f639e894 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -2,12 +2,12 @@ use crate::check::{FnCtxt, Expectation, Diverges, Needs};
 use crate::check::coercion::CoerceMany;
 use crate::util::nodemap::FxHashMap;
 use errors::{Applicability, DiagnosticBuilder};
-use rustc::hir::{self, PatKind, Pat};
+use rustc::hir::{self, PatKind, Pat, ExprKind};
 use rustc::hir::def::{Res, DefKind, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::infer;
 use rustc::infer::type_variable::TypeVariableOrigin;
-use rustc::traits::ObligationCauseCode;
+use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::subst::Kind;
 use syntax::ast;
@@ -15,6 +15,7 @@ use syntax::source_map::Spanned;
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
+use syntax_pos::hygiene::CompilerDesugaringKind;
 
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::cmp;
@@ -22,10 +23,9 @@ use std::cmp;
 use super::report_unexpected_variant_res;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    /// `match_discrim_span` argument having a `Span` indicates that this pattern is part of
-    /// a match expression arm guard, and it points to the match discriminant to add context
-    /// in type errors. In the folloowing example, `match_discrim_span` corresponds to the
-    /// `a + b` expression:
+    /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match
+    /// expression arm guard, and it points to the match discriminant to add context in type errors.
+    /// In the following example, `discrim_span` corresponds to the `a + b` expression:
     ///
     /// ```text
     /// error[E0308]: mismatched types
@@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         pat: &'gcx hir::Pat,
         mut expected: Ty<'tcx>,
         mut def_bm: ty::BindingMode,
-        match_discrim_span: Option<Span>,
+        discrim_span: Option<Span>,
     ) {
         let tcx = self.tcx;
 
@@ -176,7 +176,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 //     &'static str <: expected
                 //
                 // that's equivalent to there existing a LUB.
-                self.demand_suptype(pat.span, expected, pat_ty);
+                if let Some(mut err) = self.demand_suptype_diag(pat.span, expected, pat_ty) {
+                    err.emit_unless(discrim_span
+                        .filter(|&s| s.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary))
+                        .is_some());
+                }
+
                 pat_ty
             }
             PatKind::Range(ref begin, ref end, _) => {
@@ -224,8 +229,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
 
                 // subtyping doesn't matter here, as the value is some kind of scalar
-                self.demand_eqtype_pat(pat.span, expected, lhs_ty, match_discrim_span);
-                self.demand_eqtype_pat(pat.span, expected, rhs_ty, match_discrim_span);
+                self.demand_eqtype_pat(pat.span, expected, lhs_ty, discrim_span);
+                self.demand_eqtype_pat(pat.span, expected, rhs_ty, discrim_span);
                 common_type
             }
             PatKind::Binding(ba, var_id, _, ref sub) => {
@@ -254,13 +259,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
                         // required. However, we use equality, which is stronger. See (*) for
                         // an explanation.
-                        self.demand_eqtype_pat(pat.span, region_ty, local_ty, match_discrim_span);
+                        self.demand_eqtype_pat(pat.span, region_ty, local_ty, discrim_span);
                     }
                     // otherwise the type of x is the expected type T
                     ty::BindByValue(_) => {
                         // As above, `T <: typeof(x)` is required but we
                         // use equality, see (*) below.
-                        self.demand_eqtype_pat(pat.span, expected, local_ty, match_discrim_span);
+                        self.demand_eqtype_pat(pat.span, expected, local_ty, discrim_span);
                     }
                 }
 
@@ -268,11 +273,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // what the type of the binding `x` ought to be
                 if var_id != pat.hir_id {
                     let vt = self.local_ty(pat.span, var_id).decl_ty;
-                    self.demand_eqtype_pat(pat.span, vt, local_ty, match_discrim_span);
+                    self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span);
                 }
 
                 if let Some(ref p) = *sub {
-                    self.check_pat_walk(&p, expected, def_bm, match_discrim_span);
+                    self.check_pat_walk(&p, expected, def_bm, discrim_span);
                 }
 
                 local_ty
@@ -285,14 +290,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     ddpos,
                     expected,
                     def_bm,
-                    match_discrim_span,
+                    discrim_span,
                 )
             }
             PatKind::Path(ref qpath) => {
                 self.check_pat_path(pat, qpath, expected)
             }
             PatKind::Struct(ref qpath, ref fields, etc) => {
-                self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, match_discrim_span)
+                self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span)
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -318,7 +323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // further errors being emitted when using the bindings. #50333
                     let element_tys_iter = (0..max_len).map(|_| tcx.types.err);
                     for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                        self.check_pat_walk(elem, &tcx.types.err, def_bm, match_discrim_span);
+                        self.check_pat_walk(elem, &tcx.types.err, def_bm, discrim_span);
                     }
                     tcx.mk_tup(element_tys_iter)
                 } else {
@@ -327,7 +332,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             elem,
                             &element_tys[i].expect_ty(),
                             def_bm,
-                            match_discrim_span,
+                            discrim_span,
                         );
                     }
                     pat_ty
@@ -341,11 +346,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // Here, `demand::subtype` is good enough, but I don't
                     // think any errors can be introduced by using
                     // `demand::eqtype`.
-                    self.demand_eqtype_pat(pat.span, expected, uniq_ty, match_discrim_span);
-                    self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span);
+                    self.demand_eqtype_pat(pat.span, expected, uniq_ty, discrim_span);
+                    self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span);
                     uniq_ty
                 } else {
-                    self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span);
+                    self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span);
                     tcx.types.err
                 }
             }
@@ -384,10 +389,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     };
 
-                    self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span);
+                    self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span);
                     rptr_ty
                 } else {
-                    self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span);
+                    self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span);
                     tcx.types.err
                 }
             }
@@ -445,13 +450,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
 
                 for elt in before {
-                    self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span);
+                    self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span);
                 }
                 if let Some(ref slice) = *slice {
-                    self.check_pat_walk(&slice, slice_ty, def_bm, match_discrim_span);
+                    self.check_pat_walk(&slice, slice_ty, def_bm, discrim_span);
                 }
                 for elt in after {
-                    self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span);
+                    self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span);
                 }
                 expected_ty
             }
@@ -595,73 +600,26 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
-        // Not entirely obvious: if matches may create ref bindings, we want to
-        // use the *precise* type of the discriminant, *not* some supertype, as
-        // the "discriminant type" (issue #23116).
-        //
-        // arielb1 [writes here in this comment thread][c] that there
-        // is certainly *some* potential danger, e.g., for an example
-        // like:
-        //
-        // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956
-        //
-        // ```
-        // let Foo(x) = f()[0];
-        // ```
-        //
-        // Then if the pattern matches by reference, we want to match
-        // `f()[0]` as a lexpr, so we can't allow it to be
-        // coerced. But if the pattern matches by value, `f()[0]` is
-        // still syntactically a lexpr, but we *do* want to allow
-        // coercions.
-        //
-        // However, *likely* we are ok with allowing coercions to
-        // happen if there are no explicit ref mut patterns - all
-        // implicit ref mut patterns must occur behind a reference, so
-        // they will have the "correct" variance and lifetime.
-        //
-        // This does mean that the following pattern would be legal:
-        //
-        // ```
-        // struct Foo(Bar);
-        // struct Bar(u32);
-        // impl Deref for Foo {
-        //     type Target = Bar;
-        //     fn deref(&self) -> &Bar { &self.0 }
-        // }
-        // impl DerefMut for Foo {
-        //     fn deref_mut(&mut self) -> &mut Bar { &mut self.0 }
-        // }
-        // fn foo(x: &mut Foo) {
-        //     {
-        //         let Bar(z): &mut Bar = x;
-        //         *z = 42;
-        //     }
-        //     assert_eq!(foo.0.0, 42);
-        // }
-        // ```
-        //
-        // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
-        // is problematic as the HIR is being scraped, but ref bindings may be
-        // implicit after #42640. We need to make sure that pat_adjustments
-        // (once introduced) is populated by the time we get here.
-        //
-        // See #44848.
-        let contains_ref_bindings = arms.iter()
-                                        .filter_map(|a| a.contains_explicit_ref_binding())
-                                        .max_by_key(|m| match *m {
-                                            hir::MutMutable => 1,
-                                            hir::MutImmutable => 0,
-                                        });
-        let discrim_ty;
-        if let Some(m) = contains_ref_bindings {
-            discrim_ty = self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m));
+        use hir::MatchSource::*;
+        let (source_if, if_no_else, if_desugar) = match match_src {
+            IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
+            IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false),
+            _ => (false, false, false),
+        };
+
+        // Type check the descriminant and get its type.
+        let discrim_ty = if if_desugar {
+            // Here we want to ensure:
+            //
+            // 1. That default match bindings are *not* accepted in the condition of an
+            //    `if` expression. E.g. given `fn foo() -> &bool;` we reject `if foo() { .. }`.
+            //
+            // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`.
+            //
+            // FIXME(60707): Consider removing hack with principled solution.
+            self.check_expr_has_type_or_error(discrim, self.tcx.types.bool)
         } else {
-            // ...but otherwise we want to use any supertype of the
-            // discriminant. This is sort of a workaround, see note (*) in
-            // `check_pat` for some details.
-            discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
-            self.check_expr_has_type_or_error(discrim, discrim_ty);
+            self.demand_discriminant_type(arms, discrim)
         };
 
         // If there are no arms, that is a diverging match; a special case.
@@ -670,11 +628,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             return tcx.types.never;
         }
 
-        if self.diverges.get().always() {
-            for arm in arms {
-                self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm");
-            }
-        }
+        self.warn_arms_when_scrutinee_diverges(arms, source_if);
 
         // Otherwise, we have to union together the types that the
         // arms produce and so forth.
@@ -687,12 +641,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             let mut all_pats_diverge = Diverges::WarnedAlways;
             for p in &arm.pats {
                 self.diverges.set(Diverges::Maybe);
-                self.check_pat_walk(
-                    &p,
-                    discrim_ty,
-                    ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
-                    Some(discrim.span),
-                );
+                let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable);
+                self.check_pat_walk(&p, discrim_ty, binding_mode, Some(discrim.span));
                 all_pats_diverge &= self.diverges.get();
             }
 
@@ -734,7 +684,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         let mut other_arms = vec![];  // used only for diagnostics
         let mut prior_arm_ty = None;
         for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
-            if let Some(ref g) = arm.guard {
+            if let Some(g) = &arm.guard {
                 self.diverges.set(pats_diverge);
                 match g {
                     hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool),
@@ -745,43 +695,44 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
             all_arms_diverge &= self.diverges.get();
 
-            // Handle the fallback arm of a desugared if-let like a missing else.
-            let is_if_let_fallback = match match_src {
-                hir::MatchSource::IfLetDesugar { contains_else_clause: false } => {
-                    i == arms.len() - 1 && arm_ty.is_unit()
+            let span = expr.span;
+
+            if source_if {
+                let then_expr = &arms[0].body;
+                match (i, if_no_else) {
+                    (0, _) => coercion.coerce(self, &self.misc(span), then_expr, arm_ty),
+                    (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion),
+                    (_, _) => {
+                        let then_ty = prior_arm_ty.unwrap();
+                        let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty);
+                        coercion.coerce(self, &cause, &arm.body, arm_ty);
+                    }
                 }
-                _ => false
-            };
-
-            let arm_span = if let hir::ExprKind::Block(ref blk, _) = arm.body.node {
-                // Point at the block expr instead of the entire block
-                blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span)
-            } else {
-                arm.body.span
-            };
-            if is_if_let_fallback {
-                let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse);
-                assert!(arm_ty.is_unit());
-                coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
             } else {
-                let cause = if i == 0 {
+                let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.node {
+                    // Point at the block expr instead of the entire block
+                    blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span)
+                } else {
+                    arm.body.span
+                };
+                let (span, code) = match i {
                     // The reason for the first arm to fail is not that the match arms diverge,
                     // but rather that there's a prior obligation that doesn't hold.
-                    self.cause(arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id))
-                } else {
-                    self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
+                    0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
+                    _ => (span, ObligationCauseCode::MatchExpressionArm {
                         arm_span,
                         source: match_src,
                         prior_arms: other_arms.clone(),
                         last_ty: prior_arm_ty.unwrap(),
                         discrim_hir_id: discrim.hir_id,
-                    })
+                    }),
                 };
+                let cause = self.cause(span, code);
                 coercion.coerce(self, &cause, &arm.body, arm_ty);
-            }
-            other_arms.push(arm_span);
-            if other_arms.len() > 5 {
-                other_arms.remove(0);
+                other_arms.push(arm_span);
+                if other_arms.len() > 5 {
+                    other_arms.remove(0);
+                }
             }
             prior_arm_ty = Some(arm_ty);
         }
@@ -792,6 +743,251 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         coercion.complete(self)
     }
 
+    /// When the previously checked expression (the scrutinee) diverges,
+    /// warn the user about the match arms being unreachable.
+    fn warn_arms_when_scrutinee_diverges(&self, arms: &'gcx [hir::Arm], source_if: bool) {
+        if self.diverges.get().always() {
+            let msg = if source_if { "block in `if` expression" } else { "arm" };
+            for arm in arms {
+                self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg);
+            }
+        }
+    }
+
+    /// Handle the fallback arm of a desugared if(-let) like a missing else.
+    fn if_fallback_coercion(
+        &self,
+        span: Span,
+        then_expr: &'gcx hir::Expr,
+        coercion: &mut CoerceMany<'gcx, 'tcx, '_, rustc::hir::Arm>,
+    ) {
+        // If this `if` expr is the parent's function return expr,
+        // the cause of the type coercion is the return type, point at it. (#25228)
+        let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
+        let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
+        coercion.coerce_forced_unit(self, &cause, &mut |err| {
+            if let Some((span, msg)) = &ret_reason {
+                err.span_label(*span, msg.as_str());
+            } else if let ExprKind::Block(block, _) = &then_expr.node {
+                if let Some(expr) = &block.expr {
+                    err.span_label(expr.span, "found here".to_string());
+                }
+            }
+            err.note("`if` expressions without `else` evaluate to `()`");
+            err.help("consider adding an `else` block that evaluates to the expected type");
+        }, ret_reason.is_none());
+    }
+
+    fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> {
+        use hir::Node::{Block, Item, Local};
+
+        let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id(
+            self.tcx.hir().get_parent_node_by_hir_id(hir_id),
+        ));
+        if let Block(block) = node {
+            // check that the body's parent is an fn
+            let parent = self.tcx.hir().get_by_hir_id(
+                self.tcx.hir().get_parent_node_by_hir_id(
+                    self.tcx.hir().get_parent_node_by_hir_id(block.hir_id),
+                ),
+            );
+            if let (Some(expr), Item(hir::Item {
+                node: hir::ItemKind::Fn(..), ..
+            })) = (&block.expr, parent) {
+                // check that the `if` expr without `else` is the fn body's expr
+                if expr.span == span {
+                    return self.get_fn_decl(hir_id).map(|(fn_decl, _)| (
+                        fn_decl.output.span(),
+                        format!("expected `{}` because of this return type", fn_decl.output),
+                    ));
+                }
+            }
+        }
+        if let Local(hir::Local { ty: Some(_), pat, .. }) = node {
+            return Some((pat.span, "expected because of this assignment".to_string()));
+        }
+        None
+    }
+
+    fn if_cause(
+        &self,
+        span: Span,
+        then_expr: &'gcx hir::Expr,
+        else_expr: &'gcx hir::Expr,
+        then_ty: Ty<'tcx>,
+        else_ty: Ty<'tcx>,
+    ) -> ObligationCause<'tcx> {
+        let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
+            // The `if`/`else` isn't in one line in the output, include some context to make it
+            // clear it is an if/else expression:
+            // ```
+            // LL |      let x = if true {
+            //    | _____________-
+            // LL ||         10i32
+            //    ||         ----- expected because of this
+            // LL ||     } else {
+            // LL ||         10u32
+            //    ||         ^^^^^ expected i32, found u32
+            // LL ||     };
+            //    ||_____- if and else have incompatible types
+            // ```
+            Some(span)
+        } else {
+            // The entire expression is in one line, only point at the arms
+            // ```
+            // LL |     let x = if true { 10i32 } else { 10u32 };
+            //    |                       -----          ^^^^^ expected i32, found u32
+            //    |                       |
+            //    |                       expected because of this
+            // ```
+            None
+        };
+
+        let mut remove_semicolon = None;
+        let error_sp = if let ExprKind::Block(block, _) = &else_expr.node {
+            if let Some(expr) = &block.expr {
+                expr.span
+            } else if let Some(stmt) = block.stmts.last() {
+                // possibly incorrect trailing `;` in the else arm
+                remove_semicolon = self.could_remove_semicolon(block, then_ty);
+                stmt.span
+            } else {  // empty block, point at its entirety
+                // Avoid overlapping spans that aren't as readable:
+                // ```
+                // 2 |        let x = if true {
+                //   |   _____________-
+                // 3 |  |         3
+                //   |  |         - expected because of this
+                // 4 |  |     } else {
+                //   |  |____________^
+                // 5 | ||
+                // 6 | ||     };
+                //   | ||     ^
+                //   | ||_____|
+                //   | |______if and else have incompatible types
+                //   |        expected integer, found ()
+                // ```
+                // by not pointing at the entire expression:
+                // ```
+                // 2 |       let x = if true {
+                //   |               ------- if and else have incompatible types
+                // 3 |           3
+                //   |           - expected because of this
+                // 4 |       } else {
+                //   |  ____________^
+                // 5 | |
+                // 6 | |     };
+                //   | |_____^ expected integer, found ()
+                // ```
+                if outer_sp.is_some() {
+                    outer_sp = Some(self.tcx.sess.source_map().def_span(span));
+                }
+                else_expr.span
+            }
+        } else { // shouldn't happen unless the parser has done something weird
+            else_expr.span
+        };
+
+        // Compute `Span` of `then` part of `if`-expression:
+        let then_sp = if let ExprKind::Block(block, _) = &then_expr.node {
+            if let Some(expr) = &block.expr {
+                expr.span
+            } else if let Some(stmt) = block.stmts.last() {
+                // possibly incorrect trailing `;` in the else arm
+                remove_semicolon = remove_semicolon.or(self.could_remove_semicolon(block, else_ty));
+                stmt.span
+            } else {  // empty block, point at its entirety
+                outer_sp = None;  // same as in `error_sp`, cleanup output
+                then_expr.span
+            }
+        } else {  // shouldn't happen unless the parser has done something weird
+            then_expr.span
+        };
+
+        // Finally construct the cause:
+        self.cause(error_sp, ObligationCauseCode::IfExpression {
+            then: then_sp,
+            outer: outer_sp,
+            semicolon: remove_semicolon,
+        })
+    }
+
+    fn demand_discriminant_type(
+        &self,
+        arms: &'gcx [hir::Arm],
+        discrim: &'gcx hir::Expr,
+    ) -> Ty<'tcx> {
+        // Not entirely obvious: if matches may create ref bindings, we want to
+        // use the *precise* type of the discriminant, *not* some supertype, as
+        // the "discriminant type" (issue #23116).
+        //
+        // arielb1 [writes here in this comment thread][c] that there
+        // is certainly *some* potential danger, e.g., for an example
+        // like:
+        //
+        // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956
+        //
+        // ```
+        // let Foo(x) = f()[0];
+        // ```
+        //
+        // Then if the pattern matches by reference, we want to match
+        // `f()[0]` as a lexpr, so we can't allow it to be
+        // coerced. But if the pattern matches by value, `f()[0]` is
+        // still syntactically a lexpr, but we *do* want to allow
+        // coercions.
+        //
+        // However, *likely* we are ok with allowing coercions to
+        // happen if there are no explicit ref mut patterns - all
+        // implicit ref mut patterns must occur behind a reference, so
+        // they will have the "correct" variance and lifetime.
+        //
+        // This does mean that the following pattern would be legal:
+        //
+        // ```
+        // struct Foo(Bar);
+        // struct Bar(u32);
+        // impl Deref for Foo {
+        //     type Target = Bar;
+        //     fn deref(&self) -> &Bar { &self.0 }
+        // }
+        // impl DerefMut for Foo {
+        //     fn deref_mut(&mut self) -> &mut Bar { &mut self.0 }
+        // }
+        // fn foo(x: &mut Foo) {
+        //     {
+        //         let Bar(z): &mut Bar = x;
+        //         *z = 42;
+        //     }
+        //     assert_eq!(foo.0.0, 42);
+        // }
+        // ```
+        //
+        // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
+        // is problematic as the HIR is being scraped, but ref bindings may be
+        // implicit after #42640. We need to make sure that pat_adjustments
+        // (once introduced) is populated by the time we get here.
+        //
+        // See #44848.
+        let contains_ref_bindings = arms.iter()
+                                        .filter_map(|a| a.contains_explicit_ref_binding())
+                                        .max_by_key(|m| match *m {
+                                            hir::MutMutable => 1,
+                                            hir::MutImmutable => 0,
+                                        });
+
+        if let Some(m) = contains_ref_bindings {
+            self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m))
+        } else {
+            // ...but otherwise we want to use any supertype of the
+            // discriminant. This is sort of a workaround, see note (*) in
+            // `check_pat` for some details.
+            let discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
+            self.check_expr_has_type_or_error(discrim, discrim_ty);
+            discrim_ty
+        }
+    }
+
     fn check_pat_struct(
         &self,
         pat: &'gcx hir::Pat,
@@ -800,7 +996,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
         etc: bool,
         expected: Ty<'tcx>,
         def_bm: ty::BindingMode,
-        match_discrim_span: Option<Span>,
+        discrim_span: Option<Span>,
     ) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
@@ -809,18 +1005,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
             variant_ty
         } else {
             for field in fields {
-                self.check_pat_walk(
-                    &field.node.pat,
-                    self.tcx.types.err,
-                    def_bm,
-                    match_discrim_span,
-                );
+                self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, discrim_span);
             }
             return self.tcx.types.err;
         };
 
         // Type-check the path.
-        self.demand_eqtype_pat(pat.span, expected, pat_ty, match_discrim_span);
+        self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span);
 
         // Type-check subpatterns.
         if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm)
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index d21ceb983f8..90b2643d165 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -68,6 +68,7 @@ use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
 use syntax::feature_gate;
 use syntax::ptr::P;
+use syntax::symbol::sym;
 use syntax_pos;
 
 struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
@@ -620,7 +621,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
         if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
             feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
-                                           "unsized_tuple_coercion",
+                                           sym::unsized_tuple_coercion,
                                            self.cause.span,
                                            feature_gate::GateIssue::Language,
                                            feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION);
@@ -1248,12 +1249,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
                     augment_error(&mut db);
                 }
 
-                if expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some() {
-                    // Error reported in `check_assign` so avoid emitting error again.
-                    db.delay_as_bug();
-                } else {
-                    db.emit();
-                }
+                // Error possibly reported in `check_assign` so avoid emitting error again.
+                db.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some());
 
                 self.final_ty = Some(fcx.tcx.types.err);
             }
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 1699447886a..8d68179b495 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -2,6 +2,7 @@ use crate::check::FnCtxt;
 use rustc::infer::InferOk;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 
+use syntax::symbol::sym;
 use syntax::util::parser::PREC_POSTFIX;
 use syntax_pos::Span;
 use rustc::hir;
@@ -197,7 +198,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 //
                 // FIXME? Other potential candidate methods: `as_ref` and
                 // `as_mut`?
-                .find(|a| a.check_name("rustc_conversion_suggestion")).is_some()
+                .find(|a| a.check_name(sym::rustc_conversion_suggestion)).is_some()
         });
 
         methods
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 40c60caffa4..c6191e6b579 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -7,7 +7,7 @@ use rustc::ty::subst::Subst;
 use crate::require_same_types;
 
 use rustc_target::spec::abi::Abi;
-use syntax::symbol::Symbol;
+use syntax::symbol::InternedString;
 
 use rustc::hir;
 
@@ -80,7 +80,7 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
 /// and in libcore/intrinsics.rs
 pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       it: &hir::ForeignItem) {
-    let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
+    let param = |n| tcx.mk_ty_param(n, InternedString::intern(&format!("P{}", n)));
     let name = it.ident.as_str();
 
     let mk_va_list_ty = || {
@@ -397,7 +397,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                it: &hir::ForeignItem) {
     let param = |n| {
-        let name = Symbol::intern(&format!("P{}", n)).as_interned_str();
+        let name = InternedString::intern(&format!("P{}", n));
         tcx.mk_ty_param(n, name)
     };
 
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index b57ae361eb6..77d2ffab8ef 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -91,14 +91,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     CandidateSource::ImplSource(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
-                        let item = self.associated_item(impl_did, item_name, Namespace::Value)
-                            .or_else(|| {
-                                self.associated_item(
-                                    self.tcx.impl_trait_ref(impl_did).unwrap().def_id,
-                                    item_name,
-                                    Namespace::Value,
-                                )
-                            }).unwrap();
+                        let item = match self.associated_item(
+                            impl_did,
+                            item_name,
+                            Namespace::Value,
+                        ).or_else(|| {
+                            let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+                            self.associated_item(
+                                impl_trait_ref.def_id,
+                                item_name,
+                                Namespace::Value,
+                            )
+                        }) {
+                            Some(item) => item,
+                            None => continue,
+                        };
                         let note_span = self.tcx.hir().span_if_local(item.def_id).or_else(|| {
                             self.tcx.hir().span_if_local(impl_did)
                         });
@@ -132,9 +139,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        let item = self
-                            .associated_item(trait_did, item_name, Namespace::Value)
-                            .unwrap();
+                        let item = match self.associated_item(
+                            trait_did,
+                            item_name,
+                            Namespace::Value)
+                        {
+                            Some(item) => item,
+                            None => continue,
+                        };
                         let item_span = self.tcx.sess.source_map()
                             .def_span(self.tcx.def_span(item.def_id));
                         if sources.len() > 1 {
@@ -251,8 +263,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 if let &QPath::Resolved(_, ref path) = &qpath {
                                     if let hir::def::Res::Local(hir_id) = path.res {
                                         let span = tcx.hir().span_by_hir_id(hir_id);
-                                        let snippet = tcx.sess.source_map().span_to_snippet(span)
-                                            .unwrap();
+                                        let snippet = tcx.sess.source_map().span_to_snippet(span);
                                         let filename = tcx.sess.source_map().span_to_filename(span);
 
                                         let parent_node = self.tcx.hir().get_by_hir_id(
@@ -263,12 +274,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                             concrete_type,
                                         );
 
-                                        match (filename, parent_node) {
+                                        match (filename, parent_node, snippet) {
                                             (FileName::Real(_), Node::Local(hir::Local {
                                                 source: hir::LocalSource::Normal,
                                                 ty,
                                                 ..
-                                            })) => {
+                                            }), Ok(ref snippet)) => {
                                                 err.span_suggestion(
                                                     // account for `let x: _ = 42;`
                                                     //                  ^^^^
@@ -375,14 +386,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id),
                                 );
 
-                                let span = call_expr.span.trim_start(item_name.span).unwrap();
-
-                                err.span_suggestion(
-                                    span,
-                                    "remove the arguments",
-                                    String::new(),
-                                    Applicability::MaybeIncorrect,
-                                );
+                                if let Some(span) = call_expr.span.trim_start(item_name.span) {
+                                    err.span_suggestion(
+                                        span,
+                                        "remove the arguments",
+                                        String::new(),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
                             }
                         }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 965f52be31c..362b6f0504d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -117,12 +117,13 @@ use rustc::ty::subst::{UnpackedKind, Subst, InternalSubsts, SubstsRef, UserSelfT
 use rustc::ty::util::{Representability, IntTypeExt, Discr};
 use rustc::ty::layout::VariantIdx;
 use syntax_pos::{self, BytePos, Span, MultiSpan};
+use syntax_pos::hygiene::CompilerDesugaringKind;
 use syntax::ast;
 use syntax::attr;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
 use syntax::source_map::{DUMMY_SP, original_sp};
-use syntax::symbol::{Symbol, LocalInternedString, keywords};
+use syntax::symbol::{Symbol, LocalInternedString, keywords, sym};
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use std::cell::{Cell, RefCell, Ref, RefMut};
@@ -1086,12 +1087,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // Add formal parameters.
     for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
         // Check the pattern.
-        fcx.check_pat_walk(
-            &arg.pat,
-            arg_ty,
-            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
-            None,
-        );
+        let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable);
+        fcx.check_pat_walk(&arg.pat, arg_ty, binding_mode, None);
 
         // Check that argument is Sized.
         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
@@ -1843,7 +1840,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     if vs.is_empty() {
         let attributes = tcx.get_attrs(def_id);
-        if let Some(attr) = attr::find_by_name(&attributes, "repr") {
+        if let Some(attr) = attr::find_by_name(&attributes, sym::repr) {
             struct_span_err!(
                 tcx.sess, attr.span, E0084,
                 "unsupported representation for zero-variant enum")
@@ -1856,7 +1853,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
         if !tcx.features().repr128 {
             emit_feature_err(&tcx.sess.parse_sess,
-                             "repr128",
+                             sym::repr128,
                              sp,
                              GateIssue::Language,
                              "repr with 128-bit type is unstable");
@@ -2045,15 +2042,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// Produces warning on the given node, if the current point in the
     /// function is unreachable, and there hasn't been another warning.
     fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
-        if self.diverges.get() == Diverges::Always {
+        if self.diverges.get() == Diverges::Always &&
+            // If span arose from a desugaring of `if` then it is the condition itself,
+            // which diverges, that we are about to lint on. This gives suboptimal diagnostics
+            // and so we stop here and allow the block of the `if`-expression to be linted instead.
+            !span.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary) {
             self.diverges.set(Diverges::WarnedAlways);
 
             debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
 
-            self.tcx().lint_hir(
-                lint::builtin::UNREACHABLE_CODE,
-                id, span,
-                &format!("unreachable {}", kind));
+            let msg = format!("unreachable {}", kind);
+            self.tcx().lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg);
         }
     }
 
@@ -3084,7 +3083,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     // AST fragment checking
     fn check_lit(&self,
-                 lit: &ast::Lit,
+                 lit: &hir::Lit,
                  expected: Expectation<'tcx>)
                  -> Ty<'tcx>
     {
@@ -3161,13 +3160,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
 
         if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) {
-            if self.is_assign_to_bool(expr, expected_ty) {
-                // Error reported in `check_assign` so avoid emitting error again.
-                // FIXME(centril): Consider removing if/when `if` desugars to `match`.
-                err.delay_as_bug();
-            } else {
-                err.emit();
-            }
+            let expr = match &expr.node {
+                ExprKind::DropTemps(expr) => expr,
+                _ => expr,
+            };
+            // Error possibly reported in `check_assign` so avoid emitting error again.
+            err.emit_unless(self.is_assign_to_bool(expr, expected_ty));
         }
         ty
     }
@@ -3330,194 +3328,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             return_expr_ty);
     }
 
-    // A generic function for checking the 'then' and 'else' clauses in an 'if'
-    // or 'if-else' expression.
-    fn check_then_else(&self,
-                       cond_expr: &'gcx hir::Expr,
-                       then_expr: &'gcx hir::Expr,
-                       opt_else_expr: Option<&'gcx hir::Expr>,
-                       sp: Span,
-                       expected: Expectation<'tcx>) -> Ty<'tcx> {
-        let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool);
-        let cond_diverges = self.diverges.get();
-        self.diverges.set(Diverges::Maybe);
-
-        let expected = expected.adjust_for_branches(self);
-        let then_ty = self.check_expr_with_expectation(then_expr, expected);
-        let then_diverges = self.diverges.get();
-        self.diverges.set(Diverges::Maybe);
-
-        // We've already taken the expected type's preferences
-        // into account when typing the `then` branch. To figure
-        // out the initial shot at a LUB, we thus only consider
-        // `expected` if it represents a *hard* constraint
-        // (`only_has_type`); otherwise, we just go with a
-        // fresh type variable.
-        let coerce_to_ty = expected.coercion_target_type(self, sp);
-        let mut coerce: DynamicCoerceMany<'_, '_> = CoerceMany::new(coerce_to_ty);
-
-        coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
-
-        if let Some(else_expr) = opt_else_expr {
-            let else_ty = self.check_expr_with_expectation(else_expr, expected);
-            let else_diverges = self.diverges.get();
-
-            let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) {
-                // The `if`/`else` isn't in one line in the output, include some context to make it
-                // clear it is an if/else expression:
-                // ```
-                // LL |      let x = if true {
-                //    | _____________-
-                // LL ||         10i32
-                //    ||         ----- expected because of this
-                // LL ||     } else {
-                // LL ||         10u32
-                //    ||         ^^^^^ expected i32, found u32
-                // LL ||     };
-                //    ||_____- if and else have incompatible types
-                // ```
-                Some(sp)
-            } else {
-                // The entire expression is in one line, only point at the arms
-                // ```
-                // LL |     let x = if true { 10i32 } else { 10u32 };
-                //    |                       -----          ^^^^^ expected i32, found u32
-                //    |                       |
-                //    |                       expected because of this
-                // ```
-                None
-            };
-            let mut remove_semicolon = None;
-            let error_sp = if let ExprKind::Block(block, _) = &else_expr.node {
-                if let Some(expr) = &block.expr {
-                    expr.span
-                } else if let Some(stmt) = block.stmts.last() {
-                    // possibly incorrect trailing `;` in the else arm
-                    remove_semicolon = self.could_remove_semicolon(block, then_ty);
-                    stmt.span
-                } else {  // empty block, point at its entirety
-                    // Avoid overlapping spans that aren't as readable:
-                    // ```
-                    // 2 |        let x = if true {
-                    //   |   _____________-
-                    // 3 |  |         3
-                    //   |  |         - expected because of this
-                    // 4 |  |     } else {
-                    //   |  |____________^
-                    // 5 | ||
-                    // 6 | ||     };
-                    //   | ||     ^
-                    //   | ||_____|
-                    //   | |______if and else have incompatible types
-                    //   |        expected integer, found ()
-                    // ```
-                    // by not pointing at the entire expression:
-                    // ```
-                    // 2 |       let x = if true {
-                    //   |               ------- if and else have incompatible types
-                    // 3 |           3
-                    //   |           - expected because of this
-                    // 4 |       } else {
-                    //   |  ____________^
-                    // 5 | |
-                    // 6 | |     };
-                    //   | |_____^ expected integer, found ()
-                    // ```
-                    if outer_sp.is_some() {
-                        outer_sp = Some(self.tcx.sess.source_map().def_span(sp));
-                    }
-                    else_expr.span
-                }
-            } else { // shouldn't happen unless the parser has done something weird
-                else_expr.span
-            };
-            let then_sp = if let ExprKind::Block(block, _) = &then_expr.node {
-                if let Some(expr) = &block.expr {
-                    expr.span
-                } else if let Some(stmt) = block.stmts.last() {
-                    // possibly incorrect trailing `;` in the else arm
-                    remove_semicolon = remove_semicolon.or(
-                        self.could_remove_semicolon(block, else_ty));
-                    stmt.span
-                } else {  // empty block, point at its entirety
-                    outer_sp = None;  // same as in `error_sp`, cleanup output
-                    then_expr.span
-                }
-            } else {  // shouldn't happen unless the parser has done something weird
-                then_expr.span
-            };
-
-            let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression {
-                then: then_sp,
-                outer: outer_sp,
-                semicolon: remove_semicolon,
-            });
-
-            coerce.coerce(self, &if_cause, else_expr, else_ty);
-
-            // We won't diverge unless both branches do (or the condition does).
-            self.diverges.set(cond_diverges | then_diverges & else_diverges);
-        } else {
-            // If this `if` expr is the parent's function return expr, the cause of the type
-            // coercion is the return type, point at it. (#25228)
-            let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, sp);
-
-            let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse);
-            coerce.coerce_forced_unit(self, &else_cause, &mut |err| {
-                if let Some((sp, msg)) = &ret_reason {
-                    err.span_label(*sp, msg.as_str());
-                } else if let ExprKind::Block(block, _) = &then_expr.node {
-                    if let Some(expr) = &block.expr {
-                        err.span_label(expr.span, "found here".to_string());
-                    }
-                }
-                err.note("`if` expressions without `else` evaluate to `()`");
-                err.help("consider adding an `else` block that evaluates to the expected type");
-            }, ret_reason.is_none());
-
-            // If the condition is false we can't diverge.
-            self.diverges.set(cond_diverges);
-        }
-
-        let result_ty = coerce.complete(self);
-        if cond_ty.references_error() {
-            self.tcx.types.err
-        } else {
-            result_ty
-        }
-    }
-
-    fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
-        let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id(
-            self.tcx.hir().get_parent_node_by_hir_id(hir_id),
-        ));
-        if let Node::Block(block) = node {
-            // check that the body's parent is an fn
-            let parent = self.tcx.hir().get_by_hir_id(
-                self.tcx.hir().get_parent_node_by_hir_id(
-                    self.tcx.hir().get_parent_node_by_hir_id(block.hir_id),
-                ),
-            );
-            if let (Some(expr), Node::Item(hir::Item {
-                node: hir::ItemKind::Fn(..), ..
-            })) = (&block.expr, parent) {
-                // check that the `if` expr without `else` is the fn body's expr
-                if expr.span == sp {
-                    return self.get_fn_decl(hir_id).map(|(fn_decl, _)| (
-                        fn_decl.output.span(),
-                        format!("expected `{}` because of this return type", fn_decl.output),
-                    ));
-                }
-            }
-        }
-        if let Node::Local(hir::Local {
-            ty: Some(_), pat, ..
-        }) = node {
-            return Some((pat.span, "expected because of this assignment".to_string()));
-        }
-        None
-    }
-
     // Check field access expressions
     fn check_field(&self,
                    expr: &'gcx hir::Expr,
@@ -4062,7 +3872,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match expr.node {
             ExprKind::Block(..) |
             ExprKind::Loop(..) | ExprKind::While(..) |
-            ExprKind::If(..) | ExprKind::Match(..) => {}
+            ExprKind::Match(..) => {}
 
             _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression")
         }
@@ -4387,7 +4197,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         // ... except when we try to 'break rust;'.
                         // ICE this expression in particular (see #43162).
                         if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.node {
-                            if path.segments.len() == 1 && path.segments[0].ident.name == "rust" {
+                            if path.segments.len() == 1 &&
+                               path.segments[0].ident.name == sym::rust {
                                 fatally_break_rust(self.tcx.sess);
                             }
                         }
@@ -4444,10 +4255,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ExprKind::Assign(ref lhs, ref rhs) => {
                 self.check_assign(expr, expected, lhs, rhs)
             }
-            ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => {
-                self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e),
-                                     expr.span, expected)
-            }
             ExprKind::While(ref cond, ref body, _) => {
                 let ctxt = BreakableCtxt {
                     // cannot use break with a value from a while loop
@@ -5261,7 +5068,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             match expression.node {
                 ExprKind::Call(..) |
                 ExprKind::MethodCall(..) |
-                ExprKind::If(..) |
                 ExprKind::While(..) |
                 ExprKind::Loop(..) |
                 ExprKind::Match(..) |
@@ -5669,10 +5475,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
-                    span_bug!(span,
+                    self.tcx.sess.delay_span_bug(span, &format!(
                         "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
                         self_ty,
-                        impl_ty);
+                        impl_ty,
+                    ));
                 }
             }
         }
@@ -5693,7 +5500,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                       span: Span) {
         // We're only interested in functions tagged with
         // #[rustc_args_required_const], so ignore anything that's not.
-        if !self.tcx.has_attr(def_id, "rustc_args_required_const") {
+        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
             return
         }
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index d1ca0578093..cd207478f8f 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -305,8 +305,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             };
                             if let Some(missing_trait) = missing_trait {
                                 if op.node == hir::BinOpKind::Add &&
-                                    self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                            rhs_ty, &mut err, true, op) {
+                                    self.check_str_addition(
+                                        lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op) {
                                     // This has nothing here because it means we did string
                                     // concatenation (e.g., "Hello " += "World!"). This means
                                     // we don't want the note in the else clause to be emitted
@@ -400,8 +400,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             };
                             if let Some(missing_trait) = missing_trait {
                                 if op.node == hir::BinOpKind::Add &&
-                                    self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
-                                                            rhs_ty, &mut err, false, op) {
+                                    self.check_str_addition(
+                                        lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op) {
                                     // This has nothing here because it means we did string
                                     // concatenation (e.g., "Hello " + "World!"). This means
                                     // we don't want the note in the else clause to be emitted
@@ -502,9 +502,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         false
     }
 
+    /// Provide actionable suggestions when trying to add two strings with incorrect types,
+    /// like `&str + &str`, `String + String` and `&str + &String`.
+    ///
+    /// If this function returns `true` it means a note was printed, so we don't need
+    /// to print the normal "implementation of `std::ops::Add` might be missing" note
     fn check_str_addition(
         &self,
-        expr: &'gcx hir::Expr,
         lhs_expr: &'gcx hir::Expr,
         rhs_expr: &'gcx hir::Expr,
         lhs_ty: Ty<'tcx>,
@@ -514,45 +518,78 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         op: hir::BinOp,
     ) -> bool {
         let source_map = self.tcx.sess.source_map();
+        let remove_borrow_msg = "String concatenation appends the string on the right to the \
+                                 string on the left and may require reallocation. This \
+                                 requires ownership of the string on the left";
+
         let msg = "`to_owned()` can be used to create an owned `String` \
                    from a string reference. String concatenation \
                    appends the string on the right to the string \
                    on the left and may require reallocation. This \
                    requires ownership of the string on the left";
-        // If this function returns true it means a note was printed, so we don't need
-        // to print the normal "implementation of `std::ops::Add` might be missing" note
+
+        let is_std_string = |ty| &format!("{:?}", ty) == "std::string::String";
+
         match (&lhs_ty.sty, &rhs_ty.sty) {
-            (&Ref(_, l_ty, _), &Ref(_, r_ty, _))
-            if l_ty.sty == Str && r_ty.sty == Str => {
-                if !is_assign {
-                    err.span_label(op.span,
-                                   "`+` can't be used to concatenate two `&str` strings");
+            (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str
+                if (l_ty.sty == Str || is_std_string(l_ty)) && (
+                        r_ty.sty == Str || is_std_string(r_ty) ||
+                        &format!("{:?}", rhs_ty) == "&&str"
+                    ) =>
+            {
+                if !is_assign { // Do not supply this message if `&str += &str`
+                    err.span_label(
+                        op.span,
+                        "`+` cannot be used to concatenate two `&str` strings",
+                    );
                     match source_map.span_to_snippet(lhs_expr.span) {
-                        Ok(lstring) => err.span_suggestion(
-                            lhs_expr.span,
-                            msg,
-                            format!("{}.to_owned()", lstring),
-                            Applicability::MachineApplicable,
-                        ),
+                        Ok(lstring) => {
+                            err.span_suggestion(
+                                lhs_expr.span,
+                                if lstring.starts_with("&") {
+                                    remove_borrow_msg
+                                } else {
+                                    msg
+                                },
+                                if lstring.starts_with("&") {
+                                    // let a = String::new();
+                                    // let _ = &a + "bar";
+                                    format!("{}", &lstring[1..])
+                                } else {
+                                    format!("{}.to_owned()", lstring)
+                                },
+                                Applicability::MachineApplicable,
+                            )
+                        }
                         _ => err.help(msg),
                     };
                 }
                 true
             }
-            (&Ref(_, l_ty, _), &Adt(..))
-            if l_ty.sty == Str && &format!("{:?}", rhs_ty) == "std::string::String" => {
-                err.span_label(expr.span,
-                    "`+` can't be used to concatenate a `&str` with a `String`");
+            (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String`
+                if (l_ty.sty == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) =>
+            {
+                err.span_label(
+                    op.span,
+                    "`+` cannot be used to concatenate a `&str` with a `String`",
+                );
                 match (
                     source_map.span_to_snippet(lhs_expr.span),
                     source_map.span_to_snippet(rhs_expr.span),
                     is_assign,
                 ) {
                     (Ok(l), Ok(r), false) => {
+                        let to_string = if l.starts_with("&") {
+                            // let a = String::new(); let b = String::new();
+                            // let _ = &a + b;
+                            format!("{}", &l[1..])
+                        } else {
+                            format!("{}.to_owned()", l)
+                        };
                         err.multipart_suggestion(
                             msg,
                             vec![
-                                (lhs_expr.span, format!("{}.to_owned()", l)),
+                                (lhs_expr.span, to_string),
                                 (rhs_expr.span, format!("&{}", r)),
                             ],
                             Applicability::MachineApplicable,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index fd7d6fe694c..b009c8ea6dc 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -13,6 +13,7 @@ use rustc::infer::opaque_types::may_define_existential_type;
 use syntax::ast;
 use syntax::feature_gate::{self, GateIssue};
 use syntax_pos::Span;
+use syntax::symbol::sym;
 use errors::{DiagnosticBuilder, DiagnosticId};
 
 use rustc::hir::itemlikevisit::ParItemLikeVisitor;
@@ -796,7 +797,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
                 // report error, would have worked with arbitrary_self_types
                 feature_gate::feature_err(
                     &fcx.tcx.sess.parse_sess,
-                    "arbitrary_self_types",
+                    sym::arbitrary_self_types,
                     span,
                     GateIssue::Language,
                     &format!(
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index f9d83146e30..13baf667808 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -16,6 +16,7 @@ use rustc::mir::interpret::ConstValue;
 use rustc::util::nodemap::DefIdSet;
 use rustc_data_structures::sync::Lrc;
 use std::mem;
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 ///////////////////////////////////////////////////////////////////////////
@@ -36,8 +37,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let item_def_id = self.tcx.hir().local_def_id(item_id);
 
         // This attribute causes us to dump some writeback information
-        // in the form of errors, which is used for unit tests.
-        let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, "rustc_dump_user_substs");
+        // in the form of errors, which is uSymbolfor unit tests.
+        let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs);
 
         let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);
         for arg in &body.arguments {
@@ -465,6 +466,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap();
             let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id);
 
+            debug_assert!(!instantiated_ty.has_escaping_bound_vars());
+
             let generics = self.tcx().generics_of(def_id);
 
             let definition_ty = if generics.parent.is_some() {
@@ -523,8 +526,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                     },
                     lt_op: |region| {
                         match region {
-                            // ignore static regions
-                            ty::ReStatic => region,
+                            // Skip static and bound regions: they don't
+                            // require substitution.
+                            ty::ReStatic | ty::ReLateBound(..) => region,
                             _ => {
                                 trace!("checking {:?}", region);
                                 for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) {
@@ -611,26 +615,33 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                 }
             }
 
-            let new = ty::ResolvedOpaqueTy {
-                concrete_type: definition_ty,
-                substs: self.tcx().lift_to_global(&opaque_defn.substs).unwrap(),
-            };
-
-            let old = self.tables
-                .concrete_existential_types
-                .insert(def_id, new);
-            if let Some(old) = old {
-                if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
-                    span_bug!(
-                        span,
-                        "visit_opaque_types tried to write \
-                        different types for the same existential type: {:?}, {:?}, {:?}, {:?}",
-                        def_id,
-                        definition_ty,
-                        opaque_defn,
-                        old,
-                    );
+            if let Some(substs) = self.tcx().lift_to_global(&opaque_defn.substs) {
+                let new = ty::ResolvedOpaqueTy {
+                    concrete_type: definition_ty,
+                    substs,
+                };
+
+                let old = self.tables
+                    .concrete_existential_types
+                    .insert(def_id, new);
+                if let Some(old) = old {
+                    if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
+                        span_bug!(
+                            span,
+                            "visit_opaque_types tried to write \
+                            different types for the same existential type: {:?}, {:?}, {:?}, {:?}",
+                            def_id,
+                            definition_ty,
+                            opaque_defn,
+                            old,
+                        );
+                    }
                 }
+            } else {
+                self.tcx().sess.delay_span_bug(
+                    span,
+                    "cannot lift `opaque_defn` substs to global type context",
+                );
             }
         }
     }
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index cbb6d9b29f5..3c3509f24ce 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -158,6 +158,13 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
             continue;
         }
 
+        // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
+        // would not insert the new name into the prelude, where other imports in the crate may be
+        // expecting it.
+        if extern_crate.orig_name.is_some() {
+            continue;
+        }
+
         // If the extern crate has any attributes, they may have funky
         // semantics we can't faithfully represent using `use` (most
         // notably `#[macro_use]`). Ignore it.
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index d0156db32e9..a9951c7fe44 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -5,8 +5,6 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::traits::{self, IntercrateMode};
 use rustc::ty::TyCtxt;
 
-use crate::lint;
-
 pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     crate_num: CrateNum) {
     assert_eq!(crate_num, LOCAL_CRATE);
@@ -20,8 +18,7 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
     fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId,
-                                       overlap: traits::OverlapResult<'_>,
-                                       used_to_be_allowed: bool) {
+                                       overlap: traits::OverlapResult<'_>) {
 
         let name_and_namespace = |def_id| {
             let item = self.tcx.associated_item(def_id);
@@ -36,22 +33,12 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
 
             for &item2 in &impl_items2[..] {
                 if (name, namespace) == name_and_namespace(item2) {
-                    let hir_id = self.tcx.hir().as_local_hir_id(impl1);
-                    let mut err = if used_to_be_allowed && hir_id.is_some() {
-                        self.tcx.struct_span_lint_hir(
-                            lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
-                            hir_id.unwrap(),
-                            self.tcx.span_of_impl(item1).unwrap(),
-                            &format!("duplicate definitions with name `{}` (E0592)", name)
-                        )
-                    } else {
+                    let mut err =
                         struct_span_err!(self.tcx.sess,
                                          self.tcx.span_of_impl(item1).unwrap(),
                                          E0592,
                                          "duplicate definitions with name `{}`",
-                                         name)
-                    };
-
+                                         name);
                     err.span_label(self.tcx.span_of_impl(item1).unwrap(),
                                    format!("duplicate definitions for `{}`", name));
                     err.span_label(self.tcx.span_of_impl(item2).unwrap(),
@@ -76,7 +63,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                let used_to_be_allowed = traits::overlapping_impls(
+                traits::overlapping_impls(
                     self.tcx,
                     impl1_def_id,
                     impl2_def_id,
@@ -86,28 +73,11 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
                             impl1_def_id,
                             impl2_def_id,
                             overlap,
-                            false,
                         );
                         false
                     },
                     || true,
                 );
-
-                if used_to_be_allowed {
-                    traits::overlapping_impls(
-                        self.tcx,
-                        impl1_def_id,
-                        impl2_def_id,
-                        IntercrateMode::Fixed,
-                        |overlap| self.check_for_common_items_in_impls(
-                            impl1_def_id,
-                            impl2_def_id,
-                            overlap,
-                            true,
-                        ),
-                        || (),
-                    );
-                }
             }
         }
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 4185999fdd6..711d79f95f5 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -39,7 +39,7 @@ use syntax::ast::{Ident, MetaItemKind};
 use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used};
 use syntax::source_map::Spanned;
 use syntax::feature_gate;
-use syntax::symbol::{keywords, Symbol};
+use syntax::symbol::{InternedString, keywords, Symbol, sym};
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::def::{CtorKind, Res, DefKind};
@@ -750,7 +750,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
-    let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
+    let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
     if paren_sugar && !tcx.features().unboxed_closures {
         let mut err = tcx.sess.struct_span_err(
             item.span,
@@ -765,7 +765,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::
         err.emit();
     }
 
-    let is_marker = tcx.has_attr(def_id, "marker");
+    let is_marker = tcx.has_attr(def_id, sym::marker);
     let def_path_hash = tcx.def_path_hash(def_id);
     let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash);
     tcx.alloc_trait_def(def)
@@ -1082,7 +1082,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
                 .enumerate()
                 .map(|(i, &arg)| ty::GenericParamDef {
                     index: type_start + i as u32,
-                    name: Symbol::intern(arg).as_interned_str(),
+                    name: InternedString::intern(arg),
                     def_id,
                     pure_wrt_drop: false,
                     kind: ty::GenericParamDefKind::Type {
@@ -1097,7 +1097,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
             params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
                 ty::GenericParamDef {
                     index: type_start + i,
-                    name: Symbol::intern("<upvar>").as_interned_str(),
+                    name: InternedString::intern("<upvar>"),
                     def_id,
                     pure_wrt_drop: false,
                     kind: ty::GenericParamDefKind::Type {
@@ -1404,7 +1404,13 @@ pub fn checked_type_of<'a, 'tcx>(
                                     if !fail {
                                         return None;
                                     }
-                                    bug!("unexpected const parent path def {:?}", x);
+                                    tcx.sess.delay_span_bug(
+                                        DUMMY_SP,
+                                        &format!(
+                                            "unexpected const parent path def {:?}", x
+                                        ),
+                                    );
+                                    tcx.types.err
                                 }
                             }
                         }
@@ -1412,7 +1418,13 @@ pub fn checked_type_of<'a, 'tcx>(
                             if !fail {
                                 return None;
                             }
-                            bug!("unexpected const parent path {:?}", x);
+                            tcx.sess.delay_span_bug(
+                                DUMMY_SP,
+                                &format!(
+                                    "unexpected const parent path {:?}", x
+                                ),
+                            );
+                            tcx.types.err
                         }
                     }
                 }
@@ -1421,7 +1433,13 @@ pub fn checked_type_of<'a, 'tcx>(
                     if !fail {
                         return None;
                     }
-                    bug!("unexpected const parent in type_of_def_id(): {:?}", x);
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!(
+                            "unexpected const parent in type_of_def_id(): {:?}", x
+                        ),
+                    );
+                    tcx.types.err
                 }
             }
         }
@@ -2382,7 +2400,7 @@ fn from_target_feature(
     tcx: TyCtxt<'_, '_, '_>,
     id: DefId,
     attr: &ast::Attribute,
-    whitelist: &FxHashMap<String, Option<String>>,
+    whitelist: &FxHashMap<String, Option<Symbol>>,
     target_features: &mut Vec<Symbol>,
 ) {
     let list = match attr.meta_item_list() {
@@ -2392,7 +2410,7 @@ fn from_target_feature(
     let rust_features = tcx.features();
     for item in list {
         // Only `enable = ...` is accepted in the meta item list
-        if !item.check_name("enable") {
+        if !item.check_name(sym::enable) {
             let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
                        currently";
             tcx.sess.span_err(item.span(), &msg);
@@ -2435,29 +2453,29 @@ fn from_target_feature(
             };
 
             // Only allow features whose feature gates have been enabled
-            let allowed = match feature_gate.as_ref().map(|s| &**s) {
-                Some("arm_target_feature") => rust_features.arm_target_feature,
-                Some("aarch64_target_feature") => rust_features.aarch64_target_feature,
-                Some("hexagon_target_feature") => rust_features.hexagon_target_feature,
-                Some("powerpc_target_feature") => rust_features.powerpc_target_feature,
-                Some("mips_target_feature") => rust_features.mips_target_feature,
-                Some("avx512_target_feature") => rust_features.avx512_target_feature,
-                Some("mmx_target_feature") => rust_features.mmx_target_feature,
-                Some("sse4a_target_feature") => rust_features.sse4a_target_feature,
-                Some("tbm_target_feature") => rust_features.tbm_target_feature,
-                Some("wasm_target_feature") => rust_features.wasm_target_feature,
-                Some("cmpxchg16b_target_feature") => rust_features.cmpxchg16b_target_feature,
-                Some("adx_target_feature") => rust_features.adx_target_feature,
-                Some("movbe_target_feature") => rust_features.movbe_target_feature,
-                Some("rtm_target_feature") => rust_features.rtm_target_feature,
-                Some("f16c_target_feature") => rust_features.f16c_target_feature,
+            let allowed = match feature_gate.as_ref().map(|s| *s) {
+                Some(sym::arm_target_feature) => rust_features.arm_target_feature,
+                Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,
+                Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
+                Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
+                Some(sym::mips_target_feature) => rust_features.mips_target_feature,
+                Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
+                Some(sym::mmx_target_feature) => rust_features.mmx_target_feature,
+                Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
+                Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
+                Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
+                Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
+                Some(sym::adx_target_feature) => rust_features.adx_target_feature,
+                Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
+                Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
+                Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
             if !allowed && id.is_local() {
                 feature_gate::emit_feature_err(
                     &tcx.sess.parse_sess,
-                    feature_gate.as_ref().unwrap(),
+                    feature_gate.unwrap(),
                     item.span(),
                     feature_gate::GateIssue::Language,
                     &format!("the target feature `{}` is currently unstable", feature),
@@ -2512,13 +2530,13 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
 
     let mut inline_span = None;
     for attr in attrs.iter() {
-        if attr.check_name("cold") {
+        if attr.check_name(sym::cold) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
-        } else if attr.check_name("allocator") {
+        } else if attr.check_name(sym::allocator) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
-        } else if attr.check_name("unwind") {
+        } else if attr.check_name(sym::unwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
-        } else if attr.check_name("ffi_returns_twice") {
+        } else if attr.check_name(sym::ffi_returns_twice) {
             if tcx.is_foreign_item(id) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
             } else {
@@ -2530,21 +2548,21 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                     "`#[ffi_returns_twice]` may only be used on foreign functions"
                 ).emit();
             }
-        } else if attr.check_name("rustc_allocator_nounwind") {
+        } else if attr.check_name(sym::rustc_allocator_nounwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
-        } else if attr.check_name("naked") {
+        } else if attr.check_name(sym::naked) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
-        } else if attr.check_name("no_mangle") {
+        } else if attr.check_name(sym::no_mangle) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
-        } else if attr.check_name("rustc_std_internal_symbol") {
+        } else if attr.check_name(sym::rustc_std_internal_symbol) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
-        } else if attr.check_name("no_debug") {
+        } else if attr.check_name(sym::no_debug) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_DEBUG;
-        } else if attr.check_name("used") {
+        } else if attr.check_name(sym::used) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
-        } else if attr.check_name("thread_local") {
+        } else if attr.check_name(sym::thread_local) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
-        } else if attr.check_name("export_name") {
+        } else if attr.check_name(sym::export_name) {
             if let Some(s) = attr.value_str() {
                 if s.as_str().contains("\0") {
                     // `#[export_name = ...]` will be converted to a null-terminated string,
@@ -2558,7 +2576,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                 }
                 codegen_fn_attrs.export_name = Some(s);
             }
-        } else if attr.check_name("target_feature") {
+        } else if attr.check_name(sym::target_feature) {
             if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
                 let msg = "#[target_feature(..)] can only be applied to \
                            `unsafe` function";
@@ -2571,11 +2589,11 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                 &whitelist,
                 &mut codegen_fn_attrs.target_features,
             );
-        } else if attr.check_name("linkage") {
+        } else if attr.check_name(sym::linkage) {
             if let Some(val) = attr.value_str() {
                 codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
             }
-        } else if attr.check_name("link_section") {
+        } else if attr.check_name(sym::link_section) {
             if let Some(val) = attr.value_str() {
                 if val.as_str().bytes().any(|b| b == 0) {
                     let msg = format!(
@@ -2588,13 +2606,13 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                     codegen_fn_attrs.link_section = Some(val);
                 }
             }
-        } else if attr.check_name("link_name") {
+        } else if attr.check_name(sym::link_name) {
             codegen_fn_attrs.link_name = attr.value_str();
         }
     }
 
     codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
-        if attr.path != "inline" {
+        if attr.path != sym::inline {
             return ia;
         }
         match attr.meta().map(|i| i.node) {
@@ -2613,9 +2631,9 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                         "expected one argument"
                     );
                     InlineAttr::None
-                } else if list_contains_name(&items[..], "always") {
+                } else if list_contains_name(&items[..], sym::always) {
                     InlineAttr::Always
-                } else if list_contains_name(&items[..], "never") {
+                } else if list_contains_name(&items[..], sym::never) {
                     InlineAttr::Never
                 } else {
                     span_err!(
@@ -2634,7 +2652,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
     });
 
     codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
-        if attr.path != "optimize" {
+        if attr.path != sym::optimize {
             return ia;
         }
         let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s);
@@ -2649,9 +2667,9 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
                 if items.len() != 1 {
                     err(attr.span, "expected one argument");
                     OptimizeAttr::None
-                } else if list_contains_name(&items[..], "size") {
+                } else if list_contains_name(&items[..], sym::size) {
                     OptimizeAttr::Size
-                } else if list_contains_name(&items[..], "speed") {
+                } else if list_contains_name(&items[..], sym::speed) {
                     OptimizeAttr::Speed
                 } else {
                     err(items[0].span(), "invalid argument");
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index e3e2fe7106a..a6b5b99982e 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -5,6 +5,7 @@ use rustc::ty::query::Providers;
 use rustc::ty::subst::UnpackedKind;
 use rustc::ty::{self, CratePredicatesMap, TyCtxt};
 use rustc_data_structures::sync::Lrc;
+use syntax::symbol::sym;
 
 mod explicit;
 mod implicit_infer;
@@ -40,7 +41,7 @@ fn inferred_outlives_of<'a, 'tcx>(
                     .map(|p| *p)
                     .unwrap_or(&[]);
 
-                if tcx.has_attr(item_def_id, "rustc_outlives") {
+                if tcx.has_attr(item_def_id, sym::rustc_outlives) {
                     let mut pred: Vec<String> = predicates
                         .iter()
                         .map(|out_pred| match out_pred {
diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs
index e10c8361207..54fd4fad1d1 100644
--- a/src/librustc_typeck/outlives/test.rs
+++ b/src/librustc_typeck/outlives/test.rs
@@ -1,6 +1,7 @@
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::ty::TyCtxt;
+use syntax::symbol::sym;
 
 pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.hir()
@@ -18,7 +19,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
 
         // For unit testing: check for a special "rustc_outlives"
         // attribute and report an error with various results if found.
-        if self.tcx.has_attr(item_def_id, "rustc_outlives") {
+        if self.tcx.has_attr(item_def_id, sym::rustc_outlives) {
             let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
             span_err!(
                 self.tcx.sess,
diff --git a/src/librustc_typeck/variance/test.rs b/src/librustc_typeck/variance/test.rs
index d04b1b276a2..b5195826b86 100644
--- a/src/librustc_typeck/variance/test.rs
+++ b/src/librustc_typeck/variance/test.rs
@@ -1,6 +1,7 @@
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::ty::TyCtxt;
+use syntax::symbol::sym;
 
 pub fn test_variance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx });
@@ -16,7 +17,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> {
 
         // For unit testing: check for a special "rustc_variance"
         // attribute and report an error with various results if found.
-        if self.tcx.has_attr(item_def_id, "rustc_variance") {
+        if self.tcx.has_attr(item_def_id, sym::rustc_variance) {
             let variances_of = self.tcx.variances_of(item_def_id);
             span_err!(self.tcx.sess,
                       item.span,
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 69445451503..61399e0568c 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -7,7 +7,7 @@ use std::mem;
 use std::fmt::{self, Write};
 use std::ops;
 
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind};
 use syntax::parse::ParseSess;
 use syntax::feature_gate::Features;
@@ -186,7 +186,7 @@ impl Cfg {
 
     fn should_use_with_in_description(&self) -> bool {
         match *self {
-            Cfg::Cfg(ref name, _) if name == &"target_feature" => true,
+            Cfg::Cfg(name, _) if name == sym::target_feature => true,
             _ => false,
         }
     }
@@ -338,7 +338,6 @@ impl<'a> fmt::Display for Html<'a> {
                     ("debug_assertions", None) => "debug-assertions enabled",
                     ("target_os", Some(os)) => match &*os.as_str() {
                         "android" => "Android",
-                        "bitrig" => "Bitrig",
                         "dragonfly" => "DragonFly BSD",
                         "emscripten" => "Emscripten",
                         "freebsd" => "FreeBSD",
@@ -414,10 +413,11 @@ impl<'a> fmt::Display for Html<'a> {
 mod test {
     use super::Cfg;
 
-    use syntax::symbol::Symbol;
+    use syntax_pos::DUMMY_SP;
     use syntax::ast::*;
+    use syntax::attr;
     use syntax::source_map::dummy_spanned;
-    use syntax_pos::DUMMY_SP;
+    use syntax::symbol::Symbol;
     use syntax::with_globals;
 
     fn word_cfg(s: &str) -> Cfg {
@@ -592,14 +592,10 @@ mod test {
             let mi = dummy_meta_item_word("all");
             assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
 
-            let mi = MetaItem {
-                path: Path::from_ident(Ident::from_str("all")),
-                node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str(
-                    Symbol::intern("done"),
-                    StrStyle::Cooked,
-                ))),
-                span: DUMMY_SP,
-            };
+            let mi = attr::mk_name_value_item_str(
+                Ident::from_str("all"),
+                dummy_spanned(Symbol::intern("done"))
+            );
             assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done")));
 
             let mi = dummy_meta_item_list!(all, [a, b]);
@@ -627,11 +623,12 @@ mod test {
     #[test]
     fn test_parse_err() {
         with_globals(|| {
-            let mi = MetaItem {
-                path: Path::from_ident(Ident::from_str("foo")),
-                node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))),
-                span: DUMMY_SP,
-            };
+            let mi = attr::mk_name_value_item(
+                DUMMY_SP,
+                Ident::from_str("foo"),
+                LitKind::Bool(false),
+                DUMMY_SP,
+            );
             assert!(Cfg::parse(&mi).is_err());
 
             let mi = dummy_meta_item_list!(not, [a, b]);
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d9d6b8e07e9..15108a7dbb9 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -4,6 +4,7 @@ use std::iter::once;
 
 use syntax::ast;
 use syntax::ext::base::{MacroKind, SyntaxExtension};
+use syntax::symbol::sym;
 use syntax_pos::Span;
 
 use rustc::hir;
@@ -186,7 +187,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
     let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
-    let is_spotlight = load_attrs(cx, did).has_doc_flag("spotlight");
+    let is_spotlight = load_attrs(cx, did).has_doc_flag(sym::spotlight);
     let is_auto = cx.tcx.trait_is_auto(did);
     clean::Trait {
         auto: auto_trait,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3a260db8065..e434623d4a1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -32,6 +32,7 @@ use syntax::ext::base::MacroKind;
 use syntax::source_map::{dummy_spanned, Spanned};
 use syntax::ptr::P;
 use syntax::symbol::keywords::{self, Keyword};
+use syntax::symbol::{Symbol, sym};
 use syntax::symbol::InternedString;
 use syntax_pos::{self, Pos, FileName};
 
@@ -170,7 +171,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
                     // `compiler_builtins` should be masked too, but we can't apply
                     // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
                     if it.is_extern_crate()
-                        && (it.attrs.has_doc_flag("masked")
+                        && (it.attrs.has_doc_flag(sym::masked)
                             || self.cx.tcx.is_compiler_builtins(it.def_id.krate))
                     {
                         masked_crates.insert(it.def_id.krate);
@@ -261,9 +262,9 @@ impl Clean<ExternalCrate> for CrateNum {
             if let Res::Def(DefKind::Mod, def_id) = res {
                 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
                 let mut prim = None;
-                for attr in attrs.lists("doc") {
+                for attr in attrs.lists(sym::doc) {
                     if let Some(v) = attr.value_str() {
-                        if attr.check_name("primitive") {
+                        if attr.check_name(sym::primitive) {
                             prim = PrimitiveType::from_str(&v.as_str());
                             if prim.is_some() {
                                 break;
@@ -305,9 +306,9 @@ impl Clean<ExternalCrate> for CrateNum {
             if let Res::Def(DefKind::Mod, def_id) = res {
                 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
                 let mut keyword = None;
-                for attr in attrs.lists("doc") {
+                for attr in attrs.lists(sym::doc) {
                     if let Some(v) = attr.value_str() {
-                        if attr.check_name("keyword") {
+                        if attr.check_name(sym::keyword) {
                             keyword = Keyword::from_str(&v.as_str()).ok()
                                                                     .map(|x| x.name().to_string());
                             if keyword.is_some() {
@@ -501,7 +502,7 @@ impl Item {
 
     pub fn is_non_exhaustive(&self) -> bool {
         self.attrs.other_attrs.iter()
-            .any(|a| a.check_name("non_exhaustive"))
+            .any(|a| a.check_name(sym::non_exhaustive))
     }
 
     /// Returns a documentation-level item type from the item.
@@ -669,7 +670,7 @@ impl Clean<Item> for doctree::Module {
 pub struct ListAttributesIter<'a> {
     attrs: slice::Iter<'a, ast::Attribute>,
     current_list: vec::IntoIter<ast::NestedMetaItem>,
-    name: &'a str
+    name: Symbol,
 }
 
 impl<'a> Iterator for ListAttributesIter<'a> {
@@ -702,11 +703,11 @@ impl<'a> Iterator for ListAttributesIter<'a> {
 
 pub trait AttributesExt {
     /// Finds an attribute as List and returns the list of attributes nested inside.
-    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
+    fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a>;
 }
 
 impl AttributesExt for [ast::Attribute] {
-    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
+    fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> {
         ListAttributesIter {
             attrs: self.iter(),
             current_list: Vec::new().into_iter(),
@@ -717,11 +718,11 @@ impl AttributesExt for [ast::Attribute] {
 
 pub trait NestedAttributesExt {
     /// Returns `true` if the attribute list contains a specific `Word`
-    fn has_word(self, word: &str) -> bool;
+    fn has_word(self, word: Symbol) -> bool;
 }
 
 impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
-    fn has_word(self, word: &str) -> bool {
+    fn has_word(self, word: Symbol) -> bool {
         self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
     }
 }
@@ -803,7 +804,7 @@ impl Attributes {
         if let ast::MetaItemKind::List(ref nmis) = mi.node {
             if nmis.len() == 1 {
                 if let MetaItem(ref cfg_mi) = nmis[0] {
-                    if cfg_mi.check_name("cfg") {
+                    if cfg_mi.check_name(sym::cfg) {
                         if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node {
                             if cfg_nmis.len() == 1 {
                                 if let MetaItem(ref content_mi) = cfg_nmis[0] {
@@ -827,7 +828,7 @@ impl Attributes {
     {
         mi.meta_item_list().and_then(|list| {
             for meta in list {
-                if meta.check_name("include") {
+                if meta.check_name(sym::include) {
                     // the actual compiled `#[doc(include="filename")]` gets expanded to
                     // `#[doc(include(file="filename", contents="file contents")]` so we need to
                     // look for that instead
@@ -836,11 +837,11 @@ impl Attributes {
                         let mut contents: Option<String> = None;
 
                         for it in list {
-                            if it.check_name("file") {
+                            if it.check_name(sym::file) {
                                 if let Some(name) = it.value_str() {
                                     filename = Some(name.to_string());
                                 }
-                            } else if it.check_name("contents") {
+                            } else if it.check_name(sym::contents) {
                                 if let Some(docs) = it.value_str() {
                                     contents = Some(docs.to_string());
                                 }
@@ -860,9 +861,9 @@ impl Attributes {
         })
     }
 
-    pub fn has_doc_flag(&self, flag: &str) -> bool {
+    pub fn has_doc_flag(&self, flag: Symbol) -> bool {
         for attr in &self.other_attrs {
-            if !attr.check_name("doc") { continue; }
+            if !attr.check_name(sym::doc) { continue; }
 
             if let Some(items) = attr.meta_item_list() {
                 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
@@ -883,7 +884,7 @@ impl Attributes {
 
         let other_attrs = attrs.iter().filter_map(|attr| {
             attr.with_desugared_doc(|attr| {
-                if attr.check_name("doc") {
+                if attr.check_name(sym::doc) {
                     if let Some(mi) = attr.meta() {
                         if let Some(value) = mi.value_str() {
                             // Extracted #[doc = "..."]
@@ -925,11 +926,12 @@ impl Attributes {
 
         // treat #[target_feature(enable = "feat")] attributes as if they were
         // #[doc(cfg(target_feature = "feat"))] attributes as well
-        for attr in attrs.lists("target_feature") {
-            if attr.check_name("enable") {
+        for attr in attrs.lists(sym::target_feature) {
+            if attr.check_name(sym::enable) {
                 if let Some(feat) = attr.value_str() {
-                    let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"),
-                                                            dummy_spanned(feat));
+                    let meta = attr::mk_name_value_item_str(
+                        Ident::with_empty_ctxt(sym::target_feature),
+                        dummy_spanned(feat));
                     if let Ok(feat_cfg) = Cfg::parse(&meta) {
                         cfg &= feat_cfg;
                     }
@@ -938,7 +940,7 @@ impl Attributes {
         }
 
         let inner_docs = attrs.iter()
-                              .filter(|a| a.check_name("doc"))
+                              .filter(|a| a.check_name(sym::doc))
                               .next()
                               .map_or(true, |a| a.style == AttrStyle::Inner);
 
@@ -1039,7 +1041,7 @@ impl Hash for Attributes {
 }
 
 impl AttributesExt for Attributes {
-    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
+    fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> {
         self.other_attrs.lists(name)
     }
 }
@@ -2133,7 +2135,7 @@ pub struct Trait {
 impl Clean<Item> for doctree::Trait {
     fn clean(&self, cx: &DocContext<'_>) -> Item {
         let attrs = self.attrs.clean(cx);
-        let is_spotlight = attrs.has_doc_flag("spotlight");
+        let is_spotlight = attrs.has_doc_flag(sym::spotlight);
         Item {
             name: Some(self.name.clean(cx)),
             attrs: attrs,
@@ -3147,7 +3149,10 @@ impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
     fn clean(&self, cx: &DocContext<'_>) -> Constant {
         Constant {
             type_: self.ty.clean(cx),
-            expr: format!("{:?}", self.val), // FIXME(const_generics)
+            expr: match self.val {
+                ConstValue::Param(ty::ParamConst { name, .. }) => format!("{}", name),
+                e => format!("{:?}", e), // FIXME generic consts with expressions
+            },
         }
     }
 }
@@ -3403,6 +3408,7 @@ pub struct Span {
     pub locol: usize,
     pub hiline: usize,
     pub hicol: usize,
+    pub original: syntax_pos::Span,
 }
 
 impl Span {
@@ -3411,8 +3417,13 @@ impl Span {
             filename: FileName::Anon(0),
             loline: 0, locol: 0,
             hiline: 0, hicol: 0,
+            original: syntax_pos::DUMMY_SP,
         }
     }
+
+    pub fn span(&self) -> syntax_pos::Span {
+        self.original
+    }
 }
 
 impl Clean<Span> for syntax_pos::Span {
@@ -3431,6 +3442,7 @@ impl Clean<Span> for syntax_pos::Span {
             locol: lo.col.to_usize(),
             hiline: hi.line,
             hicol: hi.col.to_usize(),
+            original: *self,
         }
     }
 }
@@ -3893,8 +3905,8 @@ impl Clean<Vec<Item>> for doctree::ExternCrate {
     fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
 
         let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| {
-            a.check_name("doc") && match a.meta_item_list() {
-                Some(l) => attr::list_contains_name(&l, "inline"),
+            a.check_name(sym::doc) && match a.meta_item_list() {
+                Some(l) => attr::list_contains_name(&l, sym::inline),
                 None => false,
             }
         });
@@ -3935,15 +3947,15 @@ impl Clean<Vec<Item>> for doctree::Import {
         // #[doc(no_inline)] attribute is present.
         // Don't inline doc(hidden) imports so they can be stripped at a later stage.
         let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| {
-            a.check_name("doc") && match a.meta_item_list() {
-                Some(l) => attr::list_contains_name(&l, "no_inline") ||
-                           attr::list_contains_name(&l, "hidden"),
+            a.check_name(sym::doc) && match a.meta_item_list() {
+                Some(l) => attr::list_contains_name(&l, sym::no_inline) ||
+                           attr::list_contains_name(&l, sym::hidden),
                 None => false,
             }
         });
         // Also check whether imports were asked to be inlined, in case we're trying to re-export a
         // crate in Rust 2018+
-        let please_inline = self.attrs.lists("doc").has_word("inline");
+        let please_inline = self.attrs.lists(sym::doc).has_word(sym::inline);
         let path = self.path.clean(cx);
         let inner = if self.glob {
             if !denied {
@@ -4382,7 +4394,7 @@ where
 
 // Start of code copied from rust-clippy
 
-pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
+pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option<DefId> {
     let krate = tcx.hir().krate();
     let mut items = krate.module.item_ids.clone();
     let mut path_it = path.iter().peekable();
@@ -4407,7 +4419,7 @@ pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId
     }
 }
 
-pub fn path_to_def(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
+pub fn path_to_def(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option<DefId> {
     let crates = tcx.crates();
 
     let krate = crates
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 72421c9decc..6b490f730af 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -13,7 +13,7 @@ use rustc::session::config::{nightly_options, build_codegen_options, build_debug
 use rustc::session::search_paths::SearchPath;
 use rustc_driver;
 use rustc_target::spec::TargetTriple;
-use syntax::edition::Edition;
+use syntax::edition::{Edition, DEFAULT_EDITION};
 
 use crate::core::new_handler;
 use crate::externalfiles::ExternalHtml;
@@ -386,6 +386,18 @@ impl Options {
             }
         }
 
+        let edition = if let Some(e) = matches.opt_str("edition") {
+            match e.parse() {
+                Ok(e) => e,
+                Err(_) => {
+                    diag.struct_err("could not parse edition").emit();
+                    return Err(1);
+                }
+            }
+        } else {
+            DEFAULT_EDITION
+        };
+
         let mut id_map = html::markdown::IdMap::new();
         id_map.populate(html::render::initial_ids());
         let external_html = match ExternalHtml::load(
@@ -393,20 +405,12 @@ impl Options {
                 &matches.opt_strs("html-before-content"),
                 &matches.opt_strs("html-after-content"),
                 &matches.opt_strs("markdown-before-content"),
-                &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
+                &matches.opt_strs("markdown-after-content"),
+                &diag, &mut id_map, edition) {
             Some(eh) => eh,
             None => return Err(3),
         };
 
-        let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
-        let edition = match edition.parse() {
-            Ok(e) => e,
-            Err(_) => {
-                diag.struct_err("could not parse edition").emit();
-                return Err(1);
-            }
-        };
-
         match matches.opt_str("r").as_ref().map(|s| &**s) {
             Some("rust") | None => {}
             Some(s) => {
@@ -538,7 +542,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler)
        "passes",
     ];
 
-    for flag in deprecated_flags.into_iter() {
+    for flag in deprecated_flags.iter() {
         if matches.opt_present(flag) {
             let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
                                                     flag));
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index e91e3a029da..2a3bc5e9961 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -18,6 +18,7 @@ use rustc_target::spec::TargetTriple;
 use syntax::source_map;
 use syntax::feature_gate::UnstableFeatures;
 use syntax::json::JsonEmitter;
+use syntax::symbol::sym;
 use errors;
 use errors::emitter::{Emitter, EmitterWriter};
 use parking_lot::ReentrantMutex;
@@ -142,7 +143,7 @@ impl<'tcx> DocContext<'tcx> {
             crate_num,
             DefId {
                 krate: crate_num,
-                index: DefIndex::from_array_index(def_id.index.as_array_index() + 1),
+                index: DefIndex::from(def_id.index.index() + 1),
             },
         );
 
@@ -367,9 +368,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
             };
 
             let send_trait = if crate_name == Some("core".to_string()) {
-                clean::path_to_def_local(tcx, &["marker", "Send"])
+                clean::path_to_def_local(tcx, &[sym::marker, sym::Send])
             } else {
-                clean::path_to_def(tcx, &["core", "marker", "Send"])
+                clean::path_to_def(tcx, &[sym::core, sym::marker, sym::Send])
             };
 
             let mut renderinfo = RenderInfo::default();
@@ -415,24 +416,24 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
 
             // Process all of the crate attributes, extracting plugin metadata along
             // with the passes which we are supposed to run.
-            for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
+            for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) {
                 let diag = ctxt.sess().diagnostic();
 
                 let name = attr.name_or_empty();
                 if attr.is_word() {
-                    if name == "no_default_passes" {
+                    if name == sym::no_default_passes {
                         report_deprecated_attr("no_default_passes", diag);
                         if default_passes == passes::DefaultPassOption::Default {
                             default_passes = passes::DefaultPassOption::None;
                         }
                     }
                 } else if let Some(value) = attr.value_str() {
-                    let sink = match name.get() {
-                        "passes" => {
+                    let sink = match name {
+                        sym::passes => {
                             report_deprecated_attr("passes = \"...\"", diag);
                             &mut manual_passes
                         },
-                        "plugins" => {
+                        sym::plugins => {
                             report_deprecated_attr("plugins = \"...\"", diag);
                             eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \
                                       see CVE-2018-1000622");
@@ -445,7 +446,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                     }
                 }
 
-                if attr.is_word() && name == "document_private_items" {
+                if attr.is_word() && name == sym::document_private_items {
                     if default_passes == passes::DefaultPassOption::Default {
                         default_passes = passes::DefaultPassOption::Private;
                     }
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 0378b12662d..d604ba11d41 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -3,6 +3,7 @@ use std::path::Path;
 use std::str;
 use errors;
 use crate::syntax::feature_gate::UnstableFeatures;
+use crate::syntax::edition::Edition;
 use crate::html::markdown::{IdMap, ErrorCodes, Markdown};
 
 use std::cell::RefCell;
@@ -23,7 +24,7 @@ pub struct ExternalHtml {
 impl ExternalHtml {
     pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
                 md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler,
-                id_map: &mut IdMap)
+                id_map: &mut IdMap, edition: Edition)
             -> Option<ExternalHtml> {
         let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
         load_external_files(in_header, diag)
@@ -34,7 +35,8 @@ impl ExternalHtml {
             .and_then(|(ih, bc)|
                 load_external_files(md_before_content, diag)
                     .map(|m_bc| (ih,
-                            format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), codes))))
+                            format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map),
+                                    codes, edition))))
             )
             .and_then(|(ih, bc)|
                 load_external_files(after_content, diag)
@@ -43,7 +45,8 @@ impl ExternalHtml {
             .and_then(|(ih, bc, ac)|
                 load_external_files(md_after_content, diag)
                     .map(|m_ac| (ih, bc,
-                            format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), codes))))
+                            format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map),
+                                    codes, edition))))
             )
             .map(|(ih, bc, ac)|
                 ExternalHtml {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 3d8af7c7716..2784d5b3e10 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -262,9 +262,7 @@ impl fmt::Display for clean::Lifetime {
 
 impl fmt::Display for clean::Constant {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&self.expr, f)?;
-        f.write_str(": ")?;
-        fmt::Display::fmt(&self.type_, f)
+        fmt::Display::fmt(&self.expr, f)
     }
 }
 
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index d66455f91ba..5bb06516ac4 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -318,6 +318,8 @@ impl<'a> Classifier<'a> {
 
                     // Number literals.
                     token::Integer(..) | token::Float(..) => Class::Number,
+
+                    token::Bool(..) => panic!("literal token contains `Lit::Bool`"),
                 }
             }
 
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index acf019fd225..ae0bd1aafa8 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -182,14 +182,14 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
         let p = SlashChecker(&p);
         if layout.logo.is_empty() {
             format!("<a href='{path}index.html'>\
-                     <img src='{static_root_path}rust-logo{suffix}.png' \
-                          alt='logo' width='100'></a>",
+                     <div class='logo-container'>\
+                     <img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>",
                     path=p,
                     static_root_path=static_root_path,
                     suffix=page.resource_suffix)
         } else {
             format!("<a href='{}index.html'>\
-                     <img src='{}' alt='logo' width='100'></a>",
+                     <div class='logo-container'><img src='{}' alt='logo'></div></a>",
                     p,
                     layout.logo)
         }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index a3b041c6954..12d10254c4d 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -8,12 +8,16 @@
 //! ```
 //! #![feature(rustc_private)]
 //!
+//! extern crate syntax;
+//!
+//! use syntax::edition::Edition;
 //! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes};
 //! use std::cell::RefCell;
 //!
 //! let s = "My *markdown* _text_";
 //! let mut id_map = IdMap::new();
-//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), ErrorCodes::Yes));
+//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map),
+//!                                   ErrorCodes::Yes, Edition::Edition2015));
 //! // ... something using html
 //! ```
 
@@ -42,14 +46,21 @@ fn opts() -> Options {
 /// A unit struct which has the `fmt::Display` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
-/// The second parameter is a list of link replacements
+///
+/// The second parameter is a list of link replacements.
+///
+/// The third is the current list of used header IDs.
+///
+/// The fourth is whether to allow the use of explicit error codes in doctest lang strings.
+///
+/// The fifth is what default edition to use when parsing doctests (to add a `fn main`).
 pub struct Markdown<'a>(
-    pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes);
+    pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
-pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
+pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
 /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
-pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
+pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition);
 /// A unit struct like `Markdown`, that renders only the first paragraph.
 pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]);
 
@@ -146,13 +157,15 @@ thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> =
 struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
     inner: I,
     check_error_codes: ErrorCodes,
+    edition: Edition,
 }
 
 impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
-    fn new(iter: I, error_codes: ErrorCodes) -> Self {
+    fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self {
         CodeBlocks {
             inner: iter,
             check_error_codes: error_codes,
+            edition,
         }
     }
 }
@@ -177,6 +190,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
             return event;
         }
 
+        let explicit_edition = edition.is_some();
+        let edition = edition.unwrap_or(self.edition);
+
         let mut origtext = String::new();
         for event in &mut self.inner {
             match event {
@@ -202,22 +218,14 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                     .collect::<Vec<Cow<'_, str>>>().join("\n");
                 let krate = krate.as_ref().map(|s| &**s);
                 let (test, _) = test::make_test(&test, krate, false,
-                                           &Default::default());
+                                           &Default::default(), edition);
                 let channel = if test.contains("#![feature(") {
                     "&amp;version=nightly"
                 } else {
                     ""
                 };
 
-                let edition_string = if let Some(e @ Edition::Edition2018) = edition {
-                    format!("&amp;edition={}{}", e,
-                            if channel == "&amp;version=nightly" { "" }
-                            else { "&amp;version=nightly" })
-                } else if let Some(e) = edition {
-                    format!("&amp;edition={}", e)
-                } else {
-                    "".to_owned()
-                };
+                let edition_string = format!("&amp;edition={}", edition);
 
                 // These characters don't need to be escaped in a URI.
                 // FIXME: use a library function for percent encoding.
@@ -247,8 +255,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                 Some(("This example is not tested".to_owned(), "ignore"))
             } else if compile_fail {
                 Some(("This example deliberately fails to compile".to_owned(), "compile_fail"))
-            } else if let Some(e) = edition {
-                Some((format!("This code runs with edition {}", e), "edition"))
+            } else if explicit_edition {
+                Some((format!("This code runs with edition {}", edition), "edition"))
             } else {
                 None
             };
@@ -259,7 +267,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                     Some(&format!("rust-example-rendered{}",
                                   if ignore { " ignore" }
                                   else if compile_fail { " compile_fail" }
-                                  else if edition.is_some() { " edition " }
+                                  else if explicit_edition { " edition " }
                                   else { "" })),
                     playground_button.as_ref().map(String::as_str),
                     Some((s1.as_str(), s2))));
@@ -270,7 +278,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                     Some(&format!("rust-example-rendered{}",
                                   if ignore { " ignore" }
                                   else if compile_fail { " compile_fail" }
-                                  else if edition.is_some() { " edition " }
+                                  else if explicit_edition { " edition " }
                                   else { "" })),
                     playground_button.as_ref().map(String::as_str),
                     None));
@@ -659,7 +667,7 @@ impl LangString {
 
 impl<'a> fmt::Display for Markdown<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Markdown(md, links, ref ids, codes) = *self;
+        let Markdown(md, links, ref ids, codes, edition) = *self;
         let mut ids = ids.borrow_mut();
 
         // This is actually common enough to special-case
@@ -678,7 +686,7 @@ impl<'a> fmt::Display for Markdown<'a> {
 
         let p = HeadingLinks::new(p, None, &mut ids);
         let p = LinkReplacer::new(p, links);
-        let p = CodeBlocks::new(p, codes);
+        let p = CodeBlocks::new(p, codes, edition);
         let p = Footnotes::new(p);
         html::push_html(&mut s, p);
 
@@ -688,7 +696,7 @@ impl<'a> fmt::Display for Markdown<'a> {
 
 impl<'a> fmt::Display for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let MarkdownWithToc(md, ref ids, codes) = *self;
+        let MarkdownWithToc(md, ref ids, codes, edition) = *self;
         let mut ids = ids.borrow_mut();
 
         let p = Parser::new_ext(md, opts());
@@ -699,7 +707,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
 
         {
             let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
-            let p = CodeBlocks::new(p, codes);
+            let p = CodeBlocks::new(p, codes, edition);
             let p = Footnotes::new(p);
             html::push_html(&mut s, p);
         }
@@ -712,7 +720,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
 
 impl<'a> fmt::Display for MarkdownHtml<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let MarkdownHtml(md, ref ids, codes) = *self;
+        let MarkdownHtml(md, ref ids, codes, edition) = *self;
         let mut ids = ids.borrow_mut();
 
         // This is actually common enough to special-case
@@ -728,7 +736,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
         let p = HeadingLinks::new(p, None, &mut ids);
-        let p = CodeBlocks::new(p, codes);
+        let p = CodeBlocks::new(p, codes, edition);
         let p = Footnotes::new(p);
         html::push_html(&mut s, p);
 
@@ -1046,7 +1054,7 @@ mod tests {
     use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
     use super::plain_summary_line;
     use std::cell::RefCell;
-    use syntax::edition::Edition;
+    use syntax::edition::{Edition, DEFAULT_EDITION};
 
     #[test]
     fn test_lang_string_parse() {
@@ -1098,7 +1106,8 @@ mod tests {
     fn test_header() {
         fn t(input: &str, expect: &str) {
             let mut map = IdMap::new();
-            let output = Markdown(input, &[], RefCell::new(&mut map), ErrorCodes::Yes).to_string();
+            let output = Markdown(input, &[], RefCell::new(&mut map),
+                                  ErrorCodes::Yes, DEFAULT_EDITION).to_string();
             assert_eq!(output, expect, "original: {}", input);
         }
 
@@ -1120,7 +1129,8 @@ mod tests {
     fn test_header_ids_multiple_blocks() {
         let mut map = IdMap::new();
         fn t(map: &mut IdMap, input: &str, expect: &str) {
-            let output = Markdown(input, &[], RefCell::new(map), ErrorCodes::Yes).to_string();
+            let output = Markdown(input, &[], RefCell::new(map),
+                                  ErrorCodes::Yes, DEFAULT_EDITION).to_string();
             assert_eq!(output, expect, "original: {}", input);
         }
 
@@ -1157,7 +1167,8 @@ mod tests {
     fn test_markdown_html_escape() {
         fn t(input: &str, expect: &str) {
             let mut idmap = IdMap::new();
-            let output = MarkdownHtml(input, RefCell::new(&mut idmap), ErrorCodes::Yes).to_string();
+            let output = MarkdownHtml(input, RefCell::new(&mut idmap),
+                                      ErrorCodes::Yes, DEFAULT_EDITION).to_string();
             assert_eq!(output, expect, "original: {}", input);
         }
 
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 472192a6464..b628bd450d3 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -47,9 +47,11 @@ use std::rc::Rc;
 use errors;
 use serialize::json::{ToJson, Json, as_json};
 use syntax::ast;
+use syntax::edition::Edition;
 use syntax::ext::base::MacroKind;
 use syntax::source_map::FileName;
 use syntax::feature_gate::UnstableFeatures;
+use syntax::symbol::{Symbol, sym};
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
@@ -107,6 +109,8 @@ struct Context {
     /// publicly reused items to redirect to the right location.
     pub render_redirect_pages: bool,
     pub codes: ErrorCodes,
+    /// The default edition used to parse doctests.
+    pub edition: Edition,
     /// The map used to ensure all generated 'id=' attributes are unique.
     id_map: Rc<RefCell<IdMap>>,
     pub shared: Arc<SharedContext>,
@@ -505,7 +509,7 @@ pub fn initial_ids() -> Vec<String> {
      "methods",
      "deref-methods",
      "implementations",
-    ].into_iter().map(|id| (String::from(*id))).collect()
+    ].iter().map(|id| (String::from(*id))).collect()
 }
 
 /// Generates the documentation for `crate` into the directory `dst`
@@ -513,7 +517,8 @@ pub fn run(mut krate: clean::Crate,
            options: RenderOptions,
            passes: FxHashSet<String>,
            renderinfo: RenderInfo,
-           diag: &errors::Handler) -> Result<(), Error> {
+           diag: &errors::Handler,
+           edition: Edition) -> Result<(), Error> {
     // need to save a copy of the options for rendering the index page
     let md_opts = options.clone();
     let RenderOptions {
@@ -571,24 +576,24 @@ pub fn run(mut krate: clean::Crate,
     // Crawl the crate attributes looking for attributes which control how we're
     // going to emit HTML
     if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) {
-        for attr in attrs.lists("doc") {
-            match (attr.name_or_empty().get(), attr.value_str()) {
-                ("html_favicon_url", Some(s)) => {
+        for attr in attrs.lists(sym::doc) {
+            match (attr.name_or_empty(), attr.value_str()) {
+                (sym::html_favicon_url, Some(s)) => {
                     scx.layout.favicon = s.to_string();
                 }
-                ("html_logo_url", Some(s)) => {
+                (sym::html_logo_url, Some(s)) => {
                     scx.layout.logo = s.to_string();
                 }
-                ("html_playground_url", Some(s)) => {
+                (sym::html_playground_url, Some(s)) => {
                     markdown::PLAYGROUND.with(|slot| {
                         let name = krate.name.clone();
                         *slot.borrow_mut() = Some((Some(name), s.to_string()));
                     });
                 }
-                ("issue_tracker_base_url", Some(s)) => {
+                (sym::issue_tracker_base_url, Some(s)) => {
                     scx.issue_tracker_base_url = Some(s.to_string());
                 }
-                ("html_no_source", None) if attr.is_word() => {
+                (sym::html_no_source, None) if attr.is_word() => {
                     scx.include_sources = false;
                 }
                 _ => {}
@@ -603,6 +608,7 @@ pub fn run(mut krate: clean::Crate,
         dst,
         render_redirect_pages: false,
         codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
+        edition,
         id_map: Rc::new(RefCell::new(id_map)),
         shared: Arc::new(scx),
     };
@@ -1127,7 +1133,7 @@ themePicker.onblur = handleThemeButtonsBlur;
             md_opts.output = cx.dst.clone();
             md_opts.external_html = (*cx.shared).layout.external_html.clone();
 
-            crate::markdown::render(index_page, md_opts, diag);
+            crate::markdown::render(index_page, md_opts, diag, cx.edition);
         } else {
             let dst = cx.dst.join("index.html");
             let mut w = BufWriter::new(try_err!(File::create(&dst), &dst));
@@ -1388,8 +1394,8 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat
 
     // Failing that, see if there's an attribute specifying where to find this
     // external crate
-    e.attrs.lists("doc")
-     .filter(|a| a.check_name("html_root_url"))
+    e.attrs.lists(sym::doc)
+     .filter(|a| a.check_name(sym::html_root_url))
      .filter_map(|a| a.value_str())
      .map(|url| {
         let mut url = url.to_string();
@@ -1779,8 +1785,8 @@ impl<'a> Cache {
             let path = self.paths.get(&item.def_id)
                                  .map(|p| p.0[..p.0.len() - 1].join("::"))
                                  .unwrap_or("std".to_owned());
-            for alias in item.attrs.lists("doc")
-                                   .filter(|a| a.check_name("alias"))
+            for alias in item.attrs.lists(sym::doc)
+                                   .filter(|a| a.check_name(sym::alias))
                                    .filter_map(|a| a.value_str()
                                                     .map(|s| s.to_string().replace("\"", "")))
                                    .filter(|v| !v.is_empty())
@@ -2552,7 +2558,7 @@ fn render_markdown(w: &mut fmt::Formatter<'_>,
            if is_hidden { " hidden" } else { "" },
            prefix,
            Markdown(md_text, &links, RefCell::new(&mut ids),
-           cx.codes))
+           cx.codes, cx.edition))
 }
 
 fn document_short(
@@ -2917,7 +2923,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
 
         if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();
-            let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes);
+            let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes, cx.edition);
             message.push_str(&format!(": {}", html));
         }
         stability.push(format!("<div class='stab deprecated'>{}</div>", message));
@@ -2966,7 +2972,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
             message = format!(
                 "<details><summary>{}</summary>{}</details>",
                 message,
-                MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes)
+                MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition)
             );
         }
 
@@ -2991,7 +2997,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
 fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                  c: &clean::Constant) -> fmt::Result {
     write!(w, "<pre class='rust const'>")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "{vis}const \
                {name}: {typ}</pre>",
            vis = VisSpace(&it.visibility),
@@ -3003,7 +3009,7 @@ fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
 fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                s: &clean::Static) -> fmt::Result {
     write!(w, "<pre class='rust static'>")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "{vis}static {mutability}\
                {name}: {typ}</pre>",
            vis = VisSpace(&it.visibility),
@@ -3026,7 +3032,7 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
         f.generics
     ).len();
     write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w,
            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
            {name}{generics}{decl}{where_clause}</pre>",
@@ -3115,7 +3121,7 @@ fn item_trait(
     // Output the trait definition
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class='rust trait'>")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         write!(w, "{}{}{}trait {}{}{}",
                VisSpace(&it.visibility),
                UnsafetySpace(t.unsafety),
@@ -3378,8 +3384,10 @@ fn assoc_const(w: &mut fmt::Formatter<'_>,
                it: &clean::Item,
                ty: &clean::Type,
                _default: Option<&String>,
-               link: AssocItemLink<'_>) -> fmt::Result {
-    write!(w, "{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
+               link: AssocItemLink<'_>,
+               extra: &str) -> fmt::Result {
+    write!(w, "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
+           extra,
            VisSpace(&it.visibility),
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap(),
@@ -3390,8 +3398,10 @@ fn assoc_const(w: &mut fmt::Formatter<'_>,
 fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item,
                              bounds: &[clean::GenericBound],
                              default: Option<&clean::Type>,
-                             link: AssocItemLink<'_>) -> fmt::Result {
-    write!(w, "type <a href='{}' class=\"type\">{}</a>",
+                             link: AssocItemLink<'_>,
+                             extra: &str) -> fmt::Result {
+    write!(w, "{}type <a href='{}' class=\"type\">{}</a>",
+           extra,
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap())?;
     if !bounds.is_empty() {
@@ -3468,7 +3478,7 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>,
         } else {
             (0, true)
         };
-        render_attributes(w, meth)?;
+        render_attributes(w, meth, false)?;
         write!(w, "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
                if parent == ItemType::Trait { "    " } else { "" },
@@ -3502,10 +3512,12 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>,
             method(w, item, m.header, &m.generics, &m.decl, link, parent)
         }
         clean::AssociatedConstItem(ref ty, ref default) => {
-            assoc_const(w, item, ty, default.as_ref(), link)
+            assoc_const(w, item, ty, default.as_ref(), link,
+                        if parent == ItemType::Trait { "    " } else { "" })
         }
         clean::AssociatedTypeItem(ref bounds, ref default) => {
-            assoc_type(w, item, bounds, default.as_ref(), link)
+            assoc_type(w, item, bounds, default.as_ref(), link,
+                       if parent == ItemType::Trait { "    " } else { "" })
         }
         _ => panic!("render_assoc_item called on non-associated-item")
     }
@@ -3515,7 +3527,7 @@ fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                s: &clean::Struct) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class='rust struct'>")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         render_struct(w,
                       it,
                       Some(&s.generics),
@@ -3566,7 +3578,7 @@ fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                s: &clean::Union) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class='rust union'>")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         render_union(w,
                      it,
                      Some(&s.generics),
@@ -3611,7 +3623,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
              e: &clean::Enum) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "<pre class='rust enum'>")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         write!(w, "{}enum {}{}{}",
                VisSpace(&it.visibility),
                it.name.as_ref().unwrap(),
@@ -3761,22 +3773,30 @@ fn render_attribute(attr: &ast::MetaItem) -> Option<String> {
     }
 }
 
-const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
-    "export_name",
-    "lang",
-    "link_section",
-    "must_use",
-    "no_mangle",
-    "repr",
-    "unsafe_destructor_blind_to_params",
-    "non_exhaustive"
+const ATTRIBUTE_WHITELIST: &'static [Symbol] = &[
+    sym::export_name,
+    sym::lang,
+    sym::link_section,
+    sym::must_use,
+    sym::no_mangle,
+    sym::repr,
+    sym::unsafe_destructor_blind_to_params,
+    sym::non_exhaustive
 ];
 
-fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item) -> fmt::Result {
+// The `top` parameter is used when generating the item declaration to ensure it doesn't have a
+// left padding. For example:
+//
+// #[foo] <----- "top" attribute
+// struct Foo {
+//     #[bar] <---- not "top" attribute
+//     bar: usize,
+// }
+fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt::Result {
     let mut attrs = String::new();
 
     for attr in &it.attrs.other_attrs {
-        if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty().get()) {
+        if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty()) {
             continue;
         }
         if let Some(s) = render_attribute(&attr.meta().unwrap()) {
@@ -3784,7 +3804,8 @@ fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item) -> fmt::Result {
         }
     }
     if attrs.len() > 0 {
-        write!(w, "<div class=\"docblock attributes\">{}</div>", &attrs)?;
+        write!(w, "<div class=\"docblock attributes{}\">{}</div>",
+               if top { " top-attr" } else { "" }, &attrs)?;
     }
     Ok(())
 }
@@ -4117,7 +4138,8 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> {
                             out.push_str("<span class=\"where fmt-newline\">    ");
                             assoc_type(&mut out, it, &[],
                                        Some(&tydef.type_),
-                                       AssocItemLink::GotoSource(t_did, &FxHashSet::default()))?;
+                                       AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
+                                       "")?;
                             out.push_str(";</span>");
                         }
                     }
@@ -4157,7 +4179,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
                     if let clean::TypedefItem(ref tydef, _) = it.inner {
                         write!(w, "<span class=\"where fmt-newline\">  ")?;
                         assoc_type(w, it, &vec![], Some(&tydef.type_),
-                                   AssocItemLink::Anchor(None))?;
+                                   AssocItemLink::Anchor(None),
+                                   "")?;
                         write!(w, ";</span>")?;
                     }
                 }
@@ -4179,7 +4202,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
         if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
             let mut ids = cx.id_map.borrow_mut();
             write!(w, "<div class='docblock'>{}</div>",
-                   Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?;
+                   Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids),
+                            cx.codes, cx.edition))?;
         }
     }
 
@@ -4227,7 +4251,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                 write!(w, "<code id='{}'>", ns_id)?;
-                assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
+                assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?;
                 write!(w, "</code></h4>")?;
             }
             clean::AssociatedConstItem(ref ty, ref default) => {
@@ -4235,7 +4259,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                 write!(w, "<code id='{}'>", ns_id)?;
-                assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
+                assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "")?;
                 write!(w, "</code>")?;
                 render_stability_since_raw(w, item.stable_since(), outer_version)?;
                 if let Some(l) = (Item { cx, item }).src_href() {
@@ -4249,7 +4273,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                 write!(w, "<code id='{}'>", ns_id)?;
-                assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
+                assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "")?;
                 write!(w, "</code></h4>")?;
             }
             clean::StrippedItem(..) => return Ok(()),
@@ -4337,7 +4361,7 @@ fn item_existential(
     t: &clean::Existential,
 ) -> fmt::Result {
     write!(w, "<pre class='rust existential'>")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "existential type {}{}{where_clause}: {bounds};</pre>",
            it.name.as_ref().unwrap(),
            t.generics,
@@ -4356,7 +4380,7 @@ fn item_existential(
 fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                     t: &clean::TraitAlias) -> fmt::Result {
     write!(w, "<pre class='rust trait-alias'>")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "trait {}{}{} = {};</pre>",
            it.name.as_ref().unwrap(),
            t.generics,
@@ -4375,7 +4399,7 @@ fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
 fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                 t: &clean::Typedef) -> fmt::Result {
     write!(w, "<pre class='rust typedef'>")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "type {}{}{where_clause} = {type_};</pre>",
            it.name.as_ref().unwrap(),
            t.generics,
@@ -4393,7 +4417,7 @@ fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
 
 fn item_foreign_type(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item) -> fmt::Result {
     writeln!(w, "<pre class='rust foreigntype'>extern {{")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(
         w,
         "    {}type {};\n}}</pre>",
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 85ab0855f05..72a01a49bc6 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2325,7 +2325,11 @@ if (!DOMTokenList.prototype.remove) {
     }
     var attributesToggle = createToggleWrapper(createSimpleToggle(false));
     onEachLazy(main.getElementsByClassName("attributes"), function(i_e) {
-        i_e.parentNode.insertBefore(attributesToggle.cloneNode(true), i_e);
+        var attr_tog = attributesToggle.cloneNode(true);
+        if (hasClass(i_e, "top-attr") === true) {
+            addClass(attr_tog, "top-attr");
+        }
+        i_e.parentNode.insertBefore(attr_tog, i_e);
         itemAttributesFunc(i_e);
     });
 
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 880b8243355..0493bf7c5c0 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -182,12 +182,25 @@ nav.sub {
 	display: none !important;
 }
 
-.sidebar img {
+.logo-container {
+	height: 100px;
+	width: 100px;
+	position: relative;
 	margin: 20px auto;
 	display: block;
 	margin-top: 10px;
 }
 
+.logo-container > img {
+	max-width: 100px;
+	max-height: 100px;
+	position: absolute;
+	left: 50%;
+	top: 50%;
+	transform: translate(-50%, -50%);
+	display: block;
+}
+
 .sidebar .location {
 	border: 1px solid;
 	font-size: 17px;
@@ -658,18 +671,18 @@ a {
 	transition: border-color 300ms ease;
 	transition: border-radius 300ms ease-in-out;
 	transition: box-shadow 300ms ease-in-out;
-	width: calc(100% - 32px);
+	width: 100%;
 }
 
 #crate-search + .search-input {
 	border-radius: 0 1px 1px 0;
+	width: calc(100% - 32px);
 }
 
 .search-input:focus {
 	border-radius: 2px;
 	border: 0;
 	outline: 0;
-	box-shadow: 0 0 8px #078dd8;
 }
 
 .search-results .desc {
@@ -998,6 +1011,195 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 	opacity: 1;
 }
 
+.information {
+	position: absolute;
+	left: -20px;
+	margin-top: 7px;
+	z-index: 1;
+}
+
+.tooltip {
+	position: relative;
+	display: inline-block;
+	cursor: pointer;
+}
+
+.tooltip .tooltiptext {
+	width: 120px;
+	display: none;
+	text-align: center;
+	padding: 5px 3px;
+	border-radius: 6px;
+	margin-left: 5px;
+	top: -5px;
+	left: 105%;
+	z-index: 10;
+}
+
+.tooltip:hover .tooltiptext {
+	display: inline;
+}
+
+.tooltip .tooltiptext::after {
+	content: " ";
+	position: absolute;
+	top: 50%;
+	left: 11px;
+	margin-top: -5px;
+	border-width: 5px;
+	border-style: solid;
+}
+
+.important-traits .tooltip .tooltiptext {
+	border: 1px solid;
+}
+
+pre.rust {
+	position: relative;
+	tab-width: 4;
+	-moz-tab-width: 4;
+}
+
+.search-failed {
+	text-align: center;
+	margin-top: 20px;
+}
+
+.search-failed > ul {
+	text-align: left;
+	max-width: 570px;
+	margin-left: auto;
+	margin-right: auto;
+}
+
+#titles {
+	height: 35px;
+}
+
+#titles > div {
+	float: left;
+	width: 33.3%;
+	text-align: center;
+	font-size: 18px;
+	cursor: pointer;
+	border-top: 2px solid;
+}
+
+#titles > div:not(:last-child) {
+	margin-right: 1px;
+	width: calc(33.3% - 1px);
+}
+
+#titles > div > div.count {
+	display: inline-block;
+	font-size: 16px;
+}
+
+.important-traits {
+	cursor: pointer;
+	z-index: 2;
+}
+
+h4 > .important-traits {
+	position: absolute;
+	left: -44px;
+	top: 2px;
+}
+
+#all-types {
+	text-align: center;
+	border: 1px solid;
+	margin: 0 10px;
+	margin-bottom: 10px;
+	display: block;
+	border-radius: 7px;
+}
+#all-types > p {
+	margin: 5px 0;
+}
+
+#sidebar-toggle {
+	position: fixed;
+	top: 30px;
+	left: 300px;
+	z-index: 10;
+	padding: 3px;
+	border-top-right-radius: 3px;
+	border-bottom-right-radius: 3px;
+	cursor: pointer;
+	font-weight: bold;
+	transition: left .5s;
+	font-size: 1.2em;
+	border: 1px solid;
+	border-left: 0;
+}
+#source-sidebar {
+	position: fixed;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	width: 300px;
+	z-index: 1;
+	overflow: auto;
+	transition: left .5s;
+	border-right: 1px solid;
+}
+#source-sidebar > .title {
+	font-size: 1.5em;
+	text-align: center;
+	border-bottom: 1px solid;
+	margin-bottom: 6px;
+}
+
+.theme-picker {
+	position: absolute;
+	left: 211px;
+	top: 19px;
+}
+
+.theme-picker button {
+	outline: none;
+}
+
+#settings-menu {
+	position: absolute;
+	right: 0;
+	top: 10px;
+	outline: none;
+}
+
+#theme-picker, #settings-menu {
+	padding: 4px;
+	width: 27px;
+	height: 29px;
+	border: 1px solid;
+	border-radius: 3px;
+	cursor: pointer;
+}
+
+#theme-choices {
+	display: none;
+	position: absolute;
+	left: 0;
+	top: 28px;
+	border: 1px solid;
+	border-radius: 3px;
+	z-index: 1;
+	cursor: pointer;
+}
+
+#theme-choices > button {
+	border: none;
+	width: 100%;
+	padding: 4px;
+	text-align: center;
+	background: rgba(0,0,0,0);
+}
+
+#theme-choices > button:not(:first-child) {
+	border-top: 1px solid;
+}
+
 /* Media Queries */
 
 @media (max-width: 700px) {
@@ -1030,14 +1232,20 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 		padding: 0;
 	}
 
-	.sidebar img {
+	.sidebar .logo-container {
 		width: 35px;
+		height: 35px;
 		margin-top: 5px;
 		margin-bottom: 5px;
 		float: left;
 		margin-left: 50px;
 	}
 
+	.sidebar .logo-container > img {
+		max-width: 35px;
+		max-height: 35px;
+	}
+
 	.sidebar-menu {
 		position: fixed;
 		z-index: 10;
@@ -1118,125 +1326,12 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 		overflow: initial;
 	}
 
-	#main > .line-numbers {
-		margin-top: 0;
-	}
-}
-
-@media print {
-	nav.sub, .content .out-of-band, .collapse-toggle {
-		display: none;
+	.theme-picker {
+		left: 10px;
+		top: 54px;
+		z-index: 1;
 	}
-}
 
-.information {
-	position: absolute;
-	left: -20px;
-	margin-top: 7px;
-	z-index: 1;
-}
-
-.tooltip {
-	position: relative;
-	display: inline-block;
-	cursor: pointer;
-}
-
-.tooltip .tooltiptext {
-	width: 120px;
-	display: none;
-	text-align: center;
-	padding: 5px 3px;
-	border-radius: 6px;
-	margin-left: 5px;
-	top: -5px;
-	left: 105%;
-	z-index: 10;
-}
-
-.tooltip:hover .tooltiptext {
-	display: inline;
-}
-
-.tooltip .tooltiptext::after {
-	content: " ";
-	position: absolute;
-	top: 50%;
-	left: 11px;
-	margin-top: -5px;
-	border-width: 5px;
-	border-style: solid;
-}
-
-.important-traits .tooltip .tooltiptext {
-	border: 1px solid;
-}
-
-pre.rust {
-	position: relative;
-	tab-width: 4;
-	-moz-tab-width: 4;
-}
-
-.search-failed {
-	text-align: center;
-	margin-top: 20px;
-}
-
-.search-failed > ul {
-	text-align: left;
-	max-width: 570px;
-	margin-left: auto;
-	margin-right: auto;
-}
-
-#titles {
-	height: 35px;
-}
-
-#titles > div {
-	float: left;
-	width: 33.3%;
-	text-align: center;
-	font-size: 18px;
-	cursor: pointer;
-	border-top: 2px solid;
-}
-
-#titles > div:not(:last-child) {
-	margin-right: 1px;
-	width: calc(33.3% - 1px);
-}
-
-#titles > div > div.count {
-	display: inline-block;
-	font-size: 16px;
-}
-
-.important-traits {
-	cursor: pointer;
-	z-index: 2;
-}
-
-h4 > .important-traits {
-	position: absolute;
-	left: -44px;
-	top: 2px;
-}
-
-#all-types {
-	text-align: center;
-	border: 1px solid;
-	margin: 0 10px;
-	margin-bottom: 10px;
-	display: block;
-	border-radius: 7px;
-}
-#all-types > p {
-	margin: 5px 0;
-}
-
-@media (max-width: 700px) {
 	h4 > .important-traits {
 		position: absolute;
 		left: -22px;
@@ -1311,8 +1406,29 @@ h4 > .important-traits {
 	#all-types {
 		margin: 10px;
 	}
+
+	#sidebar-toggle {
+		top: 100px;
+		width: 30px;
+		font-size: 1.5rem;
+		text-align: center;
+		padding: 0;
+	}
+
+	#source-sidebar {
+		z-index: 11;
+	}
+
+	#main > .line-numbers {
+		margin-top: 0;
+	}
 }
 
+@media print {
+	nav.sub, .content .out-of-band, .collapse-toggle {
+		display: none;
+	}
+}
 
 @media (max-width: 416px) {
 	#titles {
@@ -1412,63 +1528,6 @@ kbd {
 	cursor: default;
 }
 
-.theme-picker {
-	position: absolute;
-	left: 211px;
-	top: 19px;
-}
-
-.theme-picker button {
-	outline: none;
-}
-
-#settings-menu {
-	position: absolute;
-	right: 0;
-	top: 10px;
-	outline: none;
-}
-
-#theme-picker, #settings-menu {
-	padding: 4px;
-	width: 27px;
-	height: 29px;
-	border: 1px solid;
-	border-radius: 3px;
-	cursor: pointer;
-}
-
-#theme-choices {
-	display: none;
-	position: absolute;
-	left: 0;
-	top: 28px;
-	border: 1px solid;
-	border-radius: 3px;
-	z-index: 1;
-	cursor: pointer;
-}
-
-#theme-choices > button {
-	border: none;
-	width: 100%;
-	padding: 4px;
-	text-align: center;
-	background: rgba(0,0,0,0);
-}
-
-#theme-choices > button:not(:first-child) {
-	border-top: 1px solid;
-}
-
-@media (max-width: 700px) {
-	.theme-picker {
-		left: 10px;
-		top: 54px;
-		z-index: 1;
-	}
-}
-
 .hidden-by-impl-hider,
 .hidden-by-usual-hider {
 	/* important because of conflicting rule for small screens */
@@ -1520,39 +1579,6 @@ kbd {
 	margin-bottom: 1em;
 }
 
-#sidebar-toggle {
-	position: fixed;
-	top: 30px;
-	left: 300px;
-	z-index: 10;
-	padding: 3px;
-	border-top-right-radius: 3px;
-	border-bottom-right-radius: 3px;
-	cursor: pointer;
-	font-weight: bold;
-	transition: left .5s;
-	font-size: 1.2em;
-	border: 1px solid;
-	border-left: 0;
-}
-#source-sidebar {
-	position: fixed;
-	top: 0;
-	bottom: 0;
-	left: 0;
-	width: 300px;
-	z-index: 1;
-	overflow: auto;
-	transition: left .5s;
-	border-right: 1px solid;
-}
-#source-sidebar > .title {
-	font-size: 1.5em;
-	text-align: center;
-	border-bottom: 1px solid;
-	margin-bottom: 6px;
-}
-
 div.children {
 	padding-left: 27px;
 	display: none;
@@ -1587,10 +1613,10 @@ div.name.expand::before {
 }
 
 /* This part is to fix the "Expand attributes" part in the type declaration. */
-.type-decl > pre > :first-child {
+.type-decl > pre > .toggle-wrapper.toggle-attributes.top-attr {
 	margin-left: 0 !important;
 }
-.type-decl > pre > :nth-child(2) {
+.type-decl > pre > .docblock.attributes.top-attr {
 	margin-left: 1.8em !important;
 }
 .type-decl > pre > .toggle-attributes {
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index f1255f52247..e44ae2ad10c 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -164,20 +164,21 @@ a.test-arrow {
 	color: #111;
 	background-color: #f0f0f0;
 	border-color: #000;
+	box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
 }
 
 .search-input {
 	color: #111;
-	box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
 	background-color: #f0f0f0;
+	box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
 }
 
 .search-input:focus {
 	border-color: #008dfd;
 }
 
-#crate-search + .search-input {
-	box-shadow: 1px 0 0 1px #000, 0 0 0 2px transparent;
+#crate-search + .search-input:focus {
+	box-shadow: 0 0 8px 4px #078dd8;
 }
 
 .module-item .stab {
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index c052e6b37ad..4c37000dde2 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -164,21 +164,21 @@ a.test-arrow {
 	color: #555;
 	background-color: white;
 	border-color: #e0e0e0;
-	box-shadow: 0px 0 0 1px #e0e0e0, 0 0 0 2px transparent;
+	box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
 }
 
 .search-input {
 	color: #555;
-	box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
 	background-color: white;
+	box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
 }
 
 .search-input:focus {
 	border-color: #66afe9;
 }
 
-#crate-search + .search-input {
-	box-shadow: 1px 0 0 1px #e0e0e0, 0 0 0 2px transparent;
+#crate-search + .search-input:focus {
+	box-shadow: 0 0 8px #078dd8;
 }
 
 .module-item .stab {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 5b76f6861de..f5061b67182 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -391,7 +391,10 @@ fn main_args(args: &[String]) -> i32 {
     match (options.should_test, options.markdown_input()) {
         (true, true) => return markdown::test(options, &diag),
         (true, false) => return test::run(options),
-        (false, true) => return markdown::render(options.input, options.render_options, &diag),
+        (false, true) => return markdown::render(options.input,
+                                                 options.render_options,
+                                                 &diag,
+                                                 options.edition),
         (false, false) => {}
     }
 
@@ -399,7 +402,8 @@ fn main_args(args: &[String]) -> i32 {
     // but we can't crates the Handler ahead of time because it's not Send
     let diag_opts = (options.error_format,
                      options.debugging_options.treat_err_as_bug,
-                     options.debugging_options.ui_testing);
+                     options.debugging_options.ui_testing,
+                     options.edition);
     let show_coverage = options.show_coverage;
     rust_input(options, move |out| {
         if show_coverage {
@@ -410,7 +414,7 @@ fn main_args(args: &[String]) -> i32 {
 
         let Output { krate, passes, renderinfo, renderopts } = out;
         info!("going to format");
-        let (error_format, treat_err_as_bug, ui_testing) = diag_opts;
+        let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts;
         let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
         match html::render::run(
             krate,
@@ -418,6 +422,7 @@ fn main_args(args: &[String]) -> i32 {
             passes.into_iter().collect(),
             renderinfo,
             &diag,
+            edition,
         ) {
             Ok(_) => rustc_driver::EXIT_SUCCESS,
             Err(e) => {
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index c496dde8426..b0a37ea9c80 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -5,6 +5,7 @@ use std::cell::RefCell;
 
 use errors;
 use testing;
+use syntax::edition::Edition;
 use syntax::source_map::DUMMY_SP;
 use syntax::feature_gate::UnstableFeatures;
 
@@ -36,7 +37,12 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
 
 /// Render `input` (e.g., "foo.md") into an HTML file in `output`
 /// (e.g., output = "bar" => "bar/foo.html").
-pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> i32 {
+pub fn render(
+    input: PathBuf,
+    options: RenderOptions,
+    diag: &errors::Handler,
+    edition: Edition
+) -> i32 {
     let mut output = options.output;
     output.push(input.file_stem().unwrap());
     output.set_extension("html");
@@ -76,9 +82,9 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) ->
     let mut ids = IdMap::new();
     let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
     let text = if !options.markdown_no_toc {
-        MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string()
+        MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string()
     } else {
-        Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string()
+        Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string()
     };
 
     let err = write!(
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index fe407fa24d9..4ee09f7096b 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -5,6 +5,7 @@ use crate::passes::Pass;
 
 use syntax::attr;
 use syntax_pos::FileName;
+use syntax::symbol::sym;
 
 use std::collections::BTreeMap;
 use std::ops;
@@ -131,7 +132,7 @@ impl fold::DocFolder for CoverageCalculator {
                 return Some(i);
             }
             clean::ImplItem(ref impl_)
-                if attr::contains_name(&i.attrs.other_attrs, "automatically_derived")
+                if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived)
                     || impl_.synthetic || impl_.blanket_impl.is_some() =>
             {
                 // built-in derives get the `#[automatically_derived]` attribute, and
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index abf19a0a5ef..2c382a1c175 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -99,7 +99,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             // Try looking for methods and associated items.
             let mut split = path_str.rsplitn(2, "::");
             let item_name = if let Some(first) = split.next() {
-                first
+                Symbol::intern(first)
             } else {
                 return Err(())
             };
@@ -321,7 +321,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                         if let Ok(res) = self.resolve(path_str, ns, &current_item, parent_node) {
                             res
                         } else {
-                            resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+                            resolution_failure(cx, &item, path_str, &dox, link_range);
                             // This could just be a normal link or a broken link
                             // we could potentially check if something is
                             // "intra-doc-link-like" and warn in that case.
@@ -332,7 +332,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                         if let Ok(res) = self.resolve(path_str, ns, &current_item, parent_node) {
                             res
                         } else {
-                            resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+                            resolution_failure(cx, &item, path_str, &dox, link_range);
                             // This could just be a normal link.
                             continue;
                         }
@@ -357,7 +357,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                         };
 
                         if candidates.is_empty() {
-                            resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+                            resolution_failure(cx, &item, path_str, &dox, link_range);
                             // this could just be a normal link
                             continue;
                         }
@@ -368,7 +368,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                         } else {
                             ambiguity_error(
                                 cx,
-                                &item.attrs,
+                                &item,
                                 path_str,
                                 &dox,
                                 link_range,
@@ -381,7 +381,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                         if let Some(res) = macro_resolve(cx, path_str) {
                             (res, None)
                         } else {
-                            resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+                            resolution_failure(cx, &item, path_str, &dox, link_range);
                             continue
                         }
                     }
@@ -452,16 +452,24 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
 /// line containing the failure as a note as well.
 fn resolution_failure(
     cx: &DocContext<'_>,
-    attrs: &Attributes,
+    item: &Item,
     path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
 ) {
+    let hir_id = match cx.as_local_hir_id(item.def_id) {
+        Some(hir_id) => hir_id,
+        None => {
+            // If non-local, no need to check anything.
+            return;
+        }
+    };
+    let attrs = &item.attrs;
     let sp = span_of_attrs(attrs);
 
     let mut diag = cx.tcx.struct_span_lint_hir(
         lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
-        hir::CRATE_HIR_ID,
+        hir_id,
         sp,
         &format!("`[{}]` cannot be resolved, ignoring it...", path_str),
     );
@@ -495,12 +503,20 @@ fn resolution_failure(
 
 fn ambiguity_error(
     cx: &DocContext<'_>,
-    attrs: &Attributes,
+    item: &Item,
     path_str: &str,
     dox: &str,
     link_range: Option<Range<usize>>,
     candidates: PerNS<Option<Res>>,
 ) {
+    let hir_id = match cx.as_local_hir_id(item.def_id) {
+        Some(hir_id) => hir_id,
+        None => {
+            // If non-local, no need to check anything.
+            return;
+        }
+    };
+    let attrs = &item.attrs;
     let sp = span_of_attrs(attrs);
 
     let mut msg = format!("`{}` is ", path_str);
@@ -532,7 +548,7 @@ fn ambiguity_error(
 
     let mut diag = cx.tcx.struct_span_lint_hir(
         lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
-        hir::CRATE_HIR_ID,
+        hir_id,
         sp,
         &msg,
     );
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 8d33cd72e29..70cd4b72199 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -5,6 +5,7 @@ use super::Pass;
 
 use rustc::util::nodemap::FxHashSet;
 use rustc::hir::def_id::DefId;
+use syntax::symbol::sym;
 
 pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
     name: "collect-trait-impls",
@@ -68,7 +69,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
             inline::build_impl(cx, def_id, &mut new_items);
 
             // FIXME(eddyb) is this `doc(hidden)` check needed?
-            if !cx.tcx.get_attrs(def_id).lists("doc").has_word("hidden") {
+            if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
                 let self_ty = cx.tcx.type_of(def_id);
                 let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
                 let mut renderinfo = cx.renderinfo.borrow_mut();
@@ -154,7 +155,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
-            if !self.cx.tcx.get_attrs(i.def_id).lists("doc").has_word("hidden") {
+            if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
                 self.impls.extend(get_auto_trait_and_blanket_impls(
                     self.cx,
                     self.cx.tcx.type_of(i.def_id),
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 99aca063471..d9af33ac5b6 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -1,7 +1,6 @@
 //! Contains information about "passes", used to modify crate information during the documentation
 //! process.
 
-use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::lint as lint;
 use rustc::middle::privacy::AccessLevels;
@@ -314,10 +313,13 @@ pub fn look_for_tests<'tcx>(
     item: &Item,
     check_missing_code: bool,
 ) {
-    if cx.as_local_hir_id(item.def_id).is_none() {
-        // If non-local, no need to check anything.
-        return;
-    }
+    let hir_id = match cx.as_local_hir_id(item.def_id) {
+        Some(hir_id) => hir_id,
+        None => {
+            // If non-local, no need to check anything.
+            return;
+        }
+    };
 
     struct Tests {
         found_tests: usize,
@@ -336,10 +338,11 @@ pub fn look_for_tests<'tcx>(
     find_testable_code(&dox, &mut tests, ErrorCodes::No);
 
     if check_missing_code == true && tests.found_tests == 0 {
+        let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span());
         let mut diag = cx.tcx.struct_span_lint_hir(
             lint::builtin::MISSING_DOC_CODE_EXAMPLES,
-            hir::CRATE_HIR_ID,
-            span_of_attrs(&item.attrs),
+            hir_id,
+            sp,
             "Missing code example in this documentation");
         diag.emit();
     } else if check_missing_code == false &&
@@ -347,7 +350,7 @@ pub fn look_for_tests<'tcx>(
               !cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) {
         let mut diag = cx.tcx.struct_span_lint_hir(
             lint::builtin::PRIVATE_DOC_TESTS,
-            hir::CRATE_HIR_ID,
+            hir_id,
             span_of_attrs(&item.attrs),
             "Documentation test in private item");
         diag.emit();
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 240299c212a..da8977544f6 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -1,5 +1,6 @@
 use rustc::util::nodemap::DefIdSet;
 use std::mem;
+use syntax::symbol::sym;
 
 use crate::clean::{self, AttributesExt, NestedAttributesExt};
 use crate::clean::Item;
@@ -37,7 +38,7 @@ struct Stripper<'a> {
 
 impl<'a> DocFolder for Stripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if i.attrs.lists("doc").has_word("hidden") {
+        if i.attrs.lists(sym::doc).has_word(sym::hidden) {
             debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name);
             // use a dedicated hidden item for given item type if any
             match i.inner {
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 5c0a4da1cd7..0cc99da6407 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -11,10 +11,6 @@ use syntax::ast;
 use syntax::source_map::SourceMap;
 use syntax::edition::Edition;
 use syntax::feature_gate::UnstableFeatures;
-use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName};
-use tempfile::Builder as TempFileBuilder;
-use testing;
-
 use std::env;
 use std::io::prelude::*;
 use std::io;
@@ -23,6 +19,10 @@ use std::path::PathBuf;
 use std::process::Command;
 use std::str;
 use std::sync::{Arc, Mutex};
+use syntax::symbol::sym;
+use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName};
+use tempfile::Builder as TempFileBuilder;
+use testing;
 
 use crate::clean::Attributes;
 use crate::config::Options;
@@ -137,17 +137,17 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
     };
 
     let test_attrs: Vec<_> = krate.attrs.iter()
-        .filter(|a| a.check_name("doc"))
+        .filter(|a| a.check_name(sym::doc))
         .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new))
-        .filter(|a| a.check_name("test"))
+        .filter(|a| a.check_name(sym::test))
         .collect();
     let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[]));
 
     for attr in attrs {
-        if attr.check_name("no_crate_inject") {
+        if attr.check_name(sym::no_crate_inject) {
             opts.no_crate_inject = true;
         }
-        if attr.check_name("attr") {
+        if attr.check_name(sym::attr) {
             if let Some(l) = attr.meta_item_list() {
                 for item in l {
                     opts.attrs.push(pprust::meta_list_item_to_string(item));
@@ -167,7 +167,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
             maybe_sysroot: Option<PathBuf>, linker: Option<PathBuf>, edition: Edition,
             persist_doctests: Option<PathBuf>) {
     let (test, line_offset) = match panic::catch_unwind(|| {
-        make_test(test, Some(cratename), as_test_harness, opts)
+        make_test(test, Some(cratename), as_test_harness, opts, edition)
     }) {
         Ok((test, line_offset)) => (test, line_offset),
         Err(cause) if cause.is::<errors::FatalErrorMarker>() => {
@@ -356,7 +356,8 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
 pub fn make_test(s: &str,
                  cratename: Option<&str>,
                  dont_insert_main: bool,
-                 opts: &TestOptions)
+                 opts: &TestOptions,
+                 edition: Edition)
                  -> (String, usize) {
     let (crate_attrs, everything_else, crates) = partition_source(s);
     let everything_else = everything_else.trim();
@@ -390,6 +391,8 @@ pub fn make_test(s: &str,
         use errors::emitter::EmitterWriter;
         use errors::Handler;
 
+        syntax::ext::hygiene::set_default_edition(edition);
+
         let filename = FileName::anon_source_code(s);
         let source = crates + &everything_else;
 
@@ -397,6 +400,7 @@ pub fn make_test(s: &str,
         // send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
         let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let emitter = EmitterWriter::new(box io::sink(), None, false, false, false);
+        // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
         let handler = Handler::with_emitter(false, None, box emitter);
         let sess = ParseSess::with_span_handler(handler, cm);
 
@@ -880,6 +884,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
 #[cfg(test)]
 mod tests {
     use super::{TestOptions, make_test};
+    use syntax::edition::DEFAULT_EDITION;
 
     #[test]
     fn make_test_basic() {
@@ -892,7 +897,7 @@ mod tests {
 fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, None, false, &opts);
+        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -908,7 +913,7 @@ assert_eq!(2+2, 4);
 fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -927,7 +932,7 @@ fn main() {
 use asdf::qwop;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 3));
     }
 
@@ -949,7 +954,7 @@ fn main() {
 use asdf::qwop;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -968,7 +973,7 @@ fn main() {
 use std::*;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("std"), false, &opts);
+        let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -988,7 +993,7 @@ fn main() {
 use asdf::qwop;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -1006,7 +1011,7 @@ fn main() {
 use asdf::qwop;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -1026,7 +1031,7 @@ fn main() {
 use asdf::qwop;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 3));
 
         // Adding more will also bump the returned line offset.
@@ -1039,7 +1044,7 @@ fn main() {
 use asdf::qwop;
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 4));
     }
 
@@ -1057,7 +1062,7 @@ assert_eq!(2+2, 4);";
 fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, None, false, &opts);
+        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -1074,7 +1079,7 @@ assert_eq!(2+2, 4);
 fn main() {
     assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, None, false, &opts);
+        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 1));
     }
 
@@ -1091,7 +1096,7 @@ assert_eq!(2+2, 4);";
 fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, None, false, &opts);
+        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
     }
 
@@ -1106,7 +1111,7 @@ assert_eq!(2+2, 4);";
 "#![allow(unused)]
 //Ceci n'est pas une `fn main`
 assert_eq!(2+2, 4);".to_string();
-        let output = make_test(input, None, true, &opts);
+        let output = make_test(input, None, true, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 1));
     }
 
@@ -1121,7 +1126,7 @@ assert_eq!(2+2, 4);".to_string();
 "fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
-        let output = make_test(input, None, false, &opts);
+        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 1));
     }
 
@@ -1140,7 +1145,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }".to_string();
 
-        let output = make_test(input, None, false, &opts);
+        let output = make_test(input, None, false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 2));
 
         let input =
@@ -1155,7 +1160,7 @@ fn main() {
 assert_eq!(asdf::foo, 4);
 }".to_string();
 
-        let output = make_test(input, Some("asdf"), false, &opts);
+        let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 3));
     }
 
@@ -1174,7 +1179,7 @@ test_wrapper! {
     fn main() {}
 }".to_string();
 
-        let output = make_test(input, Some("my_crate"), false, &opts);
+        let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
         assert_eq!(output, (expected, 1));
     }
 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 94d2d7ffdb8..eb9de43e388 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -10,6 +10,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::MacroKind;
 use syntax::source_map::Spanned;
+use syntax::symbol::sym;
 use syntax_pos::{self, Span};
 
 use std::mem;
@@ -165,11 +166,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     body: hir::BodyId) {
         debug!("Visiting fn");
         let macro_kind = item.attrs.iter().filter_map(|a| {
-            if a.check_name("proc_macro") {
+            if a.check_name(sym::proc_macro) {
                 Some(MacroKind::Bang)
-            } else if a.check_name("proc_macro_derive") {
+            } else if a.check_name(sym::proc_macro_derive) {
                 Some(MacroKind::Derive)
-            } else if a.check_name("proc_macro_attribute") {
+            } else if a.check_name(sym::proc_macro_attribute) {
                 Some(MacroKind::Attr)
             } else {
                 None
@@ -178,7 +179,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         match macro_kind {
             Some(kind) => {
                 let name = if kind == MacroKind::Derive {
-                    item.attrs.lists("proc_macro_derive")
+                    item.attrs.lists(sym::proc_macro_derive)
                               .filter_map(|mi| mi.ident())
                               .next()
                               .expect("proc-macro derives require a name")
@@ -188,8 +189,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
 
                 let mut helpers = Vec::new();
-                for mi in item.attrs.lists("proc_macro_derive") {
-                    if !mi.check_name("attributes") {
+                for mi in item.attrs.lists(sym::proc_macro_derive) {
+                    if !mi.check_name(sym::attributes) {
                         continue;
                     }
 
@@ -274,7 +275,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: hir::HirId) -> bool {
             while let Some(id) = cx.tcx.hir().get_enclosing_scope(node) {
                 node = id;
-                if cx.tcx.hir().attrs_by_hir_id(node).lists("doc").has_word("hidden") {
+                if cx.tcx.hir().attrs_by_hir_id(node)
+                    .lists(sym::doc).has_word(sym::hidden) {
                     return true;
                 }
                 if node == hir::CRATE_HIR_ID {
@@ -295,8 +297,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
         let use_attrs = tcx.hir().attrs_by_hir_id(id);
         // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
-        let is_no_inline = use_attrs.lists("doc").has_word("no_inline") ||
-                           use_attrs.lists("doc").has_word("hidden");
+        let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) ||
+                           use_attrs.lists(sym::doc).has_word(sym::hidden);
 
         // For cross-crate impl inlining we need to know whether items are
         // reachable in documentation -- a previously nonreachable item can be
@@ -304,7 +306,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         // (this is done here because we need to know this upfront).
         if !res_did.is_local() && !is_no_inline {
             let attrs = clean::inline::load_attrs(self.cx, res_did);
-            let self_is_hidden = attrs.lists("doc").has_word("hidden");
+            let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden);
             match res {
                 Res::Def(DefKind::Trait, did) |
                 Res::Def(DefKind::Struct, did) |
@@ -432,8 +434,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 if item.vis.node.is_pub() && self.inside_public_path {
                     let please_inline = item.attrs.iter().any(|item| {
                         match item.meta_item_list() {
-                            Some(ref list) if item.check_name("doc") => {
-                                list.iter().any(|i| i.check_name("inline"))
+                            Some(ref list) if item.check_name(sym::doc) => {
+                                list.iter().any(|i| i.check_name(sym::inline))
                             }
                             _ => false,
                         }
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 326c9a10f7d..2547e3a06e9 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -3,6 +3,7 @@ use rustc::hir::def::{Res, DefKind};
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::ty::Visibility;
 use rustc::util::nodemap::FxHashSet;
+use syntax::symbol::sym;
 
 use std::cell::RefMut;
 
@@ -42,7 +43,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
 
     // Updates node level and returns the updated level
     fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
-        let is_hidden = self.cx.tcx.get_attrs(did).lists("doc").has_word("hidden");
+        let is_hidden = self.cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden);
 
         let old_level = self.access_levels.map.get(&did).cloned();
         // Accessibility levels can only grow
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index ad5d62f667a..55e8b39974e 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -3,7 +3,7 @@ authors = ["The Rust Project Developers"]
 name = "std"
 version = "0.0.0"
 build = "build.rs"
-license = "MIT/Apache-2.0"
+license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust.git"
 description = "The Rust Standard Library"
 edition = "2018"
@@ -19,7 +19,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true }
 panic_abort = { path = "../libpanic_abort" }
 core = { path = "../libcore" }
 libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.12" }
+compiler_builtins = { version = "0.1.14" }
 profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 unwind = { path = "../libunwind" }
 hashbrown = { version = "0.3.0", features = ['rustc-dep-of-std'] }
@@ -54,7 +54,7 @@ default = ["compiler_builtins_c", "std_detect_file_io", "std_detect_dlsym_getaux
 backtrace = ["backtrace-sys"]
 panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
-compiler_builtins_c = ["compiler_builtins/c"]
+compiler_builtins_c = ["alloc/compiler-builtins-c"]
 llvm-libunwind = ["unwind/llvm-libunwind"]
 
 # Make panics and failed asserts immediately abort without formatting any message
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index 4241f47b661..ff52974775b 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -173,6 +173,9 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
 /// about the allocation that failed.
 ///
 /// The allocation error hook is a global resource.
+///
+/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
+/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html
 #[unstable(feature = "alloc_error_hook", issue = "51245")]
 pub fn set_alloc_error_hook(hook: fn(Layout)) {
     HOOK.store(hook as *mut (), Ordering::SeqCst);
@@ -183,6 +186,8 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) {
 /// *See also the function [`set_alloc_error_hook`].*
 ///
 /// If no custom hook is registered, the default hook will be returned.
+///
+/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html
 #[unstable(feature = "alloc_error_hook", issue = "51245")]
 pub fn take_alloc_error_hook() -> fn(Layout) {
     let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 726c2732153..7a6c97ebaa2 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -20,8 +20,7 @@ fn main() {
     } else if target.contains("netbsd") {
         println!("cargo:rustc-link-lib=pthread");
         println!("cargo:rustc-link-lib=rt");
-    } else if target.contains("dragonfly") || target.contains("bitrig") ||
-              target.contains("openbsd") {
+    } else if target.contains("dragonfly") || target.contains("openbsd") {
         println!("cargo:rustc-link-lib=pthread");
     } else if target.contains("solaris") {
         println!("cargo:rustc-link-lib=socket");
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index f9fb392f9f5..5a2fe2b244f 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1225,11 +1225,13 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
 ///
 /// This is a lower-level version of [`Entry`].
 ///
-/// This `enum` is constructed from the [`raw_entry`] method on [`HashMap`].
+/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`],
+/// then calling one of the methods of that [`RawEntryBuilderMut`].
 ///
 /// [`HashMap`]: struct.HashMap.html
 /// [`Entry`]: enum.Entry.html
-/// [`raw_entry`]: struct.HashMap.html#method.raw_entry
+/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut
+/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> {
     /// An occupied entry.
@@ -2492,7 +2494,10 @@ impl DefaultHasher {
 
 #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
 impl Default for DefaultHasher {
-    /// Creates a new `DefaultHasher` using [`new`][DefaultHasher::new].
+    // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link
+    // resolution failure when re-exporting libstd items. When #56922 fixed,
+    // link `new` to [DefaultHasher::new] again.
+    /// Creates a new `DefaultHasher` using `new`.
     /// See its documentation for more.
     fn default() -> DefaultHasher {
         DefaultHasher::new()
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index b56a27c80bc..403914c0707 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -618,6 +618,62 @@ impl<T, S> HashSet<T, S>
         self.map.get_key_value(value).map(|(k, _)| k)
     }
 
+    /// Inserts the given `value` into the set if it is not present, then
+    /// returns a reference to the value in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// assert_eq!(set.len(), 3);
+    /// assert_eq!(set.get_or_insert(2), &2);
+    /// assert_eq!(set.get_or_insert(100), &100);
+    /// assert_eq!(set.len(), 4); // 100 was inserted
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get_or_insert(&mut self, value: T) -> &T {
+        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
+        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
+        self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0
+    }
+
+    /// Inserts a value computed from `f` into the set if the given `value` is
+    /// not present, then returns a reference to the value in the set.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set: HashSet<String> = ["cat", "dog", "horse"]
+    ///     .iter().map(|&pet| pet.to_owned()).collect();
+    ///
+    /// assert_eq!(set.len(), 3);
+    /// for &pet in &["cat", "dog", "fish"] {
+    ///     let value = set.get_or_insert_with(pet, str::to_owned);
+    ///     assert_eq!(value, pet);
+    /// }
+    /// assert_eq!(set.len(), 4); // a new "fish" was inserted
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get_or_insert_with<Q: ?Sized, F>(&mut self, value: &Q, f: F) -> &T
+        where T: Borrow<Q>,
+              Q: Hash + Eq,
+              F: FnOnce(&Q) -> T
+    {
+        // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with
+        // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`.
+        self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0
+    }
+
     /// Returns `true` if `self` has no elements in common with `other`.
     /// This is equivalent to checking for an empty intersection.
     ///
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index c0d0c23e469..260624a8bd8 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -746,6 +746,10 @@ impl Iterator for Args {
         self.inner.next().map(|s| s.into_string().unwrap())
     }
     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+    #[inline]
+    fn last(mut self) -> Option<String> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "env", since = "1.0.0")]
@@ -781,6 +785,8 @@ impl Iterator for ArgsOs {
     type Item = OsString;
     fn next(&mut self) -> Option<OsString> { self.inner.next() }
     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+    #[inline]
+    fn last(mut self) -> Option<OsString> { self.next_back() }
 }
 
 #[stable(feature = "env", since = "1.0.0")]
@@ -845,7 +851,6 @@ pub mod consts {
     /// - ios
     /// - freebsd
     /// - dragonfly
-    /// - bitrig
     /// - netbsd
     /// - openbsd
     /// - solaris
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 081fff0562b..aeb822fa99e 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -197,16 +197,29 @@ pub trait Error: Debug + Display {
     fn source(&self) -> Option<&(dyn Error + 'static)> { None }
 
     /// Gets the `TypeId` of `self`
-    #[stable(feature = "error_type_id", since = "1.34.0")]
-    fn type_id(&self) -> TypeId where Self: 'static {
+    #[doc(hidden)]
+    #[unstable(feature = "error_type_id",
+               reason = "this is memory unsafe to override in user code",
+               issue = "60784")]
+    fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static {
         TypeId::of::<Self>()
     }
 }
 
+mod private {
+    // This is a hack to prevent `type_id` from being overridden by `Error`
+    // implementations, since that can enable unsound downcasting.
+    #[unstable(feature = "error_type_id", issue = "60784")]
+    #[derive(Debug)]
+    pub struct Internal;
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
     /// Converts a type of [`Error`] into a box of dyn [`Error`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -244,6 +257,8 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
     /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of dyn [`Error`] +
     /// [`Send`] + [`Sync`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -285,6 +300,8 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
 impl From<String> for Box<dyn Error + Send + Sync> {
     /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -318,6 +335,8 @@ impl From<String> for Box<dyn Error + Send + Sync> {
 impl From<String> for Box<dyn Error> {
     /// Converts a [`String`] into a box of dyn [`Error`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -339,6 +358,8 @@ impl From<String> for Box<dyn Error> {
 impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
     /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -359,6 +380,8 @@ impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
 impl From<&str> for Box<dyn Error> {
     /// Converts a [`str`] into a box of dyn [`Error`].
     ///
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -378,6 +401,9 @@ impl From<&str> for Box<dyn Error> {
 impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
     /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
+    /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -399,6 +425,9 @@ impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
 impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
     /// Converts a [`Cow`] into a box of dyn [`Error`].
     ///
+    /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Error`]: ../error/trait.Error.html
+    ///
     /// # Examples
     ///
     /// ```
@@ -572,7 +601,7 @@ impl dyn Error + 'static {
         let t = TypeId::of::<T>();
 
         // Get TypeId of the type in the trait object
-        let boxed = self.type_id();
+        let boxed = self.type_id(private::Internal);
 
         // Compare both TypeIds on equality
         t == boxed
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index f93583dff81..5c6c43017cf 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -43,7 +43,9 @@ use crate::sys;
 /// `CString` implements a [`as_ptr`] method through the [`Deref`]
 /// trait. This method will give you a `*const c_char` which you can
 /// feed directly to extern functions that expect a nul-terminated
-/// string, like C's `strdup()`.
+/// string, like C's `strdup()`. Notice that [`as_ptr`] returns a
+/// read-only pointer; if the C code writes to it, that causes
+/// undefined behavior.
 ///
 /// # Extracting a slice of the whole C string
 ///
@@ -61,7 +63,7 @@ use crate::sys;
 ///
 /// Once you have the kind of slice you need (with or without a nul
 /// terminator), you can call the slice's own
-/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to
 /// extern functions. See the documentation for that function for a
 /// discussion on ensuring the lifetime of the raw pointer.
 ///
@@ -1043,6 +1045,9 @@ impl CStr {
     ///
     /// **WARNING**
     ///
+    /// The returned pointer is read-only; writing to it (including passing it
+    /// to C code that writes to it) causes undefined behavior.
+    ///
     /// It is your responsibility to make sure that the underlying memory is not
     /// freed too early. For example, the following code will cause undefined
     /// behavior when `ptr` is used inside the `unsafe` block:
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 13aee783750..c7c5849a00f 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -351,6 +351,8 @@ impl From<String> for OsString {
     /// Converts a [`String`] into a [`OsString`].
     ///
     /// The conversion copies the data, and includes an allocation on the heap.
+    ///
+    /// [`OsString`]: ../../std/ffi/struct.OsString.html
     fn from(s: String) -> OsString {
         OsString { inner: Buf::from_string(s) }
     }
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 991b45fd4a2..616b5eb836f 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1812,6 +1812,8 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 ///   function.)
 /// * `path` already exists.
 ///
+/// [`create_dir_all`]: fn.create_dir_all.html
+///
 /// # Examples
 ///
 /// ```no_run
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 5be2687d8f5..e309f81192c 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -754,7 +754,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
 /// completed, rather than the entire buffer at once. Enter `LineWriter`. It
 /// does exactly that.
 ///
-/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// Like [`BufWriter`][bufwriter], a `LineWriter`’s buffer will also be flushed when the
 /// `LineWriter` goes out of scope or when its internal buffer is full.
 ///
 /// [bufwriter]: struct.BufWriter.html
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 8fea6251e65..917199f8ea8 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1579,18 +1579,13 @@ pub trait BufRead: Read {
     /// let stdin = io::stdin();
     /// let mut stdin = stdin.lock();
     ///
-    /// // we can't have two `&mut` references to `stdin`, so use a block
-    /// // to end the borrow early.
-    /// let length = {
-    ///     let buffer = stdin.fill_buf().unwrap();
+    /// let buffer = stdin.fill_buf().unwrap();
     ///
-    ///     // work with buffer
-    ///     println!("{:?}", buffer);
-    ///
-    ///     buffer.len()
-    /// };
+    /// // work with buffer
+    /// println!("{:?}", buffer);
     ///
     /// // ensure the bytes we worked with aren't returned again later
+    /// let length = buffer.len();
     /// stdin.consume(length);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs
index ffe50f11e8a..d133c2f5cb1 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -1,6 +1,6 @@
 #[doc(keyword = "as")]
 //
-/// The keyword for casting a value to a type.
+/// Cast between types, or rename an import.
 ///
 /// `as` is most commonly used to turn primitive types into other primitive types, but it has other
 /// uses that include turning pointers into addresses, addresses into pointers, and pointers into
@@ -29,9 +29,18 @@
 /// [`crate`]: keyword.crate.html
 mod as_keyword { }
 
+#[doc(keyword = "break")]
+//
+/// Exit early from a loop.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod break_keyword { }
+
 #[doc(keyword = "const")]
 //
-/// The keyword for defining constants.
+/// Compile-time constants and deterministic functions.
 ///
 /// Sometimes a certain value is used many times throughout a program, and it can become
 /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to
@@ -83,9 +92,18 @@ mod as_keyword { }
 /// [Reference]: ../reference/items/constant-items.html
 mod const_keyword { }
 
+#[doc(keyword = "continue")]
+//
+/// Skip to the next iteration of a loop.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod continue_keyword { }
+
 #[doc(keyword = "crate")]
 //
-/// The `crate` keyword.
+/// A Rust binary or library.
 ///
 /// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are
 /// used to specify a dependency on a crate external to the one it's declared in. Crates are the
@@ -116,14 +134,24 @@ mod const_keyword { }
 /// [Reference]: ../reference/items/extern-crates.html
 mod crate_keyword { }
 
+#[doc(keyword = "else")]
+//
+/// What to do when an [`if`] condition does not hold.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`if`]: keyword.if.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod else_keyword { }
+
 #[doc(keyword = "enum")]
 //
-/// For defining enumerations.
+/// A type that can be any one of several variants.
 ///
 /// Enums in Rust are similar to those of other compiled languages like C, but have important
 /// differences that make them considerably more powerful. What Rust calls enums are more commonly
-/// known as [Algebraic Data Types] if you're coming from a functional programming background. The
-/// important detail is that each enum variant can have data to go along with it.
+/// known as [Algebraic Data Types][ADT] if you're coming from a functional programming background.
+/// The important detail is that each enum variant can have data to go along with it.
 ///
 /// ```rust
 /// # struct Coord;
@@ -166,7 +194,7 @@ mod crate_keyword { }
 ///
 /// For more information, take a look at the [Rust Book] or the [Reference]
 ///
-/// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type
+/// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type
 /// [`Option`]: option/enum.Option.html
 /// [Rust Book]: ../book/ch06-01-defining-an-enum.html
 /// [Reference]: ../reference/items/enumerations.html
@@ -174,7 +202,7 @@ mod enum_keyword { }
 
 #[doc(keyword = "extern")]
 //
-/// For external connections in Rust code.
+/// Link to or import external code.
 ///
 /// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`]
 /// keyword to make your Rust code aware of other Rust crates in your project, i.e., `extern crate
@@ -214,9 +242,19 @@ mod enum_keyword { }
 /// [Reference]: ../reference/items/external-blocks.html
 mod extern_keyword { }
 
+#[doc(keyword = "false")]
+//
+/// A value of type [`bool`] representing logical **false**.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`bool`]: primitive.bool.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod false_keyword { }
+
 #[doc(keyword = "fn")]
 //
-/// The keyword for defining functions.
+/// A function or function pointer.
 ///
 /// Functions are the primary way code is executed within Rust. Function blocks, usually just
 /// called functions, can be defined in a variety of different places and be assigned many
@@ -283,7 +321,8 @@ mod fn_keyword { }
 
 #[doc(keyword = "for")]
 //
-/// The `for` keyword.
+/// Iteration with [`in`], trait implementation with [`impl`], or [higher-ranked trait bounds]
+/// (`for<'a>`).
 ///
 /// The `for` keyword is used in many syntactic locations:
 ///
@@ -350,6 +389,7 @@ mod fn_keyword { }
 ///
 /// For more information on for-loops, see the [Rust book] or the [Reference].
 ///
+/// [`in`]: keyword.in.html
 /// [`impl`]: keyword.impl.html
 /// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds
 /// [`IntoIterator`]: iter/trait.IntoIterator.html
@@ -360,7 +400,7 @@ mod for_keyword { }
 
 #[doc(keyword = "if")]
 //
-/// If statements and expressions.
+/// Evaluate a block if a condition holds.
 ///
 /// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in
 /// your code. However, unlike in most languages, `if` blocks can also act as expressions.
@@ -434,7 +474,7 @@ mod if_keyword { }
 
 #[doc(keyword = "impl")]
 //
-/// The implementation-defining keyword.
+/// Implement some functionality for a type.
 ///
 /// The `impl` keyword is primarily used to define implementations on types. Inherent
 /// implementations are standalone, while trait implementations are used to implement traits for
@@ -495,9 +535,19 @@ mod if_keyword { }
 /// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits
 mod impl_keyword { }
 
+#[doc(keyword = "in")]
+//
+/// Iterate over a series of values with [`for`].
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`for`]: keyword.for.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod in_keyword { }
+
 #[doc(keyword = "let")]
 //
-/// The variable binding keyword.
+/// Bind a value to a variable.
 ///
 /// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new
 /// set of variables into the current scope, as given by a pattern.
@@ -560,7 +610,7 @@ mod let_keyword { }
 
 #[doc(keyword = "loop")]
 //
-/// The loop-defining keyword.
+/// Loop indefinitely.
 ///
 /// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside
 /// it until the code uses `break` or the program exits.
@@ -603,9 +653,104 @@ mod let_keyword { }
 /// [Reference]: ../reference/expressions/loop-expr.html
 mod loop_keyword { }
 
+#[doc(keyword = "match")]
+//
+/// Control flow based on pattern matching.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod match_keyword { }
+
+#[doc(keyword = "mod")]
+//
+/// Organize code into [modules].
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [modules]: ../reference/items/modules.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod mod_keyword { }
+
+#[doc(keyword = "move")]
+//
+/// Capture a [closure]'s environment by value.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [closure]: ../book/second-edition/ch13-01-closures.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod move_keyword { }
+
+#[doc(keyword = "mut")]
+//
+/// A mutable binding, reference, or pointer.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod mut_keyword { }
+
+#[doc(keyword = "pub")]
+//
+/// Make an item visible to others.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod pub_keyword { }
+
+#[doc(keyword = "ref")]
+//
+/// Bind by reference during pattern matching.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod ref_keyword { }
+
+#[doc(keyword = "return")]
+//
+/// Return a value from a function.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod return_keyword { }
+
+#[doc(keyword = "self")]
+//
+/// The receiver of a method, or the current module.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod self_keyword { }
+
+#[doc(keyword = "Self")]
+//
+/// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type
+/// definition.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`impl`]: keyword.impl.html
+/// [`trait`]: keyword.trait.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod self_upper_keyword { }
+
+#[doc(keyword = "static")]
+//
+/// A place that is valid for the duration of a program.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod static_keyword { }
+
 #[doc(keyword = "struct")]
 //
-/// The keyword used to define structs.
+/// A type that is composed of other types.
 ///
 /// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit
 /// structs.
@@ -710,3 +855,122 @@ mod loop_keyword { }
 /// [book]: ../book/ch05-01-defining-structs.html
 /// [reference]: ../reference/items/structs.html
 mod struct_keyword { }
+
+#[doc(keyword = "super")]
+//
+/// The parent of the current [module].
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [module]: ../reference/items/modules.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod super_keyword { }
+
+#[doc(keyword = "trait")]
+//
+/// A common interface for a class of types.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod trait_keyword { }
+
+#[doc(keyword = "true")]
+//
+/// A value of type [`bool`] representing logical **true**.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`bool`]: primitive.bool.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod true_keyword { }
+
+#[doc(keyword = "type")]
+//
+/// Define an alias for an existing type.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod type_keyword { }
+
+#[doc(keyword = "unsafe")]
+//
+/// Code or interfaces whose [memory safety] cannot be verified by the type system.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [memory safety]: ../book/ch19-01-unsafe-rust.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod unsafe_keyword { }
+
+#[doc(keyword = "use")]
+//
+/// Import or rename items from other crates or modules.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod use_keyword { }
+
+#[doc(keyword = "where")]
+//
+/// Add constraints that must be upheld to use an item.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod where_keyword { }
+
+#[doc(keyword = "while")]
+//
+/// Loop while a condition is upheld.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod while_keyword { }
+
+// 2018 Edition keywords
+
+#[unstable(feature = "async_await", issue = "50547")]
+#[doc(keyword = "async")]
+//
+/// Return a [`Future`] instead of blocking the current thread.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`Future`]: ./future/trait.Future.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod async_keyword { }
+
+#[unstable(feature = "async_await", issue = "50547")]
+#[doc(keyword = "await")]
+//
+/// Suspend execution until the result of a [`Future`] is ready.
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [`Future`]: ./future/trait.Future.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod await_keyword { }
+
+#[doc(keyword = "dyn")]
+//
+/// Name the type of a [trait object].
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [trait object]: ../book/ch17-02-trait-objects.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod dyn_keyword { }
+
+#[doc(keyword = "union")]
+//
+/// The [Rust equivalent of a C-style union][union].
+///
+/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+///
+/// [union]: ../reference/items/unions.html
+/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+mod union_keyword { }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 3976f2344e2..e044b46e0d0 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -223,6 +223,7 @@
 #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"),
             feature(global_asm, slice_index_methods,
                     decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))]
+#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))]
 
 // std is implemented with unstable features, many of which are internal
 // compiler details that will never be stable
@@ -271,7 +272,6 @@
 #![feature(libc)]
 #![feature(link_args)]
 #![feature(linkage)]
-#![feature(maybe_uninit)]
 #![feature(needs_panic_runtime)]
 #![feature(never_type)]
 #![feature(nll)]
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 03aebeda47c..9af7bba97aa 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -357,61 +357,6 @@ macro_rules! dbg {
     };
 }
 
-/// Selects the first successful receive event from a number of receivers.
-///
-/// This macro is used to wait for the first event to occur on a number of
-/// receivers. It places no restrictions on the types of receivers given to
-/// this macro, this can be viewed as a heterogeneous select.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(mpsc_select)]
-///
-/// use std::thread;
-/// use std::sync::mpsc;
-///
-/// // two placeholder functions for now
-/// fn long_running_thread() {}
-/// fn calculate_the_answer() -> u32 { 42 }
-///
-/// let (tx1, rx1) = mpsc::channel();
-/// let (tx2, rx2) = mpsc::channel();
-///
-/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); });
-/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); });
-///
-/// select! {
-///     _ = rx1.recv() => println!("the long running thread finished first"),
-///     answer = rx2.recv() => {
-///         println!("the answer was: {}", answer.unwrap());
-///     }
-/// }
-/// # drop(rx1.recv());
-/// # drop(rx2.recv());
-/// ```
-///
-/// For more information about select, see the `std::sync::mpsc::Select` structure.
-#[macro_export]
-#[unstable(feature = "mpsc_select", issue = "27800")]
-#[rustc_deprecated(since = "1.32.0",
-                   reason = "channel selection will be removed in a future release")]
-macro_rules! select {
-    (
-        $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
-    ) => ({
-        use $crate::sync::mpsc::Select;
-        let sel = Select::new();
-        $( let mut $rx = sel.handle(&$rx); )+
-        unsafe {
-            $( $rx.add(); )+
-        }
-        let ret = sel.wait();
-        $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
-        { unreachable!() }
-    })
-}
-
 #[cfg(test)]
 macro_rules! assert_approx_eq {
     ($a:expr, $b:expr) => ({
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index ec54d8a042a..ca86a175058 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -546,6 +546,9 @@ impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
 #[stable(feature = "ip_from_ip", since = "1.16.0")]
 impl From<SocketAddrV4> for SocketAddr {
     /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+    ///
+    /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html
+    /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4
     fn from(sock4: SocketAddrV4) -> SocketAddr {
         SocketAddr::V4(sock4)
     }
@@ -554,6 +557,9 @@ impl From<SocketAddrV4> for SocketAddr {
 #[stable(feature = "ip_from_ip", since = "1.16.0")]
 impl From<SocketAddrV6> for SocketAddr {
     /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+    ///
+    /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html
+    /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6
     fn from(sock6: SocketAddrV6) -> SocketAddr {
         SocketAddr::V6(sock6)
     }
@@ -567,6 +573,13 @@ impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
     /// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`].
     ///
     /// `u16` is treated as port of the newly created [`SocketAddr`].
+    ///
+    /// [`IpAddr`]: ../../std/net/enum.IpAddr.html
+    /// [`IpAddr::V4`]: ../../std/net/enum.IpAddr.html#variant.V4
+    /// [`IpAddr::V6`]: ../../std/net/enum.IpAddr.html#variant.V6
+    /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
+    /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4
+    /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6
     fn from(pieces: (I, u16)) -> SocketAddr {
         SocketAddr::new(pieces.0.into(), pieces.1)
     }
@@ -974,9 +987,9 @@ mod tests {
         // s has been moved into the tsa call
     }
 
-    // FIXME: figure out why this fails on openbsd and bitrig and fix it
+    // FIXME: figure out why this fails on openbsd and fix it
     #[test]
-    #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))]
+    #[cfg(not(any(windows, target_os = "openbsd")))]
     fn to_socket_addr_str_bad() {
         assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err());
     }
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index 0460ac9d753..cdffa390223 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1595,9 +1595,9 @@ mod tests {
         assert_eq!(format!("{:?}", stream), compare);
     }
 
-    // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code
+    // FIXME: re-enabled openbsd tests once their socket timeout code
     //        no longer has rounding errors.
-    #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+    #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)]
     #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
     #[test]
     fn timeouts() {
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index d4187d2932b..61d9149952e 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -1024,9 +1024,9 @@ mod tests {
         assert_eq!(format!("{:?}", udpsock), compare);
     }
 
-    // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code
+    // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
     //        no longer has rounding errors.
-    #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+    #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)]
     #[test]
     fn timeouts() {
         let addr = next_test_ip4();
diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs
deleted file mode 100644
index b5c6903c410..00000000000
--- a/src/libstd/os/bitrig/fs.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use crate::fs::Metadata;
-use crate::sys_common::AsInner;
-
-#[allow(deprecated)]
-use crate::os::bitrig::raw;
-
-/// OS-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned `stat` are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(since = "1.8.0",
-                       reason = "deprecated in favor of the accessor \
-                                 methods of this trait")]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_birthtime_nsec(&self) -> i64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_flags(&self) -> u32;
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gen(&self) -> u32;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe {
-            &*(self.as_inner().as_inner() as *const libc::stat
-                                          as *const raw::stat)
-        }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_birthtime(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime as i64
-    }
-    fn st_birthtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_birthtime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-    fn st_gen(&self) -> u32 {
-        self.as_inner().as_inner().st_gen as u32
-    }
-    fn st_flags(&self) -> u32 {
-        self.as_inner().as_inner().st_flags as u32
-    }
-}
diff --git a/src/libstd/os/bitrig/mod.rs b/src/libstd/os/bitrig/mod.rs
deleted file mode 100644
index 0bc105bb2b4..00000000000
--- a/src/libstd/os/bitrig/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! Bitrig-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-pub mod raw;
-pub mod fs;
diff --git a/src/libstd/os/bitrig/raw.rs b/src/libstd/os/bitrig/raw.rs
deleted file mode 100644
index c966d5a8e5b..00000000000
--- a/src/libstd/os/bitrig/raw.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-//! Bitrig-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(since = "1.8.0",
-                    reason = "these type aliases are no longer supported by \
-                              the standard library, the `libc` crate on \
-                              crates.io should be used instead for the correct \
-                              definitions")]
-#![allow(deprecated)]
-
-use crate::os::raw::c_long;
-use crate::os::unix::raw::{uid_t, gid_t};
-
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mode: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_dev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ino: u64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_nlink: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_uid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gid: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_rdev: i32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_atime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime: u64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_mtime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_ctime_nsec: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_size: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blocks: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_blksize: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_flags: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_gen: u32,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime: i64,
-    #[stable(feature = "raw_ext", since = "1.1.0")]
-    pub st_birthtime_nsec: i64,
-}
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
index 7b56d6d62cf..44cbc180b8b 100644
--- a/src/libstd/os/mod.rs
+++ b/src/libstd/os/mod.rs
@@ -39,7 +39,6 @@ cfg_if! {
 }
 
 #[cfg(target_os = "android")]    pub mod android;
-#[cfg(target_os = "bitrig")]     pub mod bitrig;
 #[cfg(target_os = "dragonfly")]  pub mod dragonfly;
 #[cfg(target_os = "freebsd")]    pub mod freebsd;
 #[cfg(target_os = "haiku")]      pub mod haiku;
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 126bc3754da..59f9e439add 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -888,6 +888,11 @@ impl<'a> Iterator for Iter<'a> {
     fn next(&mut self) -> Option<&'a OsStr> {
         self.inner.next().map(Component::as_os_str)
     }
+
+    #[inline]
+    fn last(mut self) -> Option<&'a OsStr> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -951,6 +956,11 @@ impl<'a> Iterator for Components<'a> {
         }
         None
     }
+
+    #[inline]
+    fn last(mut self) -> Option<Self::Item> {
+        self.next_back()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 04353fde1b4..69ecd201063 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -116,7 +116,6 @@
 //! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![allow(deprecated)] // for mpsc_select
 
 // A description of how Rust's channel implementation works
 //
@@ -263,6 +262,8 @@
 // believe that there is anything fundamental that needs to change about these
 // channels, however, in order to support a more efficient select().
 //
+// FIXME: Select is now removed, so these factors are ready to be cleaned up!
+//
 // # Conclusion
 //
 // And now that you've seen all the races that I found and attempted to fix,
@@ -275,18 +276,8 @@ use crate::mem;
 use crate::cell::UnsafeCell;
 use crate::time::{Duration, Instant};
 
-#[unstable(feature = "mpsc_select", issue = "27800")]
-pub use self::select::{Select, Handle};
-use self::select::StartResult;
-use self::select::StartResult::*;
-use self::blocking::SignalToken;
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod select_tests;
-
 mod blocking;
 mod oneshot;
-mod select;
 mod shared;
 mod stream;
 mod sync;
@@ -1514,78 +1505,6 @@ impl<T> Receiver<T> {
 
 }
 
-impl<T> select::Packet for Receiver<T> {
-    fn can_recv(&self) -> bool {
-        loop {
-            let new_port = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => {
-                    match p.can_recv() {
-                        Ok(ret) => return ret,
-                        Err(upgrade) => upgrade,
-                    }
-                }
-                Flavor::Stream(ref p) => {
-                    match p.can_recv() {
-                        Ok(ret) => return ret,
-                        Err(upgrade) => upgrade,
-                    }
-                }
-                Flavor::Shared(ref p) => return p.can_recv(),
-                Flavor::Sync(ref p) => return p.can_recv(),
-            };
-            unsafe {
-                mem::swap(self.inner_mut(),
-                          new_port.inner_mut());
-            }
-        }
-    }
-
-    fn start_selection(&self, mut token: SignalToken) -> StartResult {
-        loop {
-            let (t, new_port) = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => {
-                    match p.start_selection(token) {
-                        oneshot::SelSuccess => return Installed,
-                        oneshot::SelCanceled => return Abort,
-                        oneshot::SelUpgraded(t, rx) => (t, rx),
-                    }
-                }
-                Flavor::Stream(ref p) => {
-                    match p.start_selection(token) {
-                        stream::SelSuccess => return Installed,
-                        stream::SelCanceled => return Abort,
-                        stream::SelUpgraded(t, rx) => (t, rx),
-                    }
-                }
-                Flavor::Shared(ref p) => return p.start_selection(token),
-                Flavor::Sync(ref p) => return p.start_selection(token),
-            };
-            token = t;
-            unsafe {
-                mem::swap(self.inner_mut(), new_port.inner_mut());
-            }
-        }
-    }
-
-    fn abort_selection(&self) -> bool {
-        let mut was_upgrade = false;
-        loop {
-            let result = match *unsafe { self.inner() } {
-                Flavor::Oneshot(ref p) => p.abort_selection(),
-                Flavor::Stream(ref p) => p.abort_selection(was_upgrade),
-                Flavor::Shared(ref p) => return p.abort_selection(was_upgrade),
-                Flavor::Sync(ref p) => return p.abort_selection(),
-            };
-            let new_port = match result { Ok(b) => return b, Err(p) => p };
-            was_upgrade = true;
-            unsafe {
-                mem::swap(self.inner_mut(),
-                          new_port.inner_mut());
-            }
-        }
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> Iterator for Iter<'a, T> {
     type Item = T;
diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs
index 5c516d5de0f..e7a5cc46b31 100644
--- a/src/libstd/sync/mpsc/oneshot.rs
+++ b/src/libstd/sync/mpsc/oneshot.rs
@@ -24,7 +24,6 @@
 
 pub use self::Failure::*;
 pub use self::UpgradeResult::*;
-pub use self::SelectionResult::*;
 use self::MyUpgrade::*;
 
 use crate::sync::mpsc::Receiver;
@@ -66,12 +65,6 @@ pub enum UpgradeResult {
     UpWoke(SignalToken),
 }
 
-pub enum SelectionResult<T> {
-    SelCanceled,
-    SelUpgraded(SignalToken, Receiver<T>),
-    SelSuccess,
-}
-
 enum MyUpgrade<T> {
     NothingSent,
     SendUsed,
@@ -264,71 +257,6 @@ impl<T> Packet<T> {
     // select implementation
     ////////////////////////////////////////////////////////////////////////////
 
-    // If Ok, the value is whether this port has data, if Err, then the upgraded
-    // port needs to be checked instead of this one.
-    pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
-        unsafe {
-            match self.state.load(Ordering::SeqCst) {
-                EMPTY => Ok(false), // Welp, we tried
-                DATA => Ok(true),   // we have some un-acquired data
-                DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data
-                DISCONNECTED => {
-                    match ptr::replace(self.upgrade.get(), SendUsed) {
-                        // The other end sent us an upgrade, so we need to
-                        // propagate upwards whether the upgrade can receive
-                        // data
-                        GoUp(upgrade) => Err(upgrade),
-
-                        // If the other end disconnected without sending an
-                        // upgrade, then we have data to receive (the channel is
-                        // disconnected).
-                        up => { ptr::write(self.upgrade.get(), up); Ok(true) }
-                    }
-                }
-                _ => unreachable!(), // we're the "one blocker"
-            }
-        }
-    }
-
-    // Attempts to start selection on this port. This can either succeed, fail
-    // because there is data, or fail because there is an upgrade pending.
-    pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
-        unsafe {
-            let ptr = token.cast_to_usize();
-            match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) {
-                EMPTY => SelSuccess,
-                DATA => {
-                    drop(SignalToken::cast_from_usize(ptr));
-                    SelCanceled
-                }
-                DISCONNECTED if (*self.data.get()).is_some() => {
-                    drop(SignalToken::cast_from_usize(ptr));
-                    SelCanceled
-                }
-                DISCONNECTED => {
-                    match ptr::replace(self.upgrade.get(), SendUsed) {
-                        // The other end sent us an upgrade, so we need to
-                        // propagate upwards whether the upgrade can receive
-                        // data
-                        GoUp(upgrade) => {
-                            SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade)
-                        }
-
-                        // If the other end disconnected without sending an
-                        // upgrade, then we have data to receive (the channel is
-                        // disconnected).
-                        up => {
-                            ptr::write(self.upgrade.get(), up);
-                            drop(SignalToken::cast_from_usize(ptr));
-                            SelCanceled
-                        }
-                    }
-                }
-                _ => unreachable!(), // we're the "one blocker"
-            }
-        }
-    }
-
     // Remove a previous selecting thread from this port. This ensures that the
     // blocked thread will no longer be visible to any other threads.
     //
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
deleted file mode 100644
index d1b5f2deccc..00000000000
--- a/src/libstd/sync/mpsc/select.rs
+++ /dev/null
@@ -1,352 +0,0 @@
-//! Selection over an array of receivers
-//!
-//! This module contains the implementation machinery necessary for selecting
-//! over a number of receivers. One large goal of this module is to provide an
-//! efficient interface to selecting over any receiver of any type.
-//!
-//! This is achieved through an architecture of a "receiver set" in which
-//! receivers are added to a set and then the entire set is waited on at once.
-//! The set can be waited on multiple times to prevent re-adding each receiver
-//! to the set.
-//!
-//! Usage of this module is currently encouraged to go through the use of the
-//! `select!` macro. This macro allows naturally binding of variables to the
-//! received values of receivers in a much more natural syntax then usage of the
-//! `Select` structure directly.
-//!
-//! # Examples
-//!
-//! ```rust
-//! #![feature(mpsc_select)]
-//!
-//! use std::sync::mpsc::channel;
-//!
-//! let (tx1, rx1) = channel();
-//! let (tx2, rx2) = channel();
-//!
-//! tx1.send(1).unwrap();
-//! tx2.send(2).unwrap();
-//!
-//! select! {
-//!     val = rx1.recv() => {
-//!         assert_eq!(val.unwrap(), 1);
-//!     },
-//!     val = rx2.recv() => {
-//!         assert_eq!(val.unwrap(), 2);
-//!     }
-//! }
-//! ```
-
-#![allow(dead_code)]
-#![unstable(feature = "mpsc_select",
-            reason = "This implementation, while likely sufficient, is unsafe and \
-                      likely to be error prone. At some point in the future this \
-                      module will be removed.",
-            issue = "27800")]
-#![rustc_deprecated(since = "1.32.0",
-                    reason = "channel selection will be removed in a future release")]
-
-use core::cell::{Cell, UnsafeCell};
-use core::marker;
-use core::ptr;
-use core::usize;
-
-use crate::fmt;
-use crate::sync::mpsc::{Receiver, RecvError};
-use crate::sync::mpsc::blocking::{self, SignalToken};
-
-/// The "receiver set" of the select interface. This structure is used to manage
-/// a set of receivers which are being selected over.
-pub struct Select {
-    inner: UnsafeCell<SelectInner>,
-    next_id: Cell<usize>,
-}
-
-struct SelectInner {
-    head: *mut Handle<'static, ()>,
-    tail: *mut Handle<'static, ()>,
-}
-
-impl !marker::Send for Select {}
-
-/// A handle to a receiver which is currently a member of a `Select` set of
-/// receivers. This handle is used to keep the receiver in the set as well as
-/// interact with the underlying receiver.
-pub struct Handle<'rx, T:Send+'rx> {
-    /// The ID of this handle, used to compare against the return value of
-    /// `Select::wait()`.
-    id: usize,
-    selector: *mut SelectInner,
-    next: *mut Handle<'static, ()>,
-    prev: *mut Handle<'static, ()>,
-    added: bool,
-    packet: &'rx (dyn Packet+'rx),
-
-    // due to our fun transmutes, we be sure to place this at the end. (nothing
-    // previous relies on T)
-    rx: &'rx Receiver<T>,
-}
-
-struct Packets { cur: *mut Handle<'static, ()> }
-
-#[doc(hidden)]
-#[derive(PartialEq, Eq)]
-pub enum StartResult {
-    Installed,
-    Abort,
-}
-
-#[doc(hidden)]
-pub trait Packet {
-    fn can_recv(&self) -> bool;
-    fn start_selection(&self, token: SignalToken) -> StartResult;
-    fn abort_selection(&self) -> bool;
-}
-
-impl Select {
-    /// Creates a new selection structure. This set is initially empty.
-    ///
-    /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through
-    /// the `select!` macro.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(mpsc_select)]
-    ///
-    /// use std::sync::mpsc::Select;
-    ///
-    /// let select = Select::new();
-    /// ```
-    pub fn new() -> Select {
-        Select {
-            inner: UnsafeCell::new(SelectInner {
-                head: ptr::null_mut(),
-                tail: ptr::null_mut(),
-            }),
-            next_id: Cell::new(1),
-        }
-    }
-
-    /// Creates a new handle into this receiver set for a new receiver. Note
-    /// that this does *not* add the receiver to the receiver set, for that you
-    /// must call the `add` method on the handle itself.
-    pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver<T>) -> Handle<'a, T> {
-        let id = self.next_id.get();
-        self.next_id.set(id + 1);
-        Handle {
-            id,
-            selector: self.inner.get(),
-            next: ptr::null_mut(),
-            prev: ptr::null_mut(),
-            added: false,
-            rx,
-            packet: rx,
-        }
-    }
-
-    /// Waits for an event on this receiver set. The returned value is *not* an
-    /// index, but rather an ID. This ID can be queried against any active
-    /// `Handle` structures (each one has an `id` method). The handle with
-    /// the matching `id` will have some sort of event available on it. The
-    /// event could either be that data is available or the corresponding
-    /// channel has been closed.
-    pub fn wait(&self) -> usize {
-        self.wait2(true)
-    }
-
-    /// Helper method for skipping the preflight checks during testing
-    pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize {
-        // Note that this is currently an inefficient implementation. We in
-        // theory have knowledge about all receivers in the set ahead of time,
-        // so this method shouldn't really have to iterate over all of them yet
-        // again. The idea with this "receiver set" interface is to get the
-        // interface right this time around, and later this implementation can
-        // be optimized.
-        //
-        // This implementation can be summarized by:
-        //
-        //      fn select(receivers) {
-        //          if any receiver ready { return ready index }
-        //          deschedule {
-        //              block on all receivers
-        //          }
-        //          unblock on all receivers
-        //          return ready index
-        //      }
-        //
-        // Most notably, the iterations over all of the receivers shouldn't be
-        // necessary.
-        unsafe {
-            // Stage 1: preflight checks. Look for any packets ready to receive
-            if do_preflight_checks {
-                for handle in self.iter() {
-                    if (*handle).packet.can_recv() {
-                        return (*handle).id();
-                    }
-                }
-            }
-
-            // Stage 2: begin the blocking process
-            //
-            // Create a number of signal tokens, and install each one
-            // sequentially until one fails. If one fails, then abort the
-            // selection on the already-installed tokens.
-            let (wait_token, signal_token) = blocking::tokens();
-            for (i, handle) in self.iter().enumerate() {
-                match (*handle).packet.start_selection(signal_token.clone()) {
-                    StartResult::Installed => {}
-                    StartResult::Abort => {
-                        // Go back and abort the already-begun selections
-                        for handle in self.iter().take(i) {
-                            (*handle).packet.abort_selection();
-                        }
-                        return (*handle).id;
-                    }
-                }
-            }
-
-            // Stage 3: no messages available, actually block
-            wait_token.wait();
-
-            // Stage 4: there *must* be message available; find it.
-            //
-            // Abort the selection process on each receiver. If the abort
-            // process returns `true`, then that means that the receiver is
-            // ready to receive some data. Note that this also means that the
-            // receiver may have yet to have fully read the `to_wake` field and
-            // woken us up (although the wakeup is guaranteed to fail).
-            //
-            // This situation happens in the window of where a sender invokes
-            // increment(), sees -1, and then decides to wake up the thread. After
-            // all this is done, the sending thread will set `selecting` to
-            // `false`. Until this is done, we cannot return. If we were to
-            // return, then a sender could wake up a receiver which has gone
-            // back to sleep after this call to `select`.
-            //
-            // Note that it is a "fairly small window" in which an increment()
-            // views that it should wake a thread up until the `selecting` bit
-            // is set to false. For now, the implementation currently just spins
-            // in a yield loop. This is very distasteful, but this
-            // implementation is already nowhere near what it should ideally be.
-            // A rewrite should focus on avoiding a yield loop, and for now this
-            // implementation is tying us over to a more efficient "don't
-            // iterate over everything every time" implementation.
-            let mut ready_id = usize::MAX;
-            for handle in self.iter() {
-                if (*handle).packet.abort_selection() {
-                    ready_id = (*handle).id;
-                }
-            }
-
-            // We must have found a ready receiver
-            assert!(ready_id != usize::MAX);
-            return ready_id;
-        }
-    }
-
-    fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } }
-}
-
-impl<'rx, T: Send> Handle<'rx, T> {
-    /// Retrieves the ID of this handle.
-    #[inline]
-    pub fn id(&self) -> usize { self.id }
-
-    /// Blocks to receive a value on the underlying receiver, returning `Some` on
-    /// success or `None` if the channel disconnects. This function has the same
-    /// semantics as `Receiver.recv`
-    pub fn recv(&mut self) -> Result<T, RecvError> { self.rx.recv() }
-
-    /// Adds this handle to the receiver set that the handle was created from. This
-    /// method can be called multiple times, but it has no effect if `add` was
-    /// called previously.
-    ///
-    /// This method is unsafe because it requires that the `Handle` is not moved
-    /// while it is added to the `Select` set.
-    pub unsafe fn add(&mut self) {
-        if self.added { return }
-        let selector = &mut *self.selector;
-        let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
-
-        if selector.head.is_null() {
-            selector.head = me;
-            selector.tail = me;
-        } else {
-            (*me).prev = selector.tail;
-            assert!((*me).next.is_null());
-            (*selector.tail).next = me;
-            selector.tail = me;
-        }
-        self.added = true;
-    }
-
-    /// Removes this handle from the `Select` set. This method is unsafe because
-    /// it has no guarantee that the `Handle` was not moved since `add` was
-    /// called.
-    pub unsafe fn remove(&mut self) {
-        if !self.added { return }
-
-        let selector = &mut *self.selector;
-        let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>;
-
-        if self.prev.is_null() {
-            assert_eq!(selector.head, me);
-            selector.head = self.next;
-        } else {
-            (*self.prev).next = self.next;
-        }
-        if self.next.is_null() {
-            assert_eq!(selector.tail, me);
-            selector.tail = self.prev;
-        } else {
-            (*self.next).prev = self.prev;
-        }
-
-        self.next = ptr::null_mut();
-        self.prev = ptr::null_mut();
-
-        self.added = false;
-    }
-}
-
-impl Drop for Select {
-    fn drop(&mut self) {
-        unsafe {
-            assert!((&*self.inner.get()).head.is_null());
-            assert!((&*self.inner.get()).tail.is_null());
-        }
-    }
-}
-
-impl<T: Send> Drop for Handle<'_, T> {
-    fn drop(&mut self) {
-        unsafe { self.remove() }
-    }
-}
-
-impl Iterator for Packets {
-    type Item = *mut Handle<'static, ()>;
-
-    fn next(&mut self) -> Option<*mut Handle<'static, ()>> {
-        if self.cur.is_null() {
-            None
-        } else {
-            let ret = Some(self.cur);
-            unsafe { self.cur = (*self.cur).next; }
-            ret
-        }
-    }
-}
-
-impl fmt::Debug for Select {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Select").finish()
-    }
-}
-
-impl<T: Send> fmt::Debug for Handle<'_, T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Handle").finish()
-    }
-}
diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs
deleted file mode 100644
index 18d93462c78..00000000000
--- a/src/libstd/sync/mpsc/select_tests.rs
+++ /dev/null
@@ -1,413 +0,0 @@
-#![allow(unused_imports)]
-
-/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238
-
-use crate::thread;
-use crate::sync::mpsc::*;
-
-// Don't use the libstd version so we can pull in the right Select structure
-// (std::comm points at the wrong one)
-macro_rules! select {
-    (
-        $($name:pat = $rx:ident.$meth:ident() => $code:expr),+
-    ) => ({
-        let sel = Select::new();
-        $( let mut $rx = sel.handle(&$rx); )+
-        unsafe {
-            $( $rx.add(); )+
-        }
-        let ret = sel.wait();
-        $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
-        { unreachable!() }
-    })
-}
-
-#[test]
-fn smoke() {
-    let (tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    tx1.send(1).unwrap();
-    select! {
-        foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
-        _bar = rx2.recv() => { panic!() }
-    }
-    tx2.send(2).unwrap();
-    select! {
-        _foo = rx1.recv() => { panic!() },
-        bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
-    }
-    drop(tx1);
-    select! {
-        foo = rx1.recv() => { assert!(foo.is_err()); },
-        _bar = rx2.recv() => { panic!() }
-    }
-    drop(tx2);
-    select! {
-        bar = rx2.recv() => { assert!(bar.is_err()); }
-    }
-}
-
-#[test]
-fn smoke2() {
-    let (_tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (_tx3, rx3) = channel::<i32>();
-    let (_tx4, rx4) = channel::<i32>();
-    let (tx5, rx5) = channel::<i32>();
-    tx5.send(4).unwrap();
-    select! {
-        _foo = rx1.recv() => { panic!("1") },
-        _foo = rx2.recv() => { panic!("2") },
-        _foo = rx3.recv() => { panic!("3") },
-        _foo = rx4.recv() => { panic!("4") },
-        foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
-    }
-}
-
-#[test]
-fn closed() {
-    let (_tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    drop(tx2);
-
-    select! {
-        _a1 = rx1.recv() => { panic!() },
-        a2 = rx2.recv() => { assert!(a2.is_err()); }
-    }
-}
-
-#[test]
-fn unblocks() {
-    let (tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<i32>();
-
-    let _t = thread::spawn(move|| {
-        for _ in 0..20 { thread::yield_now(); }
-        tx1.send(1).unwrap();
-        rx3.recv().unwrap();
-        for _ in 0..20 { thread::yield_now(); }
-    });
-
-    select! {
-        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-        _b = rx2.recv() => { panic!() }
-    }
-    tx3.send(1).unwrap();
-    select! {
-        a = rx1.recv() => { assert!(a.is_err()) },
-        _b = rx2.recv() => { panic!() }
-    }
-}
-
-#[test]
-fn both_ready() {
-    let (tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        for _ in 0..20 { thread::yield_now(); }
-        tx1.send(1).unwrap();
-        tx2.send(2).unwrap();
-        rx3.recv().unwrap();
-    });
-
-    select! {
-        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-        a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
-    }
-    select! {
-        a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
-        a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
-    }
-    assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
-    assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
-    tx3.send(()).unwrap();
-}
-
-#[test]
-fn stress() {
-    const AMT: i32 = 10000;
-    let (tx1, rx1) = channel::<i32>();
-    let (tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        for i in 0..AMT {
-            if i % 2 == 0 {
-                tx1.send(i).unwrap();
-            } else {
-                tx2.send(i).unwrap();
-            }
-            rx3.recv().unwrap();
-        }
-    });
-
-    for i in 0..AMT {
-        select! {
-            i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
-            i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
-        }
-        tx3.send(()).unwrap();
-    }
-}
-
-#[allow(unused_must_use)]
-#[test]
-fn cloning() {
-    let (tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        rx3.recv().unwrap();
-        tx1.clone();
-        assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
-        tx1.send(2).unwrap();
-        rx3.recv().unwrap();
-    });
-
-    tx3.send(()).unwrap();
-    select! {
-        _i1 = rx1.recv() => {},
-        _i2 = rx2.recv() => panic!()
-    }
-    tx3.send(()).unwrap();
-}
-
-#[allow(unused_must_use)]
-#[test]
-fn cloning2() {
-    let (tx1, rx1) = channel::<i32>();
-    let (_tx2, rx2) = channel::<i32>();
-    let (tx3, rx3) = channel::<()>();
-
-    let _t = thread::spawn(move|| {
-        rx3.recv().unwrap();
-        tx1.clone();
-        assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
-        tx1.send(2).unwrap();
-        rx3.recv().unwrap();
-    });
-
-    tx3.send(()).unwrap();
-    select! {
-        _i1 = rx1.recv() => {},
-        _i2 = rx2.recv() => panic!()
-    }
-    tx3.send(()).unwrap();
-}
-
-#[test]
-fn cloning3() {
-    let (tx1, rx1) = channel::<()>();
-    let (tx2, rx2) = channel::<()>();
-    let (tx3, rx3) = channel::<()>();
-    let _t = thread::spawn(move|| {
-        let s = Select::new();
-        let mut h1 = s.handle(&rx1);
-        let mut h2 = s.handle(&rx2);
-        unsafe { h2.add(); }
-        unsafe { h1.add(); }
-        assert_eq!(s.wait(), h2.id());
-        tx3.send(()).unwrap();
-    });
-
-    for _ in 0..1000 { thread::yield_now(); }
-    drop(tx1.clone());
-    tx2.send(()).unwrap();
-    rx3.recv().unwrap();
-}
-
-#[test]
-fn preflight1() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    select! {
-        _n = rx.recv() => {}
-    }
-}
-
-#[test]
-fn preflight2() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    tx.send(()).unwrap();
-    select! {
-        _n = rx.recv() => {}
-    }
-}
-
-#[test]
-fn preflight3() {
-    let (tx, rx) = channel();
-    drop(tx.clone());
-    tx.send(()).unwrap();
-    select! {
-        _n = rx.recv() => {}
-    }
-}
-
-#[test]
-fn preflight4() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight5() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    tx.send(()).unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight6() {
-    let (tx, rx) = channel();
-    drop(tx.clone());
-    tx.send(()).unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight7() {
-    let (tx, rx) = channel::<()>();
-    drop(tx);
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight8() {
-    let (tx, rx) = channel();
-    tx.send(()).unwrap();
-    drop(tx);
-    rx.recv().unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn preflight9() {
-    let (tx, rx) = channel();
-    drop(tx.clone());
-    tx.send(()).unwrap();
-    drop(tx);
-    rx.recv().unwrap();
-    let s = Select::new();
-    let mut h = s.handle(&rx);
-    unsafe { h.add(); }
-    assert_eq!(s.wait2(false), h.id());
-}
-
-#[test]
-fn oneshot_data_waiting() {
-    let (tx1, rx1) = channel();
-    let (tx2, rx2) = channel();
-    let _t = thread::spawn(move|| {
-        select! {
-            _n = rx1.recv() => {}
-        }
-        tx2.send(()).unwrap();
-    });
-
-    for _ in 0..100 { thread::yield_now() }
-    tx1.send(()).unwrap();
-    rx2.recv().unwrap();
-}
-
-#[test]
-fn stream_data_waiting() {
-    let (tx1, rx1) = channel();
-    let (tx2, rx2) = channel();
-    tx1.send(()).unwrap();
-    tx1.send(()).unwrap();
-    rx1.recv().unwrap();
-    rx1.recv().unwrap();
-    let _t = thread::spawn(move|| {
-        select! {
-            _n = rx1.recv() => {}
-        }
-        tx2.send(()).unwrap();
-    });
-
-    for _ in 0..100 { thread::yield_now() }
-    tx1.send(()).unwrap();
-    rx2.recv().unwrap();
-}
-
-#[test]
-fn shared_data_waiting() {
-    let (tx1, rx1) = channel();
-    let (tx2, rx2) = channel();
-    drop(tx1.clone());
-    tx1.send(()).unwrap();
-    rx1.recv().unwrap();
-    let _t = thread::spawn(move|| {
-        select! {
-            _n = rx1.recv() => {}
-        }
-        tx2.send(()).unwrap();
-    });
-
-    for _ in 0..100 { thread::yield_now() }
-    tx1.send(()).unwrap();
-    rx2.recv().unwrap();
-}
-
-#[test]
-fn sync1() {
-    let (tx, rx) = sync_channel::<i32>(1);
-    tx.send(1).unwrap();
-    select! {
-        n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
-    }
-}
-
-#[test]
-fn sync2() {
-    let (tx, rx) = sync_channel::<i32>(0);
-    let _t = thread::spawn(move|| {
-        for _ in 0..100 { thread::yield_now() }
-        tx.send(1).unwrap();
-    });
-    select! {
-        n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
-    }
-}
-
-#[test]
-fn sync3() {
-    let (tx1, rx1) = sync_channel::<i32>(0);
-    let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
-    let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
-    let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
-    select! {
-        n = rx1.recv() => {
-            let n = n.unwrap();
-            assert_eq!(n, 1);
-            assert_eq!(rx2.recv().unwrap(), 2);
-        },
-        n = rx2.recv() => {
-            let n = n.unwrap();
-            assert_eq!(n, 2);
-            assert_eq!(rx1.recv().unwrap(), 1);
-        }
-    }
-}
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
index cc70a620365..dbcdcdac932 100644
--- a/src/libstd/sync/mpsc/shared.rs
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -9,6 +9,7 @@
 /// channels are quite similar, and this is no coincidence!
 
 pub use self::Failure::*;
+use self::StartResult::*;
 
 use core::cmp;
 use core::intrinsics::abort;
@@ -19,8 +20,6 @@ use crate::ptr;
 use crate::sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering};
 use crate::sync::mpsc::blocking::{self, SignalToken};
 use crate::sync::mpsc::mpsc_queue as mpsc;
-use crate::sync::mpsc::select::StartResult::*;
-use crate::sync::mpsc::select::StartResult;
 use crate::sync::{Mutex, MutexGuard};
 use crate::thread;
 use crate::time::Instant;
@@ -57,6 +56,12 @@ pub enum Failure {
     Disconnected,
 }
 
+#[derive(PartialEq, Eq)]
+enum StartResult {
+    Installed,
+    Abort,
+}
+
 impl<T> Packet<T> {
     // Creation of a packet *must* be followed by a call to postinit_lock
     // and later by inherit_blocker
@@ -394,16 +399,6 @@ impl<T> Packet<T> {
     // select implementation
     ////////////////////////////////////////////////////////////////////////////
 
-    // Helper function for select, tests whether this port can receive without
-    // blocking (obviously not an atomic decision).
-    //
-    // This is different than the stream version because there's no need to peek
-    // at the queue, we can just look at the local count.
-    pub fn can_recv(&self) -> bool {
-        let cnt = self.cnt.load(Ordering::SeqCst);
-        cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0
-    }
-
     // increment the count on the channel (used for selection)
     fn bump(&self, amt: isize) -> isize {
         match self.cnt.fetch_add(amt, Ordering::SeqCst) {
@@ -415,22 +410,6 @@ impl<T> Packet<T> {
         }
     }
 
-    // Inserts the signal token for selection on this port, returning true if
-    // blocking should proceed.
-    //
-    // The code here is the same as in stream.rs, except that it doesn't need to
-    // peek at the channel to see if an upgrade is pending.
-    pub fn start_selection(&self, token: SignalToken) -> StartResult {
-        match self.decrement(token) {
-            Installed => Installed,
-            Abort => {
-                let prev = self.bump(1);
-                assert!(prev == DISCONNECTED || prev >= 0);
-                Abort
-            }
-        }
-    }
-
     // Cancels a previous thread waiting on this port, returning whether there's
     // data on the port.
     //
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
index 7ae6f68b514..40877282761 100644
--- a/src/libstd/sync/mpsc/stream.rs
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -9,7 +9,6 @@
 
 pub use self::Failure::*;
 pub use self::UpgradeResult::*;
-pub use self::SelectionResult::*;
 use self::Message::*;
 
 use core::cmp;
@@ -60,12 +59,6 @@ pub enum UpgradeResult {
     UpWoke(SignalToken),
 }
 
-pub enum SelectionResult<T> {
-    SelSuccess,
-    SelCanceled,
-    SelUpgraded(SignalToken, Receiver<T>),
-}
-
 // Any message could contain an "upgrade request" to a new shared port, so the
 // internal queue it's a queue of T, but rather Message<T>
 enum Message<T> {
@@ -338,27 +331,6 @@ impl<T> Packet<T> {
     // select implementation
     ////////////////////////////////////////////////////////////////////////////
 
-    // Tests to see whether this port can receive without blocking. If Ok is
-    // returned, then that's the answer. If Err is returned, then the returned
-    // port needs to be queried instead (an upgrade happened)
-    pub fn can_recv(&self) -> Result<bool, Receiver<T>> {
-        // We peek at the queue to see if there's anything on it, and we use
-        // this return value to determine if we should pop from the queue and
-        // upgrade this channel immediately. If it looks like we've got an
-        // upgrade pending, then go through the whole recv rigamarole to update
-        // the internal state.
-        match self.queue.peek() {
-            Some(&mut GoUp(..)) => {
-                match self.recv(None) {
-                    Err(Upgraded(port)) => Err(port),
-                    _ => unreachable!(),
-                }
-            }
-            Some(..) => Ok(true),
-            None => Ok(false)
-        }
-    }
-
     // increment the count on the channel (used for selection)
     fn bump(&self, amt: isize) -> isize {
         match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
@@ -370,31 +342,6 @@ impl<T> Packet<T> {
         }
     }
 
-    // Attempts to start selecting on this port. Like a oneshot, this can fail
-    // immediately because of an upgrade.
-    pub fn start_selection(&self, token: SignalToken) -> SelectionResult<T> {
-        match self.decrement(token) {
-            Ok(()) => SelSuccess,
-            Err(token) => {
-                let ret = match self.queue.peek() {
-                    Some(&mut GoUp(..)) => {
-                        match self.queue.pop() {
-                            Some(GoUp(port)) => SelUpgraded(token, port),
-                            _ => unreachable!(),
-                        }
-                    }
-                    Some(..) => SelCanceled,
-                    None => SelCanceled,
-                };
-                // Undo our decrement above, and we should be guaranteed that the
-                // previous value is positive because we're not going to sleep
-                let prev = self.bump(1);
-                assert!(prev == DISCONNECTED || prev >= 0);
-                ret
-            }
-        }
-    }
-
     // Removes a previous thread from being blocked in this port
     pub fn abort_selection(&self,
                            was_upgrade: bool) -> Result<bool, Receiver<T>> {
diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs
index b2d9f4c6491..3c4f8e077c9 100644
--- a/src/libstd/sync/mpsc/sync.rs
+++ b/src/libstd/sync/mpsc/sync.rs
@@ -33,7 +33,6 @@ use core::ptr;
 
 use crate::sync::atomic::{Ordering, AtomicUsize};
 use crate::sync::mpsc::blocking::{self, WaitToken, SignalToken};
-use crate::sync::mpsc::select::StartResult::{self, Installed, Abort};
 use crate::sync::{Mutex, MutexGuard};
 use crate::time::Instant;
 
@@ -406,42 +405,6 @@ impl<T> Packet<T> {
         while let Some(token) = queue.dequeue() { token.signal(); }
         waiter.map(|t| t.signal());
     }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // select implementation
-    ////////////////////////////////////////////////////////////////////////////
-
-    // If Ok, the value is whether this port has data, if Err, then the upgraded
-    // port needs to be checked instead of this one.
-    pub fn can_recv(&self) -> bool {
-        let guard = self.lock.lock().unwrap();
-        guard.disconnected || guard.buf.size() > 0
-    }
-
-    // Attempts to start selection on this port. This can either succeed or fail
-    // because there is data waiting.
-    pub fn start_selection(&self, token: SignalToken) -> StartResult {
-        let mut guard = self.lock.lock().unwrap();
-        if guard.disconnected || guard.buf.size() > 0 {
-            Abort
-        } else {
-            match mem::replace(&mut guard.blocker, BlockedReceiver(token)) {
-                NoneBlocked => {}
-                BlockedSender(..) => unreachable!(),
-                BlockedReceiver(..) => unreachable!(),
-            }
-            Installed
-        }
-    }
-
-    // Remove a previous selecting thread from this port. This ensures that the
-    // blocked thread will no longer be visible to any other threads.
-    //
-    // The return value indicates whether there's data on this port.
-    pub fn abort_selection(&self) -> bool {
-        let mut guard = self.lock.lock().unwrap();
-        abort_selection(&mut guard)
-    }
 }
 
 impl<T> Drop for Packet<T> {
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 11ac34fcb24..87c2318a937 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -376,6 +376,8 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
 impl<T> From<T> for Mutex<T> {
     /// Creates a new mutex in an unlocked state ready for use.
     /// This is equivalent to [`Mutex::new`].
+    ///
+    /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new
     fn from(t: T) -> Self {
         Mutex::new(t)
     }
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index 1299a744095..b1b56f321fc 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -453,6 +453,8 @@ impl<T: Default> Default for RwLock<T> {
 impl<T> From<T> for RwLock<T> {
     /// Creates a new instance of an `RwLock<T>` which is unlocked.
     /// This is equivalent to [`RwLock::new`].
+    ///
+    /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new
     fn from(t: T) -> Self {
         RwLock::new(t)
     }
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
index 18de1096df2..6ba947d4598 100644
--- a/src/libstd/sys/unix/args.rs
+++ b/src/libstd/sys/unix/args.rs
@@ -35,6 +35,8 @@ impl Iterator for Args {
     type Item = OsString;
     fn next(&mut self) -> Option<OsString> { self.iter.next() }
     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+    #[inline]
+    fn last(mut self) -> Option<OsString> { self.next_back() }
 }
 
 impl ExactSizeIterator for Args {
@@ -49,7 +51,6 @@ impl DoubleEndedIterator for Args {
           target_os = "android",
           target_os = "freebsd",
           target_os = "dragonfly",
-          target_os = "bitrig",
           target_os = "netbsd",
           target_os = "openbsd",
           target_os = "solaris",
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
index f9592d5c45f..891013406a1 100644
--- a/src/libstd/sys/unix/env.rs
+++ b/src/libstd/sys/unix/env.rs
@@ -53,17 +53,6 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "";
 }
 
-#[cfg(target_os = "bitrig")]
-pub mod os {
-    pub const FAMILY: &str = "unix";
-    pub const OS: &str = "bitrig";
-    pub const DLL_PREFIX: &str = "lib";
-    pub const DLL_SUFFIX: &str = ".so";
-    pub const DLL_EXTENSION: &str = "so";
-    pub const EXE_SUFFIX: &str = "";
-    pub const EXE_EXTENSION: &str = "";
-}
-
 #[cfg(target_os = "netbsd")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index 45a850aa4a8..3ccb0a1b1ab 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -32,12 +32,12 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner};
 #[cfg(any(target_os = "linux", target_os = "android",
           target_os = "dragonfly", target_os = "freebsd",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "haiku", target_os = "bitrig"))]
+          target_os = "haiku"))]
 use libc::MSG_NOSIGNAL;
 #[cfg(not(any(target_os = "linux", target_os = "android",
               target_os = "dragonfly", target_os = "freebsd",
               target_os = "openbsd", target_os = "netbsd",
-              target_os = "haiku", target_os = "bitrig")))]
+              target_os = "haiku")))]
 const MSG_NOSIGNAL: libc::c_int = 0x0;
 
 fn sun_path_offset() -> usize {
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 22c05a72a91..cc1f0790d43 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -147,8 +147,7 @@ impl FileAttr {
         }))
     }
 
-    #[cfg(any(target_os = "bitrig",
-              target_os = "freebsd",
+    #[cfg(any(target_os = "freebsd",
               target_os = "openbsd",
               target_os = "macos",
               target_os = "ios"))]
@@ -159,8 +158,7 @@ impl FileAttr {
         }))
     }
 
-    #[cfg(not(any(target_os = "bitrig",
-                  target_os = "freebsd",
+    #[cfg(not(any(target_os = "freebsd",
                   target_os = "openbsd",
                   target_os = "macos",
                   target_os = "ios")))]
@@ -355,7 +353,6 @@ impl DirEntry {
 
     #[cfg(any(target_os = "freebsd",
               target_os = "openbsd",
-              target_os = "bitrig",
               target_os = "netbsd",
               target_os = "dragonfly"))]
     pub fn ino(&self) -> u64 {
@@ -367,8 +364,7 @@ impl DirEntry {
               target_os = "netbsd",
               target_os = "openbsd",
               target_os = "freebsd",
-              target_os = "dragonfly",
-              target_os = "bitrig"))]
+              target_os = "dragonfly"))]
     fn name_bytes(&self) -> &[u8] {
         use crate::slice;
         unsafe {
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 90e26449ae2..c2b264ff8de 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -5,7 +5,6 @@ use crate::io::ErrorKind;
 #[cfg(any(rustdoc, target_os = "linux"))] pub use crate::os::linux as platform;
 
 #[cfg(all(not(rustdoc), target_os = "android"))]   pub use crate::os::android as platform;
-#[cfg(all(not(rustdoc), target_os = "bitrig"))]    pub use crate::os::bitrig as platform;
 #[cfg(all(not(rustdoc), target_os = "dragonfly"))] pub use crate::os::dragonfly as platform;
 #[cfg(all(not(rustdoc), target_os = "freebsd"))]   pub use crate::os::freebsd as platform;
 #[cfg(all(not(rustdoc), target_os = "haiku"))]     pub use crate::os::haiku as platform;
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 726b17969b7..dad19eabf7d 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -33,8 +33,7 @@ extern {
                    target_os = "fuchsia",
                    target_os = "l4re"),
                link_name = "__errno_location")]
-    #[cfg_attr(any(target_os = "bitrig",
-                   target_os = "netbsd",
+    #[cfg_attr(any(target_os = "netbsd",
                    target_os = "openbsd",
                    target_os = "android",
                    target_os = "hermit",
@@ -257,7 +256,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     sysctl().or_else(|_| procfs())
 }
 
-#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+#[cfg(target_os = "openbsd")]
 pub fn current_exe() -> io::Result<PathBuf> {
     unsafe {
         let mut mib = [libc::CTL_KERN,
diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs
index e923b9aa29b..71c62461ee9 100644
--- a/src/libstd/sys/unix/rand.rs
+++ b/src/libstd/sys/unix/rand.rs
@@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 
 #[cfg(all(unix,
           not(target_os = "ios"),
-          not(all(target_os = "macos", miri)),
           not(target_os = "openbsd"),
           not(target_os = "freebsd"),
           not(target_os = "fuchsia")))]
@@ -48,7 +47,12 @@ mod imp {
                 let err = errno() as libc::c_int;
                 if err == libc::EINTR {
                     continue;
-                } else if err == libc::ENOSYS {
+                } else if err == libc::ENOSYS || err == libc::EPERM {
+                    // Fall back to reading /dev/urandom if `getrandom` is not
+                    // supported on the current kernel.
+                    //
+                    // Also fall back in case it is disabled by something like
+                    // seccomp or inside of virtual machines.
                     GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                     return false;
                 } else if err == libc::EAGAIN {
@@ -107,9 +111,7 @@ mod imp {
 // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
 // only used on iOS where direct access to `/dev/urandom` is blocked by the
 // sandbox.
-// HACK: However, we do use this when running in Miri on macOS; intercepting this is much
-// easier than intercepting accesses to /dev/urandom.
-#[cfg(any(target_os = "ios", all(target_os = "macos", miri)))]
+#[cfg(target_os = "ios")]
 mod imp {
     use crate::io;
     use crate::ptr;
diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs
index 561279e8278..fe1095fa0c2 100644
--- a/src/libstd/sys/unix/stack_overflow.rs
+++ b/src/libstd/sys/unix/stack_overflow.rs
@@ -25,7 +25,6 @@ impl Drop for Handler {
 
 #[cfg(any(target_os = "linux",
           target_os = "macos",
-          target_os = "bitrig",
           target_os = "dragonfly",
           target_os = "freebsd",
           target_os = "solaris",
@@ -139,7 +138,6 @@ mod imp {
 
     #[cfg(any(target_os = "linux",
               target_os = "macos",
-              target_os = "bitrig",
               target_os = "freebsd",
               target_os = "netbsd",
               target_os = "openbsd",
@@ -185,7 +183,6 @@ mod imp {
 
 #[cfg(not(any(target_os = "linux",
               target_os = "macos",
-              target_os = "bitrig",
               target_os = "dragonfly",
               target_os = "freebsd",
               target_os = "solaris",
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index f7d604ac4c8..f4a1783ce89 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -99,7 +99,6 @@ impl Thread {
 
     #[cfg(any(target_os = "freebsd",
               target_os = "dragonfly",
-              target_os = "bitrig",
               target_os = "openbsd"))]
     pub fn set_name(name: &CStr) {
         unsafe {
@@ -189,7 +188,6 @@ impl Drop for Thread {
 #[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
           not(target_os = "freebsd"),
           not(target_os = "macos"),
-          not(target_os = "bitrig"),
           not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
           not(target_os = "openbsd"),
           not(target_os = "solaris")))]
@@ -205,7 +203,6 @@ pub mod guard {
 #[cfg(any(all(target_os = "linux", not(target_env = "musl")),
           target_os = "freebsd",
           target_os = "macos",
-          target_os = "bitrig",
           all(target_os = "netbsd", not(target_vendor = "rumprun")),
           target_os = "openbsd",
           target_os = "solaris"))]
@@ -236,16 +233,15 @@ pub mod guard {
         Some(stackaddr as *mut libc::c_void)
     }
 
-    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+    #[cfg(target_os = "openbsd")]
     unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
         let mut current_stack: libc::stack_t = crate::mem::zeroed();
         assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                              &mut current_stack), 0);
 
-        let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
         let stackaddr = if libc::pthread_main_np() == 1 {
             // main thread
-            current_stack.ss_sp as usize - current_stack.ss_size + extra
+            current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE
         } else {
             // new thread
             current_stack.ss_sp as usize - current_stack.ss_size
@@ -343,7 +339,6 @@ pub mod guard {
     }
 
     #[cfg(any(target_os = "macos",
-              target_os = "bitrig",
               target_os = "openbsd",
               target_os = "solaris"))]
     pub unsafe fn current() -> Option<Guard> {
diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs
index b3c77b86995..6766099c1ec 100644
--- a/src/libstd/sys/wasm/args.rs
+++ b/src/libstd/sys/wasm/args.rs
@@ -37,6 +37,10 @@ impl Iterator for Args {
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
+    #[inline]
+    fn last(mut self) -> Option<OsString> {
+        self.next_back()
+    }
 }
 
 impl ExactSizeIterator for Args {
diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs
index b04bb484eed..744d7ec59d3 100644
--- a/src/libstd/sys/windows/args.rs
+++ b/src/libstd/sys/windows/args.rs
@@ -181,6 +181,8 @@ impl Iterator for Args {
     type Item = OsString;
     fn next(&mut self) -> Option<OsString> { self.parsed_args_list.next() }
     fn size_hint(&self) -> (usize, Option<usize>) { self.parsed_args_list.size_hint() }
+    #[inline]
+    fn last(mut self) -> Option<OsString> { self.next_back() }
 }
 
 impl DoubleEndedIterator for Args {
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
index cf1dc20b52f..391f670346f 100644
--- a/src/libstd/sys_common/net.rs
+++ b/src/libstd/sys_common/net.rs
@@ -37,12 +37,12 @@ use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
 #[cfg(any(target_os = "linux", target_os = "android",
           target_os = "dragonfly", target_os = "freebsd",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "haiku", target_os = "bitrig"))]
+          target_os = "haiku"))]
 use libc::MSG_NOSIGNAL;
 #[cfg(not(any(target_os = "linux", target_os = "android",
               target_os = "dragonfly", target_os = "freebsd",
               target_os = "openbsd", target_os = "netbsd",
-              target_os = "haiku", target_os = "bitrig")))]
+              target_os = "haiku")))]
 const MSG_NOSIGNAL: c_int = 0x0;
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index fce28ffd9c3..35de4f4008b 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -443,6 +443,7 @@ impl Builder {
     /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
     /// [`io::Result`]: ../../std/io/type.Result.html
     /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+    /// [`JoinHandle::join`]: ../../std/thread/struct.JoinHandle.html#method.join
     #[unstable(feature = "thread_spawn_unchecked", issue = "55132")]
     pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
         F: FnOnce() -> T, F: Send + 'a, T: Send + 'a
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index af2302d24f5..a6bb47bef87 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -6,6 +6,7 @@ pub use crate::symbol::{Ident, Symbol as Name};
 pub use crate::util::parser::ExprPrecedence;
 
 use crate::ext::hygiene::{Mark, SyntaxContext};
+use crate::parse::token;
 use crate::print::pprust;
 use crate::ptr::P;
 use crate::source_map::{dummy_spanned, respan, Spanned};
@@ -15,7 +16,7 @@ use crate::ThinVec;
 
 use rustc_data_structures::indexed_vec::Idx;
 #[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert;
+use rustc_data_structures::static_assert_size;
 use rustc_target::spec::abi::Abi;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -71,21 +72,11 @@ pub struct Path {
 impl PartialEq<Symbol> for Path {
     fn eq(&self, symbol: &Symbol) -> bool {
         self.segments.len() == 1 && {
-            let name = self.segments[0].ident.name;
-            // Make sure these symbols are pure strings
-            debug_assert!(!symbol.is_gensymed());
-            debug_assert!(!name.is_gensymed());
-            name == *symbol
+            self.segments[0].ident.name == *symbol
         }
     }
 }
 
-impl<'a> PartialEq<&'a str> for Path {
-    fn eq(&self, string: &&'a str) -> bool {
-        self.segments.len() == 1 && self.segments[0].ident.name == *string
-    }
-}
-
 impl fmt::Debug for Path {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "path({})", pprust::path_to_string(self))
@@ -969,7 +960,7 @@ pub struct Expr {
 
 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 96);
+static_assert_size!(Expr, 96);
 
 impl Expr {
     /// Whether this expression would be valid somewhere that expects a value; for example, an `if`
@@ -1350,8 +1341,19 @@ pub enum StrStyle {
     Raw(u16),
 }
 
-/// A literal.
-pub type Lit = Spanned<LitKind>;
+/// An AST literal.
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct Lit {
+    /// The original literal token as written in source code.
+    pub token: token::Lit,
+    /// The original literal suffix as written in source code.
+    pub suffix: Option<Symbol>,
+    /// The "semantic" representation of the literal lowered from the original tokens.
+    /// Strings are unescaped, hexadecimal forms are eliminated, etc.
+    /// FIXME: Remove this and only create the semantic representation during lowering to HIR.
+    pub node: LitKind,
+    pub span: Span,
+}
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)]
 pub enum LitIntType {
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index db821f4e536..65ca96afab1 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -5,7 +5,7 @@ use crate::feature_gate::{Features, GatedCfg};
 use crate::parse::ParseSess;
 
 use errors::{Applicability, Handler};
-use syntax_pos::{symbol::Symbol, Span};
+use syntax_pos::{symbol::Symbol, symbol::sym, Span};
 
 use super::{mark_used, MetaItemKind};
 
@@ -80,13 +80,13 @@ pub enum UnwindAttr {
 /// Determine what `#[unwind]` attribute is present in `attrs`, if any.
 pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
     attrs.iter().fold(None, |ia, attr| {
-        if attr.check_name("unwind") {
+        if attr.check_name(sym::unwind) {
             if let Some(meta) = attr.meta() {
                 if let MetaItemKind::List(items) = meta.node {
                     if items.len() == 1 {
-                        if items[0].check_name("allowed") {
+                        if items[0].check_name(sym::allowed) {
                             return Some(UnwindAttr::Allowed);
-                        } else if items[0].check_name("aborts") {
+                        } else if items[0].check_name(sym::aborts) {
                             return Some(UnwindAttr::Aborts);
                         }
                     }
@@ -153,9 +153,9 @@ pub struct RustcDeprecation {
 
 /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
 /// This will not perform any "sanity checks" on the form of the attributes.
-pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
+pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
     attrs.iter().any(|item| {
-        item.check_name("feature") &&
+        item.check_name(sym::feature) &&
         item.meta_item_list().map(|list| {
             list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name))
         }).unwrap_or(false)
@@ -185,12 +185,12 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
 
     'outer: for attr in attrs_iter {
         if ![
-            "rustc_deprecated",
-            "rustc_const_unstable",
-            "unstable",
-            "stable",
-            "rustc_promotable",
-            "rustc_allow_const_fn_ptr",
+            sym::rustc_deprecated,
+            sym::rustc_const_unstable,
+            sym::unstable,
+            sym::stable,
+            sym::rustc_promotable,
+            sym::rustc_allow_const_fn_ptr,
         ].iter().any(|&s| attr.path == s) {
             continue // not a stability level
         }
@@ -199,10 +199,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
 
         let meta = attr.meta();
 
-        if attr.path == "rustc_promotable" {
+        if attr.path == sym::rustc_promotable {
             promotable = true;
         }
-        if attr.path == "rustc_allow_const_fn_ptr" {
+        if attr.path == sym::rustc_allow_const_fn_ptr {
             allow_const_fn_ptr = true;
         }
         // attributes with data
@@ -229,10 +229,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                     )+
                     for meta in metas {
                         if let Some(mi) = meta.meta_item() {
-                            match mi.name_or_empty().get() {
+                            match mi.name_or_empty() {
                                 $(
-                                    stringify!($name)
-                                        => if !get(mi, &mut $name) { continue 'outer },
+                                    sym::$name => if !get(mi, &mut $name) { continue 'outer },
                                 )+
                                 _ => {
                                     let expected = &[ $( stringify!($name) ),+ ];
@@ -259,8 +258,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                 }
             }
 
-            match meta.name_or_empty().get() {
-                "rustc_deprecated" => {
+            match meta.name_or_empty() {
+                sym::rustc_deprecated => {
                     if rustc_depr.is_some() {
                         span_err!(diagnostic, item_sp, E0540,
                                   "multiple rustc_deprecated attributes");
@@ -287,7 +286,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         }
                     }
                 }
-                "rustc_const_unstable" => {
+                sym::rustc_const_unstable => {
                     if rustc_const_unstable.is_some() {
                         span_err!(diagnostic, item_sp, E0553,
                                   "multiple rustc_const_unstable attributes");
@@ -302,7 +301,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         continue
                     }
                 }
-                "unstable" => {
+                sym::unstable => {
                     if stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
                         break
@@ -313,10 +312,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                     let mut issue = None;
                     for meta in metas {
                         if let Some(mi) = meta.meta_item() {
-                            match mi.name_or_empty().get() {
-                                "feature" => if !get(mi, &mut feature) { continue 'outer },
-                                "reason" => if !get(mi, &mut reason) { continue 'outer },
-                                "issue" => if !get(mi, &mut issue) { continue 'outer },
+                            match mi.name_or_empty() {
+                                sym::feature => if !get(mi, &mut feature) { continue 'outer },
+                                sym::reason => if !get(mi, &mut reason) { continue 'outer },
+                                sym::issue => if !get(mi, &mut issue) { continue 'outer },
                                 _ => {
                                     handle_errors(
                                         sess,
@@ -374,7 +373,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         }
                     }
                 }
-                "stable" => {
+                sym::stable => {
                     if stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
                         break
@@ -385,11 +384,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                     for meta in metas {
                         match meta {
                             NestedMetaItem::MetaItem(mi) => {
-                                match mi.name_or_empty().get() {
-                                    "feature" =>
-                                        if !get(mi, &mut feature) { continue 'outer },
-                                    "since" =>
-                                        if !get(mi, &mut since) { continue 'outer },
+                                match mi.name_or_empty() {
+                                    sym::feature => if !get(mi, &mut feature) { continue 'outer },
+                                    sym::since => if !get(mi, &mut since) { continue 'outer },
                                     _ => {
                                         handle_errors(
                                             sess,
@@ -482,7 +479,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
 }
 
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
-    super::first_attr_value_str_by_name(attrs, "crate_name")
+    super::first_attr_value_str_by_name(attrs, sym::crate_name)
 }
 
 /// Tests if a cfg-pattern matches the cfg set
@@ -542,14 +539,14 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
 
             // The unwraps below may look dangerous, but we've already asserted
             // that they won't fail with the loop above.
-            match cfg.name_or_empty().get() {
-                "any" => mis.iter().any(|mi| {
+            match cfg.name_or_empty() {
+                sym::any => mis.iter().any(|mi| {
                     eval_condition(mi.meta_item().unwrap(), sess, eval)
                 }),
-                "all" => mis.iter().all(|mi| {
+                sym::all => mis.iter().all(|mi| {
                     eval_condition(mi.meta_item().unwrap(), sess, eval)
                 }),
-                "not" => {
+                sym::not => {
                     if mis.len() != 1 {
                         span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
                         return false;
@@ -593,7 +590,7 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
     let diagnostic = &sess.span_diagnostic;
 
     'outer: for attr in attrs_iter {
-        if !attr.check_name("deprecated") {
+        if !attr.check_name(sym::deprecated) {
             continue;
         }
 
@@ -645,9 +642,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
                 for meta in list {
                     match meta {
                         NestedMetaItem::MetaItem(mi) => {
-                            match mi.name_or_empty().get() {
-                                "since" => if !get(mi, &mut since) { continue 'outer },
-                                "note" => if !get(mi, &mut note) { continue 'outer },
+                            match mi.name_or_empty() {
+                                sym::since => if !get(mi, &mut since) { continue 'outer },
+                                sym::note => if !get(mi, &mut note) { continue 'outer },
                                 _ => {
                                     handle_errors(
                                         sess,
@@ -721,7 +718,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
 
     let mut acc = Vec::new();
     let diagnostic = &sess.span_diagnostic;
-    if attr.path == "repr" {
+    if attr.path == sym::repr {
         if let Some(items) = attr.meta_item_list() {
             mark_used(attr);
             for item in items {
@@ -739,11 +736,11 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
 
                 let mut recognised = false;
                 if item.is_word() {
-                    let hint = match item.name_or_empty().get() {
-                        "C" => Some(ReprC),
-                        "packed" => Some(ReprPacked(1)),
-                        "simd" => Some(ReprSimd),
-                        "transparent" => Some(ReprTransparent),
+                    let hint = match item.name_or_empty() {
+                        sym::C => Some(ReprC),
+                        sym::packed => Some(ReprPacked(1)),
+                        sym::simd => Some(ReprSimd),
+                        sym::transparent => Some(ReprTransparent),
                         name => int_type_of_word(name).map(ReprInt),
                     };
 
@@ -770,14 +767,14 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                     };
 
                     let mut literal_error = None;
-                    if name == "align" {
+                    if name == sym::align {
                         recognised = true;
                         match parse_alignment(&value.node) {
                             Ok(literal) => acc.push(ReprAlign(literal)),
                             Err(message) => literal_error = Some(message)
                         };
                     }
-                    else if name == "packed" {
+                    else if name == sym::packed {
                         recognised = true;
                         match parse_alignment(&value.node) {
                             Ok(literal) => acc.push(ReprPacked(literal)),
@@ -790,7 +787,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                     }
                 } else {
                     if let Some(meta_item) = item.meta_item() {
-                        if meta_item.check_name("align") {
+                        if meta_item.check_name(sym::align) {
                             if let MetaItemKind::NameValue(ref value) = meta_item.node {
                                 recognised = true;
                                 let mut err = struct_span_err!(diagnostic, item.span(), E0693,
@@ -830,22 +827,22 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
     acc
 }
 
-fn int_type_of_word(s: &str) -> Option<IntType> {
+fn int_type_of_word(s: Symbol) -> Option<IntType> {
     use IntType::*;
 
     match s {
-        "i8" => Some(SignedInt(ast::IntTy::I8)),
-        "u8" => Some(UnsignedInt(ast::UintTy::U8)),
-        "i16" => Some(SignedInt(ast::IntTy::I16)),
-        "u16" => Some(UnsignedInt(ast::UintTy::U16)),
-        "i32" => Some(SignedInt(ast::IntTy::I32)),
-        "u32" => Some(UnsignedInt(ast::UintTy::U32)),
-        "i64" => Some(SignedInt(ast::IntTy::I64)),
-        "u64" => Some(UnsignedInt(ast::UintTy::U64)),
-        "i128" => Some(SignedInt(ast::IntTy::I128)),
-        "u128" => Some(UnsignedInt(ast::UintTy::U128)),
-        "isize" => Some(SignedInt(ast::IntTy::Isize)),
-        "usize" => Some(UnsignedInt(ast::UintTy::Usize)),
+        sym::i8 => Some(SignedInt(ast::IntTy::I8)),
+        sym::u8 => Some(UnsignedInt(ast::UintTy::U8)),
+        sym::i16 => Some(SignedInt(ast::IntTy::I16)),
+        sym::u16 => Some(UnsignedInt(ast::UintTy::U16)),
+        sym::i32 => Some(SignedInt(ast::IntTy::I32)),
+        sym::u32 => Some(UnsignedInt(ast::UintTy::U32)),
+        sym::i64 => Some(SignedInt(ast::IntTy::I64)),
+        sym::u64 => Some(UnsignedInt(ast::UintTy::U64)),
+        sym::i128 => Some(SignedInt(ast::IntTy::I128)),
+        sym::u128 => Some(UnsignedInt(ast::UintTy::U128)),
+        sym::isize => Some(SignedInt(ast::IntTy::Isize)),
+        sym::usize => Some(UnsignedInt(ast::UintTy::Usize)),
         _ => None
     }
 }
diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs
index e00f91e3952..592b40df176 100644
--- a/src/libsyntax/attr/mod.rs
+++ b/src/libsyntax/attr/mod.rs
@@ -14,15 +14,15 @@ pub use StabilityLevel::*;
 use crate::ast;
 use crate::ast::{AttrId, Attribute, AttrStyle, Name, Ident, Path, PathSegment};
 use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
-use crate::ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam};
+use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
 use crate::mut_visit::visit_clobber;
-use crate::source_map::{BytePos, Spanned, respan, dummy_spanned};
+use crate::source_map::{BytePos, Spanned, dummy_spanned};
 use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use crate::parse::parser::Parser;
 use crate::parse::{self, ParseSess, PResult};
 use crate::parse::token::{self, Token};
 use crate::ptr::P;
-use crate::symbol::{keywords, LocalInternedString, Symbol};
+use crate::symbol::{keywords, Symbol, sym};
 use crate::ThinVec;
 use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
 use crate::GLOBALS;
@@ -81,10 +81,7 @@ impl NestedMetaItem {
     }
 
     /// Returns `true` if this list item is a MetaItem with a name of `name`.
-    pub fn check_name<T>(&self, name: T) -> bool
-    where
-        Path: PartialEq<T>,
-    {
+    pub fn check_name(&self, name: Symbol) -> bool {
         self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
     }
 
@@ -92,8 +89,8 @@ impl NestedMetaItem {
     pub fn ident(&self) -> Option<Ident> {
         self.meta_item().and_then(|meta_item| meta_item.ident())
     }
-    pub fn name_or_empty(&self) -> LocalInternedString {
-        self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or(keywords::Invalid.ident()).name
     }
 
     /// Gets the string value if self is a MetaItem and the MetaItem is a
@@ -154,10 +151,7 @@ impl Attribute {
     /// attribute is marked as used.
     ///
     /// To check the attribute name without marking it used, use the `path` field directly.
-    pub fn check_name<T>(&self, name: T) -> bool
-    where
-        Path: PartialEq<T>,
-    {
+    pub fn check_name(&self, name: Symbol) -> bool {
         let matches = self.path == name;
         if matches {
             mark_used(self);
@@ -173,8 +167,8 @@ impl Attribute {
             None
         }
     }
-    pub fn name_or_empty(&self) -> LocalInternedString {
-        self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or(keywords::Invalid.ident()).name
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
@@ -211,8 +205,8 @@ impl MetaItem {
             None
         }
     }
-    pub fn name_or_empty(&self) -> LocalInternedString {
-        self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or(keywords::Invalid.ident()).name
     }
 
     // #[attribute(name = "value")]
@@ -250,10 +244,7 @@ impl MetaItem {
         }
     }
 
-    pub fn check_name<T>(&self, name: T) -> bool
-    where
-        Path: PartialEq<T>,
-    {
+    pub fn check_name(&self, name: Symbol) -> bool {
         self.path == name
     }
 
@@ -332,7 +323,7 @@ impl Attribute {
         if self.is_sugared_doc {
             let comment = self.value_str().unwrap();
             let meta = mk_name_value_item_str(
-                Ident::from_str("doc"),
+                Ident::with_empty_ctxt(sym::doc),
                 dummy_spanned(Symbol::intern(&strip_doc_comment_decoration(&comment.as_str()))));
             let mut attr = if self.style == ast::AttrStyle::Outer {
                 mk_attr_outer(self.span, self.id, meta)
@@ -350,12 +341,13 @@ impl Attribute {
 /* Constructors */
 
 pub fn mk_name_value_item_str(ident: Ident, value: Spanned<Symbol>) -> MetaItem {
-    let value = respan(value.span, LitKind::Str(value.node, ast::StrStyle::Cooked));
-    mk_name_value_item(ident.span.to(value.span), ident, value)
+    let lit_kind = LitKind::Str(value.node, ast::StrStyle::Cooked);
+    mk_name_value_item(ident.span.to(value.span), ident, lit_kind, value.span)
 }
 
-pub fn mk_name_value_item(span: Span, ident: Ident, value: ast::Lit) -> MetaItem {
-    MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) }
+pub fn mk_name_value_item(span: Span, ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
+    let lit = Lit::from_lit_kind(lit_kind, lit_span);
+    MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(lit) }
 }
 
 pub fn mk_list_item(span: Span, ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
@@ -417,39 +409,40 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute
 
 pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute {
     let style = doc_comment_style(&text.as_str());
-    let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked));
+    let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
+    let lit = Lit::from_lit_kind(lit_kind, span);
     Attribute {
         id,
         style,
-        path: Path::from_ident(Ident::from_str("doc").with_span_pos(span)),
+        path: Path::from_ident(Ident::with_empty_ctxt(sym::doc).with_span_pos(span)),
         tokens: MetaItemKind::NameValue(lit).tokens(span),
         is_sugared_doc: true,
         span,
     }
 }
 
-pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool {
+pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
     items.iter().any(|item| {
         item.check_name(name)
     })
 }
 
-pub fn contains_name(attrs: &[Attribute], name: &str) -> bool {
+pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
     attrs.iter().any(|item| {
         item.check_name(name)
     })
 }
 
-pub fn find_by_name<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> {
+pub fn find_by_name<'a>(attrs: &'a [Attribute], name: Symbol) -> Option<&'a Attribute> {
     attrs.iter().find(|attr| attr.check_name(name))
 }
 
-pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: &'a str)
+pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: Symbol)
     -> impl Iterator<Item = &'a Attribute> {
     attrs.iter().filter(move |attr| attr.check_name(name))
 }
 
-pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<Symbol> {
+pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
     attrs.iter()
         .find(|at| at.check_name(name))
         .and_then(|at| at.value_str())
@@ -561,8 +554,7 @@ impl MetaItemKind {
             Some(TokenTree::Token(_, token::Eq)) => {
                 tokens.next();
                 return if let Some(TokenTree::Token(span, token)) = tokens.next() {
-                    LitKind::from_token(token)
-                        .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span }))
+                    Lit::from_token(&token, span, None).map(MetaItemKind::NameValue)
                 } else {
                     None
                 };
@@ -607,9 +599,9 @@ impl NestedMetaItem {
         where I: Iterator<Item = TokenTree>,
     {
         if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() {
-            if let Some(node) = LitKind::from_token(token) {
+            if let Some(lit) = Lit::from_token(&token, span, None) {
                 tokens.next();
-                return Some(NestedMetaItem::Literal(respan(span, node)));
+                return Some(NestedMetaItem::Literal(lit));
             }
         }
 
@@ -617,81 +609,6 @@ impl NestedMetaItem {
     }
 }
 
-impl Lit {
-    crate fn tokens(&self) -> TokenStream {
-        TokenTree::Token(self.span, self.node.token()).into()
-    }
-}
-
-impl LitKind {
-    fn token(&self) -> Token {
-        use std::ascii;
-
-        match *self {
-            LitKind::Str(string, ast::StrStyle::Cooked) => {
-                let escaped = string.as_str().escape_default().to_string();
-                Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None)
-            }
-            LitKind::Str(string, ast::StrStyle::Raw(n)) => {
-                Token::Literal(token::Lit::StrRaw(string, n), None)
-            }
-            LitKind::ByteStr(ref bytes) => {
-                let string = bytes.iter().cloned().flat_map(ascii::escape_default)
-                    .map(Into::<char>::into).collect::<String>();
-                Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None)
-            }
-            LitKind::Byte(byte) => {
-                let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
-                Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None)
-            }
-            LitKind::Char(ch) => {
-                let string: String = ch.escape_default().map(Into::<char>::into).collect();
-                Token::Literal(token::Lit::Char(Symbol::intern(&string)), None)
-            }
-            LitKind::Int(n, ty) => {
-                let suffix = match ty {
-                    ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())),
-                    ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())),
-                    ast::LitIntType::Unsuffixed => None,
-                };
-                Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix)
-            }
-            LitKind::Float(symbol, ty) => {
-                Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string())))
-            }
-            LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None),
-            LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(if value {
-                "true"
-            } else {
-                "false"
-            })), false),
-            LitKind::Err(val) => Token::Literal(token::Lit::Err(val), None),
-        }
-    }
-
-    fn from_token(token: Token) -> Option<LitKind> {
-        match token {
-            Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)),
-            Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)),
-            Token::Interpolated(nt) => match *nt {
-                token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
-                    ExprKind::Lit(ref lit) => Some(lit.node.clone()),
-                    _ => None,
-                },
-                _ => None,
-            },
-            Token::Literal(lit, suf) => {
-                let (suffix_illegal, result) = parse::lit_token(lit, suf, None);
-                if suffix_illegal && suf.is_some() {
-                    return None;
-                }
-                result
-            }
-            _ => None,
-        }
-    }
-}
-
 pub trait HasAttrs: Sized {
     fn attrs(&self) -> &[ast::Attribute];
     fn visit_attrs<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 18173628a26..c82936afa3d 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -12,6 +12,7 @@ use crate::edition::Edition;
 use crate::mut_visit::*;
 use crate::parse::{token, ParseSess};
 use crate::ptr::P;
+use crate::symbol::sym;
 use crate::util::map_in_place::MapInPlace;
 
 use errors::Applicability;
@@ -90,7 +91,7 @@ impl<'a> StripUnconfigured<'a> {
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
     fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
-        if !attr.check_name("cfg_attr") {
+        if !attr.check_name(sym::cfg_attr) {
             return vec![attr];
         }
 
@@ -205,7 +206,7 @@ impl<'a> StripUnconfigured<'a> {
     pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) {
         if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
             let mut err = feature_err(self.sess,
-                                      "stmt_expr_attributes",
+                                      sym::stmt_expr_attributes,
                                       attr.span,
                                       GateIssue::Language,
                                       EXPLAIN_STMT_ATTR_SYNTAX);
@@ -285,9 +286,9 @@ impl<'a> StripUnconfigured<'a> {
     /// See issue #51279.
     pub fn disallow_cfg_on_generic_param(&mut self, param: &ast::GenericParam) {
         for attr in param.attrs() {
-            let offending_attr = if attr.check_name("cfg") {
+            let offending_attr = if attr.check_name(sym::cfg) {
                 "cfg"
-            } else if attr.check_name("cfg_attr") {
+            } else if attr.check_name(sym::cfg_attr) {
                 "cfg_attr"
             } else {
                 continue;
@@ -350,5 +351,5 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
 }
 
 fn is_cfg(attr: &ast::Attribute) -> bool {
-    attr.check_name("cfg")
+    attr.check_name(sym::cfg)
 }
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index 21024eb41ef..c988dc61bec 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -7,7 +7,7 @@ use crate::ext::base::{ExtCtxt, MacEager, MacResult};
 use crate::ext::build::AstBuilder;
 use crate::parse::token;
 use crate::ptr::P;
-use crate::symbol::{keywords, Symbol};
+use crate::symbol::keywords;
 use crate::tokenstream::{TokenTree};
 
 use smallvec::smallvec;
@@ -121,13 +121,13 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>,
 
     let span = span.apply_mark(ecx.current_expansion.mark);
 
-    let sym = Ident::new(Symbol::gensym(&format!("__register_diagnostic_{}", code)), span);
+    let name = Ident::from_str_and_span(&format!("__register_diagnostic_{}", code), span).gensym();
 
     MacEager::items(smallvec![
         ecx.item_mod(
             span,
             span,
-            sym,
+            name,
             vec![],
             vec![],
         )
diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs
index 09e26e29d86..0b6cf30bd27 100644
--- a/src/libsyntax/entry.rs
+++ b/src/libsyntax/entry.rs
@@ -1,5 +1,6 @@
 use crate::attr;
 use crate::ast::{Item, ItemKind};
+use crate::symbol::sym;
 
 pub enum EntryPointType {
     None,
@@ -14,11 +15,11 @@ pub enum EntryPointType {
 pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
     match item.node {
         ItemKind::Fn(..) => {
-            if attr::contains_name(&item.attrs, "start") {
+            if attr::contains_name(&item.attrs, sym::start) {
                 EntryPointType::Start
-            } else if attr::contains_name(&item.attrs, "main") {
+            } else if attr::contains_name(&item.attrs, sym::main) {
                 EntryPointType::MainAttr
-            } else if item.ident.name == "main" {
+            } else if item.ident.name == sym::main {
                 if depth == 1 {
                     // This is a top-level function so can be 'main'
                     EntryPointType::MainNamed
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index cc19acb61ad..0a88d2f8824 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -10,7 +10,7 @@ use crate::mut_visit::{self, MutVisitor};
 use crate::parse::{self, parser, DirectoryOwnership};
 use crate::parse::token;
 use crate::ptr::P;
-use crate::symbol::{keywords, Ident, Symbol};
+use crate::symbol::{keywords, Ident, Symbol, sym};
 use crate::ThinVec;
 use crate::tokenstream::{self, TokenStream};
 
@@ -871,7 +871,7 @@ impl<'a> ExtCtxt<'a> {
         let mut last_macro = None;
         loop {
             if ctxt.outer().expn_info().map_or(None, |info| {
-                if info.format.name() == "include" {
+                if info.format.name() == sym::include {
                     // Stop going up the backtrace once include! is encountered
                     return None;
                 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 40dd187ed28..d24106f697e 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -697,8 +697,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr_struct(span, self.path_ident(span, id), fields)
     }
 
-    fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P<ast::Expr> {
-        self.expr(sp, ast::ExprKind::Lit(respan(sp, lit)))
+    fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P<ast::Expr> {
+        let lit = ast::Lit::from_lit_kind(lit_kind, span);
+        self.expr(span, ast::ExprKind::Lit(lit))
     }
     fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr> {
         self.expr_lit(span, ast::LitKind::Int(i as u128,
@@ -1164,10 +1165,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         attr::mk_list_item(sp, Ident::with_empty_ctxt(name).with_span_pos(sp), mis)
     }
 
-    fn meta_name_value(&self, sp: Span, name: ast::Name, value: ast::LitKind)
+    fn meta_name_value(&self, span: Span, name: ast::Name, lit_kind: ast::LitKind)
                        -> ast::MetaItem {
-        attr::mk_name_value_item(sp, Ident::with_empty_ctxt(name).with_span_pos(sp),
-                                 respan(sp, value))
+        attr::mk_name_value_item(span, Ident::with_empty_ctxt(name).with_span_pos(span),
+                                 lit_kind, span)
     }
 
     fn item_use(&self, sp: Span,
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 6df369133d0..a24e09f127e 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -4,7 +4,7 @@ use crate::source_map::{hygiene, ExpnInfo, ExpnFormat};
 use crate::ext::base::ExtCtxt;
 use crate::ext::build::AstBuilder;
 use crate::parse::parser::PathStyle;
-use crate::symbol::Symbol;
+use crate::symbol::{Symbol, sym};
 
 use syntax_pos::Span;
 
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashSet;
 pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
     let mut result = Vec::new();
     attrs.retain(|attr| {
-        if attr.path != "derive" {
+        if attr.path != sym::derive {
             return true;
         }
         if !attr.is_meta_item_list() {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 82358679c0e..019ebc8566f 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -14,7 +14,7 @@ use crate::parse::token::{self, Token};
 use crate::parse::parser::Parser;
 use crate::ptr::P;
 use crate::symbol::Symbol;
-use crate::symbol::keywords;
+use crate::symbol::{keywords, sym};
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::visit::{self, Visitor};
 use crate::util::map_in_place::MapInPlace;
@@ -356,7 +356,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     self.collect_invocations(fragment, &[])
                 } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind {
                     if !item.derive_allowed() {
-                        let attr = attr::find_by_name(item.attrs(), "derive")
+                        let attr = attr::find_by_name(item.attrs(), sym::derive)
                             .expect("`derive` attribute should exist");
                         let span = attr.span;
                         let mut err = self.cx.mut_span_err(span,
@@ -376,7 +376,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
 
                     let mut item = self.fully_configure(item);
-                    item.visit_attrs(|attrs| attrs.retain(|a| a.path != "derive"));
+                    item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive));
                     let mut item_with_markers = item.clone();
                     add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers);
                     let derives = derives.entry(invoc.expansion_data.mark).or_default();
@@ -510,7 +510,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
            !self.cx.ecfg.macros_in_extern_enabled() {
             if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else {
-                emit_feature_err(&self.cx.parse_sess, "macros_in_extern",
+                emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
                                  invoc.span(), GateIssue::Language,
                                  "macro invocations in `extern {}` blocks are experimental");
             }
@@ -636,7 +636,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             Annotatable::Item(ref item) => {
                 match item.node {
                     ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return,
-                    ItemKind::Mod(_) => ("modules", "proc_macro_hygiene"),
+                    ItemKind::Mod(_) => ("modules", sym::proc_macro_hygiene),
                     _ => return,
                 }
             }
@@ -645,8 +645,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             Annotatable::ForeignItem(_) => return,
             Annotatable::Stmt(_) |
             Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return,
-            Annotatable::Stmt(_) => ("statements", "proc_macro_hygiene"),
-            Annotatable::Expr(_) => ("expressions", "proc_macro_hygiene"),
+            Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene),
+            Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene),
         };
         emit_feature_err(
             self.cx.parse_sess,
@@ -681,7 +681,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 if let ast::ItemKind::MacroDef(_) = i.node {
                     emit_feature_err(
                         self.parse_sess,
-                        "proc_macro_hygiene",
+                        sym::proc_macro_hygiene,
                         self.span,
                         GateIssue::Language,
                         "procedural macros cannot expand to macro definitions",
@@ -724,13 +724,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 // don't stability-check macros in the same crate
                 // (the only time this is null is for syntax extensions registered as macros)
                 if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
-                    && !span.allows_unstable(&feature.as_str())
+                    && !span.allows_unstable(feature)
                     && this.cx.ecfg.features.map_or(true, |feats| {
                     // macro features will count as lib features
                     !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
                 }) {
                     let explain = format!("macro {}! is unstable", path);
-                    emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span,
+                    emit_feature_err(this.cx.parse_sess, feature, span,
                                      GateIssue::Library(Some(issue)), &explain);
                     this.cx.trace_macros_diag();
                 }
@@ -885,7 +885,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
         emit_feature_err(
             self.cx.parse_sess,
-            "proc_macro_hygiene",
+            sym::proc_macro_hygiene,
             span,
             GateIssue::Language,
             &format!("procedural macros cannot be expanded to {}", kind),
@@ -1109,7 +1109,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                        -> Option<ast::Attribute> {
         let attr = attrs.iter()
                         .position(|a| {
-                            if a.path == "derive" {
+                            if a.path == sym::derive {
                                 *after_derive = true;
                             }
                             !attr::is_known(a) && !is_builtin_attr(a)
@@ -1117,8 +1117,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         .map(|i| attrs.remove(i));
         if let Some(attr) = &attr {
             if !self.cx.ecfg.enable_custom_inner_attributes() &&
-               attr.style == ast::AttrStyle::Inner && attr.path != "test" {
-                emit_feature_err(&self.cx.parse_sess, "custom_inner_attributes",
+               attr.style == ast::AttrStyle::Inner && attr.path != sym::test {
+                emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes,
                                  attr.span, GateIssue::Language,
                                  "non-builtin inner attributes are unstable");
             }
@@ -1167,7 +1167,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             self.check_attribute_inner(attr, features);
 
             // macros are expanded before any lint passes so this warning has to be hardcoded
-            if attr.path == "derive" {
+            if attr.path == sym::derive {
                 self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations")
                     .note("this may become a hard error in a future release")
                     .emit();
@@ -1352,7 +1352,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 let inline_module = item.span.contains(inner) || inner.is_dummy();
 
                 if inline_module {
-                    if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
+                    if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) {
                         self.cx.current_expansion.directory_ownership =
                             DirectoryOwnership::Owned { relative: None };
                         module.directory.push(&*path.as_str());
@@ -1485,19 +1485,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn visit_attribute(&mut self, at: &mut ast::Attribute) {
         // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
         // contents="file contents")]` attributes
-        if !at.check_name("doc") {
+        if !at.check_name(sym::doc) {
             return noop_visit_attribute(at, self);
         }
 
         if let Some(list) = at.meta_item_list() {
-            if !list.iter().any(|it| it.check_name("include")) {
+            if !list.iter().any(|it| it.check_name(sym::include)) {
                 return noop_visit_attribute(at, self);
             }
 
             let mut items = vec![];
 
             for mut it in list {
-                if !it.check_name("include") {
+                if !it.check_name(sym::include) {
                     items.push({ noop_visit_meta_list_item(&mut it, self); it });
                     continue;
                 }
@@ -1522,19 +1522,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                             let include_info = vec![
                                 ast::NestedMetaItem::MetaItem(
                                     attr::mk_name_value_item_str(
-                                        Ident::from_str("file"),
+                                        Ident::with_empty_ctxt(sym::file),
                                         dummy_spanned(file),
                                     ),
                                 ),
                                 ast::NestedMetaItem::MetaItem(
                                     attr::mk_name_value_item_str(
-                                        Ident::from_str("contents"),
+                                        Ident::with_empty_ctxt(sym::contents),
                                         dummy_spanned(src_interned),
                                     ),
                                 ),
                             ];
 
-                            let include_ident = Ident::from_str("include");
+                            let include_ident = Ident::with_empty_ctxt(sym::include);
                             let item = attr::mk_list_item(DUMMY_SP, include_ident, include_info);
                             items.push(ast::NestedMetaItem::MetaItem(item));
                         }
@@ -1600,7 +1600,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                 }
             }
 
-            let meta = attr::mk_list_item(DUMMY_SP, Ident::from_str("doc"), items);
+            let meta = attr::mk_list_item(DUMMY_SP, Ident::with_empty_ctxt(sym::doc), items);
             match at.style {
                 ast::AttrStyle::Inner => *at = attr::mk_spanned_attr_inner(at.span, at.id, meta),
                 ast::AttrStyle::Outer => *at = attr::mk_spanned_attr_outer(at.span, at.id, meta),
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 549de1628eb..e1cb90d9e71 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -4,7 +4,7 @@ use crate::ext::build::AstBuilder;
 use crate::parse::{self, token, DirectoryOwnership};
 use crate::print::pprust;
 use crate::ptr::P;
-use crate::symbol::Symbol;
+use crate::symbol::{Symbol, sym};
 use crate::tokenstream;
 
 use smallvec::SmallVec;
@@ -44,7 +44,7 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr
 /* __rust_unstable_column!(): expands to the current column number */
 pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
                   -> Box<dyn base::MacResult+'static> {
-    if sp.allows_unstable("__rust_unstable_column") {
+    if sp.allows_unstable(sym::__rust_unstable_column) {
         expand_column(cx, sp, tts)
     } else {
         cx.span_fatal(sp, "the __rust_unstable_column macro is unstable");
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index a53cc2fe661..672b7b42855 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -13,7 +13,7 @@ use crate::parse::{Directory, ParseSess};
 use crate::parse::parser::Parser;
 use crate::parse::token::{self, NtTT};
 use crate::parse::token::Token::*;
-use crate::symbol::Symbol;
+use crate::symbol::{Symbol, keywords, sym};
 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
 
 use errors::FatalError;
@@ -252,8 +252,8 @@ pub fn compile(
     def: &ast::Item,
     edition: Edition
 ) -> SyntaxExtension {
-    let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
-    let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
+    let lhs_nm = ast::Ident::from_str("lhs").gensym();
+    let rhs_nm = ast::Ident::from_str("rhs").gensym();
 
     // Parse the macro_rules! invocation
     let body = match def.node {
@@ -376,7 +376,7 @@ pub fn compile(
     });
 
     if body.legacy {
-        let allow_internal_unstable = attr::find_by_name(&def.attrs, "allow_internal_unstable")
+        let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
             .map(|attr| attr
                 .meta_item_list()
                 .map(|list| list.iter()
@@ -399,11 +399,11 @@ pub fn compile(
                     vec![Symbol::intern("allow_internal_unstable_backcompat_hack")].into()
                 })
             );
-        let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
+        let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
         let mut local_inner_macros = false;
-        if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") {
+        if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
             if let Some(l) = macro_export.meta_item_list() {
-                local_inner_macros = attr::list_contains_name(&l, "local_inner_macros");
+                local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
             }
         }
 
@@ -426,7 +426,7 @@ pub fn compile(
             edition,
         }
     } else {
-        let is_transparent = attr::contains_name(&def.attrs, "rustc_transparent_macro");
+        let is_transparent = attr::contains_name(&def.attrs, sym::rustc_transparent_macro);
 
         SyntaxExtension::DeclMacro {
             expander,
@@ -467,7 +467,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
             TokenTree::Sequence(span, ref seq) => {
                 if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| {
                     match *seq_tt {
-                        TokenTree::MetaVarDecl(_, _, id) => id.name == "vis",
+                        TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
                         TokenTree::Sequence(_, ref sub_seq) =>
                             sub_seq.op == quoted::KleeneOp::ZeroOrMore
                             || sub_seq.op == quoted::KleeneOp::ZeroOrOne,
@@ -1046,7 +1046,8 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
                 match *tok {
                     TokenTree::Token(_, ref tok) => match *tok {
                         FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes,
-                        Ident(i, false) if i.name == "if" || i.name == "in" => IsInFollow::Yes,
+                        Ident(i, false) if i.name == keywords::If.name() ||
+                                           i.name == keywords::In.name() => IsInFollow::Yes,
                         _ => IsInFollow::No(tokens),
                     },
                     _ => IsInFollow::No(tokens),
@@ -1063,10 +1064,12 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
                         OpenDelim(token::DelimToken::Bracket) |
                         Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi |
                         BinOp(token::Or) => IsInFollow::Yes,
-                        Ident(i, false) if i.name == "as" || i.name == "where" => IsInFollow::Yes,
+                        Ident(i, false) if i.name == keywords::As.name() ||
+                                           i.name == keywords::Where.name() => IsInFollow::Yes,
                         _ => IsInFollow::No(tokens),
                     },
-                    TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => IsInFollow::Yes,
+                    TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block =>
+                        IsInFollow::Yes,
                     _ => IsInFollow::No(tokens),
                 }
             },
@@ -1089,16 +1092,18 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> IsInFollow {
                 match *tok {
                     TokenTree::Token(_, ref tok) => match *tok {
                         Comma => IsInFollow::Yes,
-                        Ident(i, is_raw) if is_raw || i.name != "priv" => IsInFollow::Yes,
+                        Ident(i, is_raw) if is_raw || i.name != keywords::Priv.name() =>
+                            IsInFollow::Yes,
                         ref tok => if tok.can_begin_type() {
                             IsInFollow::Yes
                         } else {
                             IsInFollow::No(tokens)
                         }
                     },
-                    TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident"
-                                                       || frag.name == "ty"
-                                                       || frag.name == "path" => IsInFollow::Yes,
+                    TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::ident
+                                                       || frag.name == sym::ty
+                                                       || frag.name == sym::path =>
+                        IsInFollow::Yes,
                     _ => IsInFollow::No(tokens),
                 }
             },
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 0cefcf1ce03..e3586c1854c 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -170,10 +170,9 @@ pub fn transcribe(
                     }
 
                     LockstepIterSize::Contradiction(ref msg) => {
-                        // FIXME: this should be impossible. I (mark-i-m) believe it would
-                        // represent a bug in the macro_parser.
-                        // FIXME #2887 blame macro invoker instead
-                        cx.span_fatal(seq.span(), &msg[..]);
+                        // This should never happen because the macro parser should generate
+                        // properly-sized matches for all meta-vars.
+                        cx.span_bug(seq.span(), &msg[..]);
                     }
 
                     LockstepIterSize::Constraint(len, _) => {
@@ -188,14 +187,13 @@ pub fn transcribe(
                         // Is the repetition empty?
                         if len == 0 {
                             if seq.op == quoted::KleeneOp::OneOrMore {
-                                // FIXME: this should be impossible because we check for this in
-                                // macro_parser.rs
-                                // FIXME #2887 blame invoker
-                                cx.span_fatal(sp.entire(), "this must repeat at least once");
+                                // This should be impossible because the macro parser would not
+                                // match the given macro arm.
+                                cx.span_bug(sp.entire(), "this must repeat at least once");
                             }
                         } else {
                             // 0 is the initial counter (we have done 0 repretitions so far). `len`
-                            //   is the total number of reptitions we should generate.
+                            // is the total number of reptitions we should generate.
                             repeats.push((0, len));
 
                             // The first time we encounter the sequence we push it to the stack. It
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index c3bad3aba18..5b1a9bb739f 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -22,13 +22,13 @@ use crate::source_map::Spanned;
 use crate::edition::{ALL_EDITIONS, Edition};
 use crate::visit::{self, FnKind, Visitor};
 use crate::parse::{token, ParseSess};
-use crate::symbol::Symbol;
+use crate::symbol::{Symbol, keywords, sym};
 use crate::tokenstream::TokenTree;
 
 use errors::{DiagnosticBuilder, Handler};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_target::spec::abi::Abi;
-use syntax_pos::{Span, DUMMY_SP, symbols};
+use syntax_pos::{Span, DUMMY_SP};
 use log::debug;
 use lazy_static::lazy_static;
 
@@ -48,8 +48,8 @@ macro_rules! declare_features {
         /// Represents active features that are currently being implemented or
         /// currently being considered for addition/removal.
         const ACTIVE_FEATURES:
-            &[(&str, &str, Option<u32>, Option<Edition>, fn(&mut Features, Span))] =
-            &[$((stringify!($feature), $ver, $issue, $edition, set!($feature))),+];
+            &[(Symbol, &str, Option<u32>, Option<Edition>, fn(&mut Features, Span))] =
+            &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+];
 
         /// A set of features to be used by later passes.
         #[derive(Clone)]
@@ -80,22 +80,22 @@ macro_rules! declare_features {
 
     ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => {
         /// Represents unstable features which have since been removed (it was once Active)
-        const REMOVED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[
-            $((stringify!($feature), $ver, $issue, $reason)),+
+        const REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
+            $((sym::$feature, $ver, $issue, $reason)),+
         ];
     };
 
     ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => {
         /// Represents stable features which have since been removed (it was once Accepted)
-        const STABLE_REMOVED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[
-            $((stringify!($feature), $ver, $issue, None)),+
+        const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
+            $((sym::$feature, $ver, $issue, None)),+
         ];
     };
 
     ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => {
         /// Those language feature has since been Accepted (it was once Active)
-        const ACCEPTED_FEATURES: &[(&str, &str, Option<u32>, Option<&str>)] = &[
-            $((stringify!($feature), $ver, $issue, None)),+
+        const ACCEPTED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
+            $((sym::$feature, $ver, $issue, None)),+
         ];
     }
 }
@@ -562,9 +562,10 @@ declare_features! (
 // Some features are known to be incomplete and using them is likely to have
 // unanticipated results, such as compiler crashes. We warn the user about these
 // to alert them.
-const INCOMPLETE_FEATURES: &[&str] = &[
-    "generic_associated_types",
-    "const_generics"
+const INCOMPLETE_FEATURES: &[Symbol] = &[
+    sym::impl_trait_in_bindings,
+    sym::generic_associated_types,
+    sym::const_generics
 ];
 
 declare_features! (
@@ -860,7 +861,7 @@ pub enum AttributeType {
 pub enum AttributeGate {
     /// Is gated by a given feature gate, reason
     /// and function to check if enabled
-    Gated(Stability, &'static str, &'static str, fn(&Features) -> bool),
+    Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
 
     /// Ungated attribute, can be used on all release channels
     Ungated,
@@ -962,232 +963,232 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Normal attributes
 
     (
-        symbols::warn,
+        sym::warn,
         Normal,
         template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
         Ungated
     ),
     (
-        symbols::allow,
+        sym::allow,
         Normal,
         template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
         Ungated
     ),
     (
-        symbols::forbid,
+        sym::forbid,
         Normal,
         template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
         Ungated
     ),
     (
-        symbols::deny,
+        sym::deny,
         Normal,
         template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
         Ungated
     ),
 
-    (symbols::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated),
-    (symbols::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated),
-    (symbols::plugin_registrar, Normal, template!(Word), Ungated),
-
-    (symbols::cfg, Normal, template!(List: "predicate"), Ungated),
-    (symbols::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated),
-    (symbols::main, Normal, template!(Word), Ungated),
-    (symbols::start, Normal, template!(Word), Ungated),
-    (symbols::repr, Normal, template!(List: "C, packed, ..."), Ungated),
-    (symbols::path, Normal, template!(NameValueStr: "file"), Ungated),
-    (symbols::automatically_derived, Normal, template!(Word), Ungated),
-    (symbols::no_mangle, Normal, template!(Word), Ungated),
-    (symbols::no_link, Normal, template!(Word), Ungated),
-    (symbols::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated),
+    (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated),
+    (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated),
+    (sym::plugin_registrar, Normal, template!(Word), Ungated),
+
+    (sym::cfg, Normal, template!(List: "predicate"), Ungated),
+    (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated),
+    (sym::main, Normal, template!(Word), Ungated),
+    (sym::start, Normal, template!(Word), Ungated),
+    (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated),
+    (sym::path, Normal, template!(NameValueStr: "file"), Ungated),
+    (sym::automatically_derived, Normal, template!(Word), Ungated),
+    (sym::no_mangle, Whitelisted, template!(Word), Ungated),
+    (sym::no_link, Normal, template!(Word), Ungated),
+    (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated),
     (
-        symbols::should_panic,
+        sym::should_panic,
         Normal,
         template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
         Ungated
     ),
-    (symbols::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated),
-    (symbols::no_implicit_prelude, Normal, template!(Word), Ungated),
-    (symbols::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated),
-    (symbols::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable,
-                                "link_args",
+    (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated),
+    (sym::no_implicit_prelude, Normal, template!(Word), Ungated),
+    (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated),
+    (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable,
+                                sym::link_args,
                                 "the `link_args` attribute is experimental and not \
                                 portable across platforms, it is recommended to \
                                 use `#[link(name = \"foo\")] instead",
                                 cfg_fn!(link_args))),
-    (symbols::macro_escape, Normal, template!(Word), Ungated),
+    (sym::macro_escape, Normal, template!(Word), Ungated),
 
     // RFC #1445.
-    (symbols::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "structural_match",
+    (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::structural_match,
                                             "the semantics of constant patterns is \
                                             not yet settled",
                                             cfg_fn!(structural_match))),
 
     // RFC #2008
-    (symbols::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                        "non_exhaustive",
+    (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                        sym::non_exhaustive,
                                         "non exhaustive is an experimental feature",
                                         cfg_fn!(non_exhaustive))),
 
     // RFC #1268
-    (symbols::marker, Normal, template!(Word), Gated(Stability::Unstable,
-                            "marker_trait_attr",
+    (sym::marker, Normal, template!(Word), Gated(Stability::Unstable,
+                            sym::marker_trait_attr,
                             "marker traits is an experimental feature",
                             cfg_fn!(marker_trait_attr))),
 
-    (symbols::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable,
-                                "plugin",
+    (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable,
+                                sym::plugin,
                                 "compiler plugins are experimental \
                                 and possibly buggy",
                                 cfg_fn!(plugin))),
 
-    (symbols::no_std, CrateLevel, template!(Word), Ungated),
-    (symbols::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable,
-                                "no_core",
+    (sym::no_std, CrateLevel, template!(Word), Ungated),
+    (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable,
+                                sym::no_core,
                                 "no_core is experimental",
                                 cfg_fn!(no_core))),
-    (symbols::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable,
-                        "lang_items",
+    (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable,
+                        sym::lang_items,
                         "language items are subject to change",
                         cfg_fn!(lang_items))),
-    (symbols::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."),
+    (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."),
                                 Gated(Stability::Unstable,
-                                "linkage",
+                                sym::linkage,
                                 "the `linkage` attribute is experimental \
                                     and not portable across platforms",
                                 cfg_fn!(linkage))),
-    (symbols::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                        "thread_local",
+    (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                        sym::thread_local,
                                         "`#[thread_local]` is an experimental feature, and does \
                                          not currently handle destructors",
                                         cfg_fn!(thread_local))),
 
-    (symbols::rustc_on_unimplemented, Whitelisted, template!(List:
+    (sym::rustc_on_unimplemented, Whitelisted, template!(List:
                         r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
                         NameValueStr: "message"),
                                             Gated(Stability::Unstable,
-                                            "on_unimplemented",
+                                            sym::on_unimplemented,
                                             "the `#[rustc_on_unimplemented]` attribute \
                                             is an experimental feature",
                                             cfg_fn!(on_unimplemented))),
-    (symbols::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
+    (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
                                             Gated(Stability::Unstable,
-                                            "rustc_const_unstable",
+                                            sym::rustc_const_unstable,
                                             "the `#[rustc_const_unstable]` attribute \
                                             is an internal feature",
                                             cfg_fn!(rustc_const_unstable))),
-    (symbols::global_allocator, Normal, template!(Word), Ungated),
-    (symbols::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "allocator_internals",
+    (sym::global_allocator, Normal, template!(Word), Ungated),
+    (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::allocator_internals,
                                             "the `#[default_lib_allocator]` \
                                             attribute is an experimental feature",
                                             cfg_fn!(allocator_internals))),
-    (symbols::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable,
-                                    "allocator_internals",
+    (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable,
+                                    sym::allocator_internals,
                                     "the `#[needs_allocator]` \
                                     attribute is an experimental \
                                     feature",
                                     cfg_fn!(allocator_internals))),
-    (symbols::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                        "panic_runtime",
+    (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                        sym::panic_runtime,
                                         "the `#[panic_runtime]` attribute is \
                                         an experimental feature",
                                         cfg_fn!(panic_runtime))),
-    (symbols::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "needs_panic_runtime",
+    (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::needs_panic_runtime,
                                             "the `#[needs_panic_runtime]` \
                                                 attribute is an experimental \
                                                 feature",
                                             cfg_fn!(needs_panic_runtime))),
-    (symbols::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "the `#[rustc_outlives]` attribute \
                                     is just used for rustc unit tests \
                                     and will never be stable",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "the `#[rustc_variance]` attribute \
                                     is just used for rustc unit tests \
                                     and will never be stable",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_layout, Normal, template!(List: "field1, field2, ..."),
+    (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."),
     Gated(Stability::Unstable,
-        "rustc_attrs",
+        sym::rustc_attrs,
         "the `#[rustc_layout]` attribute \
             is just used for rustc unit tests \
             and will never be stable",
         cfg_fn!(rustc_attrs))),
-    (symbols::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"),
+    (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"),
     Gated(Stability::Unstable,
-        "rustc_attrs",
+        sym::rustc_attrs,
         "the `#[rustc_layout_scalar_valid_range_start]` attribute \
             is just used to enable niche optimizations in libcore \
             and will never be stable",
         cfg_fn!(rustc_attrs))),
-    (symbols::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"),
+    (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"),
     Gated(Stability::Unstable,
-        "rustc_attrs",
+        sym::rustc_attrs,
         "the `#[rustc_layout_scalar_valid_range_end]` attribute \
             is just used to enable niche optimizations in libcore \
             and will never be stable",
         cfg_fn!(rustc_attrs))),
-    (symbols::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "the `#[rustc_regions]` attribute \
                                     is just used for rustc unit tests \
                                     and will never be stable",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "the `#[rustc_error]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "this attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"),
+    (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"),
                                                 Gated(Stability::Unstable,
-                                                "rustc_attrs",
+                                                sym::rustc_attrs,
                                                 "the `#[rustc_if_this_changed]` attribute \
                                                 is just used for rustc unit tests \
                                                 and will never be stable",
                                                 cfg_fn!(rustc_attrs))),
-    (symbols::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"),
+    (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"),
                                                     Gated(Stability::Unstable,
-                                                    "rustc_attrs",
+                                                    sym::rustc_attrs,
                                                     "the `#[rustc_if_this_changed]` attribute \
                                                     is just used for rustc unit tests \
                                                     and will never be stable",
                                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
+    (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
                                                     /*opt*/ except = "...""#),
                                     Gated(Stability::Unstable,
-                                    "rustc_attrs",
+                                    sym::rustc_attrs,
                                     "the `#[rustc_dirty]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
+    (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
                                                     /*opt*/ except = "...""#),
                                     Gated(Stability::Unstable,
-                                    "rustc_attrs",
+                                    sym::rustc_attrs,
                                     "the `#[rustc_clean]` attribute \
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                     cfg_fn!(rustc_attrs))),
     (
-        symbols::rustc_partition_reused,
+        sym::rustc_partition_reused,
         Whitelisted,
         template!(List: r#"cfg = "...", module = "...""#),
         Gated(
             Stability::Unstable,
-            "rustc_attrs",
+            sym::rustc_attrs,
             "this attribute \
             is just used for rustc unit tests \
             and will never be stable",
@@ -1195,53 +1196,53 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         )
     ),
     (
-        symbols::rustc_partition_codegened,
+        sym::rustc_partition_codegened,
         Whitelisted,
         template!(List: r#"cfg = "...", module = "...""#),
         Gated(
             Stability::Unstable,
-            "rustc_attrs",
+            sym::rustc_attrs,
             "this attribute \
             is just used for rustc unit tests \
             and will never be stable",
             cfg_fn!(rustc_attrs),
         )
     ),
-    (symbols::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...",
+    (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...",
                                                             kind = "...""#),
                                                     Gated(Stability::Unstable,
-                                                    "rustc_attrs",
+                                                    sym::rustc_attrs,
                                                     "this attribute \
                                                     is just used for rustc unit tests \
                                                     and will never be stable",
                                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                                    "rustc_attrs",
+    (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                                    sym::rustc_attrs,
                                                     "this attribute \
                                                     is just used for rustc unit tests \
                                                     and will never be stable",
                                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "rustc_attrs",
+    (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::rustc_attrs,
                                             "internal rustc attributes will never be stable",
                                             cfg_fn!(rustc_attrs))),
-    (symbols::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                        "rustc_attrs",
+    (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                        sym::rustc_attrs,
                                         "internal rustc attributes will never be stable",
                                         cfg_fn!(rustc_attrs))),
-    (symbols::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "the `#[rustc_mir]` attribute \
                                     is just used for rustc unit tests \
                                     and will never be stable",
                                     cfg_fn!(rustc_attrs))),
     (
-        symbols::rustc_inherit_overflow_checks,
+        sym::rustc_inherit_overflow_checks,
         Whitelisted,
         template!(Word),
         Gated(
             Stability::Unstable,
-            "rustc_attrs",
+            sym::rustc_attrs,
             "the `#[rustc_inherit_overflow_checks]` \
             attribute is just used to control \
             overflow checking behavior of several \
@@ -1251,71 +1252,71 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         )
     ),
 
-    (symbols::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                                    "rustc_attrs",
+    (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                                    sym::rustc_attrs,
                                                     "the `#[rustc_dump_program_clauses]` \
                                                     attribute is just used for rustc unit \
                                                     tests and will never be stable",
                                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "the `#[rustc_test_marker]` attribute \
                                     is used internally to track tests",
                                     cfg_fn!(rustc_attrs))),
-    (symbols::rustc_transparent_macro, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                                "rustc_attrs",
+    (sym::rustc_transparent_macro, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                                sym::rustc_attrs,
                                                 "used internally for testing macro hygiene",
                                                     cfg_fn!(rustc_attrs))),
-    (symbols::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "compiler_builtins",
+    (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::compiler_builtins,
                                             "the `#[compiler_builtins]` attribute is used to \
                                             identify the `compiler_builtins` crate which \
                                             contains compiler-rt intrinsics and will never be \
                                             stable",
                                         cfg_fn!(compiler_builtins))),
-    (symbols::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "sanitizer_runtime",
+    (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::sanitizer_runtime,
                                             "the `#[sanitizer_runtime]` attribute is used to \
                                             identify crates that contain the runtime of a \
                                             sanitizer and will never be stable",
                                             cfg_fn!(sanitizer_runtime))),
-    (symbols::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                            "profiler_runtime",
+    (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                            sym::profiler_runtime,
                                             "the `#[profiler_runtime]` attribute is used to \
                                             identify the `profiler_builtins` crate which \
                                             contains the profiler runtime and will never be \
                                             stable",
                                             cfg_fn!(profiler_runtime))),
 
-    (symbols::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
+    (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
                                             Gated(Stability::Unstable,
-                                            "allow_internal_unstable",
+                                            sym::allow_internal_unstable,
                                             EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
                                             cfg_fn!(allow_internal_unstable))),
 
-    (symbols::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable,
-                                            "allow_internal_unsafe",
+    (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable,
+                                            sym::allow_internal_unsafe,
                                             EXPLAIN_ALLOW_INTERNAL_UNSAFE,
                                             cfg_fn!(allow_internal_unsafe))),
 
-    (symbols::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                    "fundamental",
+    (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                    sym::fundamental,
                                     "the `#[fundamental]` attribute \
                                         is an experimental feature",
                                     cfg_fn!(fundamental))),
 
-    (symbols::proc_macro_derive, Normal, template!(List: "TraitName, \
+    (sym::proc_macro_derive, Normal, template!(List: "TraitName, \
                                                 /*opt*/ attributes(name1, name2, ...)"),
                                     Ungated),
 
-    (symbols::rustc_copy_clone_marker, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                                "rustc_attrs",
+    (sym::rustc_copy_clone_marker, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                                sym::rustc_attrs,
                                                 "internal implementation detail",
                                                 cfg_fn!(rustc_attrs))),
 
     // FIXME: #14408 whitelist docs since rustdoc looks at them
     (
-        symbols::doc,
+        sym::doc,
         Whitelisted,
         template!(List: "hidden|inline|...", NameValueStr: "string"),
         Ungated
@@ -1323,94 +1324,94 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // FIXME: #14406 these are processed in codegen, which happens after the
     // lint pass
-    (symbols::cold, Whitelisted, template!(Word), Ungated),
-    (symbols::naked, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                "naked_functions",
+    (sym::cold, Whitelisted, template!(Word), Ungated),
+    (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                sym::naked_functions,
                                 "the `#[naked]` attribute \
                                 is an experimental feature",
                                 cfg_fn!(naked_functions))),
-    (symbols::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                "ffi_returns_twice",
+    (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                sym::ffi_returns_twice,
                                 "the `#[ffi_returns_twice]` attribute \
                                 is an experimental feature",
                                 cfg_fn!(ffi_returns_twice))),
-    (symbols::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated),
-    (symbols::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated),
-    (symbols::inline, Whitelisted, template!(Word, List: "always|never"), Ungated),
-    (symbols::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...",
+    (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated),
+    (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated),
+    (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated),
+    (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...",
                                                /*opt*/ cfg = "...""#), Ungated),
-    (symbols::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated),
-    (symbols::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated),
-    (symbols::no_builtins, Whitelisted, template!(Word), Ungated),
-    (symbols::no_debug, Whitelisted, template!(Word), Gated(
+    (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated),
+    (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated),
+    (sym::no_builtins, Whitelisted, template!(Word), Ungated),
+    (sym::no_debug, Whitelisted, template!(Word), Gated(
         Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None),
-        "no_debug",
+        sym::no_debug,
         "the `#[no_debug]` attribute was an experimental feature that has been \
         deprecated due to lack of demand",
         cfg_fn!(no_debug))),
     (
-        symbols::omit_gdb_pretty_printer_section,
+        sym::omit_gdb_pretty_printer_section,
         Whitelisted,
         template!(Word),
         Gated(
             Stability::Unstable,
-            "omit_gdb_pretty_printer_section",
+            sym::omit_gdb_pretty_printer_section,
             "the `#[omit_gdb_pretty_printer_section]` \
                 attribute is just used for the Rust test \
                 suite",
             cfg_fn!(omit_gdb_pretty_printer_section)
         )
     ),
-    (symbols::unsafe_destructor_blind_to_params,
+    (sym::unsafe_destructor_blind_to_params,
     Normal,
     template!(Word),
     Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761",
                                 Some("replace this attribute with `#[may_dangle]`")),
-        "dropck_parametricity",
+        sym::dropck_parametricity,
         "unsafe_destructor_blind_to_params has been replaced by \
             may_dangle and will be removed in the future",
         cfg_fn!(dropck_parametricity))),
-    (symbols::may_dangle,
+    (sym::may_dangle,
     Normal,
     template!(Word),
     Gated(Stability::Unstable,
-        "dropck_eyepatch",
+        sym::dropck_eyepatch,
         "may_dangle has unstable semantics and may be removed in the future",
         cfg_fn!(dropck_eyepatch))),
-    (symbols::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable,
-                                "unwind_attributes",
+    (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable,
+                                sym::unwind_attributes,
                                 "#[unwind] is experimental",
                                 cfg_fn!(unwind_attributes))),
-    (symbols::used, Whitelisted, template!(Word), Ungated),
+    (sym::used, Whitelisted, template!(Word), Ungated),
 
     // used in resolve
-    (symbols::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                        "prelude_import",
+    (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                        sym::prelude_import,
                                         "`#[prelude_import]` is for use by rustc only",
                                         cfg_fn!(prelude_import))),
 
     // FIXME: #14407 these are only looked at on-demand so we can't
     // guarantee they'll have already been checked
     (
-        symbols::rustc_deprecated,
+        sym::rustc_deprecated,
         Whitelisted,
         template!(List: r#"since = "version", reason = "...""#),
         Ungated
     ),
-    (symbols::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated),
+    (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated),
     (
-        symbols::stable,
+        sym::stable,
         Whitelisted,
         template!(List: r#"feature = "name", since = "version""#),
         Ungated
     ),
     (
-        symbols::unstable,
+        sym::unstable,
         Whitelisted,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#),
         Ungated
     ),
-    (symbols::deprecated,
+    (sym::deprecated,
         Normal,
         template!(
             Word,
@@ -1420,70 +1421,71 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         Ungated
     ),
 
-    (symbols::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable,
-                                        "unboxed_closures",
+    (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable,
+                                        sym::unboxed_closures,
                                         "unboxed_closures are still evolving",
                                         cfg_fn!(unboxed_closures))),
 
-    (symbols::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated),
+    (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated),
 
-    (symbols::proc_macro_attribute, Normal, template!(Word), Ungated),
-    (symbols::proc_macro, Normal, template!(Word), Ungated),
+    (sym::proc_macro_attribute, Normal, template!(Word), Ungated),
+    (sym::proc_macro, Normal, template!(Word), Ungated),
 
-    (symbols::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable,
-                                            "rustc_attrs",
+    (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable,
+                                            sym::rustc_attrs,
                                             "used internally by rustc",
                                             cfg_fn!(rustc_attrs))),
 
-    (symbols::allow_fail, Normal, template!(Word), Gated(Stability::Unstable,
-                                "allow_fail",
+    (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable,
+                                sym::allow_fail,
                                 "allow_fail attribute is currently unstable",
                                 cfg_fn!(allow_fail))),
 
-    (symbols::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                    "rustc_attrs",
+    (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                    sym::rustc_attrs,
                                     "this is an internal attribute that will \
                                     never be stable",
                                     cfg_fn!(rustc_attrs))),
 
     // whitelists "identity-like" conversion methods to suggest on type mismatch
-    (symbols::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable,
-                                                    "rustc_attrs",
+    (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable,
+                                                    sym::rustc_attrs,
                                                     "this is an internal attribute that will \
                                                         never be stable",
                                                     cfg_fn!(rustc_attrs))),
 
     (
-        symbols::rustc_args_required_const,
+        sym::rustc_args_required_const,
         Whitelisted,
         template!(List: "N"),
-        Gated(Stability::Unstable, "rustc_attrs", "never will be stable", cfg_fn!(rustc_attrs))
+        Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable",
+           cfg_fn!(rustc_attrs))
     ),
     // RFC 2070
-    (symbols::panic_handler, Normal, template!(Word), Ungated),
+    (sym::panic_handler, Normal, template!(Word), Ungated),
 
-    (symbols::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable,
-                        "alloc_error_handler",
+    (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable,
+                        sym::alloc_error_handler,
                         "#[alloc_error_handler] is an unstable feature",
                         cfg_fn!(alloc_error_handler))),
 
     // RFC 2412
-    (symbols::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable,
-                            "optimize_attribute",
+    (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable,
+                            sym::optimize_attribute,
                             "#[optimize] attribute is an unstable feature",
                             cfg_fn!(optimize_attribute))),
 
     // Crate level attributes
-    (symbols::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated),
-    (symbols::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated),
-    (symbols::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated),
-    (symbols::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated),
-    (symbols::no_start, CrateLevel, template!(Word), Ungated),
-    (symbols::no_main, CrateLevel, template!(Word), Ungated),
-    (symbols::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
-    (symbols::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
-    (symbols::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable,
-                    "custom_test_frameworks",
+    (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated),
+    (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated),
+    (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated),
+    (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated),
+    (sym::no_start, CrateLevel, template!(Word), Ungated),
+    (sym::no_main, CrateLevel, template!(Word), Ungated),
+    (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
+    (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
+    (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable,
+                    sym::custom_test_frameworks,
                     EXPLAIN_CUSTOM_TEST_FRAMEWORKS,
                     cfg_fn!(custom_test_frameworks))),
 ];
@@ -1503,11 +1505,11 @@ lazy_static! {
 }
 
 // cfg(...)'s that are feature gated
-const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
+const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
-    ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
-    ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
-    ("rustdoc", "doc_cfg", cfg_fn!(doc_cfg)),
+    (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
+    (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
+    (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)),
 ];
 
 #[derive(Debug)]
@@ -1540,7 +1542,7 @@ impl GatedCfg {
 struct Context<'a> {
     features: &'a Features,
     parse_sess: &'a ParseSess,
-    plugin_attributes: &'a [(String, AttributeType)],
+    plugin_attributes: &'a [(Symbol, AttributeType)],
 }
 
 macro_rules! gate_feature_fn {
@@ -1559,11 +1561,11 @@ macro_rules! gate_feature_fn {
 macro_rules! gate_feature {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
         gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
-                         stringify!($feature), $explain, GateStrength::Hard)
+                         sym::$feature, $explain, GateStrength::Hard)
     };
     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {
         gate_feature_fn!($cx, |x:&Features| x.$feature, $span,
-                         stringify!($feature), $explain, $level)
+                         sym::$feature, $explain, $level)
     };
 }
 
@@ -1582,9 +1584,9 @@ impl<'a> Context<'a> {
                         self, has_feature, attr.span, name, desc, GateStrength::Hard
                     );
                 }
-            } else if name == symbols::doc {
+            } else if name == sym::doc {
                 if let Some(content) = attr.meta_item_list() {
-                    if content.iter().any(|c| c.check_name(symbols::include)) {
+                    if content.iter().any(|c| c.check_name(sym::include)) {
                         gate_feature!(self, external_doc, attr.span,
                             "#[doc(include = \"...\")] is experimental"
                         );
@@ -1594,8 +1596,8 @@ impl<'a> Context<'a> {
             debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
             return;
         }
-        for &(ref n, ref ty) in self.plugin_attributes {
-            if attr.path == &**n {
+        for &(n, ty) in self.plugin_attributes {
+            if attr.path == n {
                 // Plugins can't gate attributes, so we don't check for it
                 // unlike the code above; we only use this loop to
                 // short-circuit to avoid the checks below.
@@ -1604,7 +1606,7 @@ impl<'a> Context<'a> {
             }
         }
         if !attr::is_known(attr) {
-            if attr.name_or_empty().starts_with("rustc_") {
+            if attr.name_or_empty().as_str().starts_with("rustc_") {
                 let msg = "unless otherwise specified, attributes with the prefix `rustc_` \
                            are reserved for internal compiler diagnostics";
                 gate_feature!(self, rustc_attrs, attr.span, msg);
@@ -1629,7 +1631,7 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
     );
 }
 
-fn find_lang_feature_issue(feature: &str) -> Option<u32> {
+fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
     if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
         let issue = info.2;
         // FIXME (#28244): enforce that active features have issue numbers
@@ -1661,7 +1663,7 @@ pub enum GateStrength {
 
 pub fn emit_feature_err(
     sess: &ParseSess,
-    feature: &str,
+    feature: Symbol,
     span: Span,
     issue: GateIssue,
     explain: &str,
@@ -1671,7 +1673,7 @@ pub fn emit_feature_err(
 
 pub fn feature_err<'a>(
     sess: &'a ParseSess,
-    feature: &str,
+    feature: Symbol,
     span: Span,
     issue: GateIssue,
     explain: &str,
@@ -1681,7 +1683,7 @@ pub fn feature_err<'a>(
 
 fn leveled_feature_err<'a>(
     sess: &'a ParseSess,
-    feature: &str,
+    feature: Symbol,
     span: Span,
     issue: GateIssue,
     explain: &str,
@@ -1769,13 +1771,13 @@ struct PostExpansionVisitor<'a> {
 macro_rules! gate_feature_post {
     ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
         let (cx, span) = ($cx, $span);
-        if !span.allows_unstable(stringify!($feature)) {
+        if !span.allows_unstable(sym::$feature) {
             gate_feature!(cx.context, $feature, span, $explain)
         }
     }};
     ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
         let (cx, span) = ($cx, $span);
-        if !span.allows_unstable(stringify!($feature)) {
+        if !span.allows_unstable(sym::$feature) {
             gate_feature!(cx.context, $feature, span, $explain, $level)
         }
     }}
@@ -1841,11 +1843,11 @@ impl<'a> PostExpansionVisitor<'a> {
                                template: AttributeTemplate) {
         // Some special attributes like `cfg` must be checked
         // before the generic check, so we skip them here.
-        let should_skip = |name| name == symbols::cfg;
+        let should_skip = |name| name == sym::cfg;
         // Some of previously accepted forms were used in practice,
         // report them as warnings for now.
-        let should_warn = |name| name == symbols::doc || name == symbols::ignore ||
-                                 name == symbols::inline || name == symbols::link;
+        let should_warn = |name| name == sym::doc || name == sym::ignore ||
+                                 name == sym::inline || name == sym::link;
 
         match attr.parse_meta(self.context.parse_sess) {
             Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
@@ -1893,25 +1895,25 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         // check for gated attributes
         self.context.check_attribute(attr, attr_info, false);
 
-        if attr.check_name(symbols::doc) {
+        if attr.check_name(sym::doc) {
             if let Some(content) = attr.meta_item_list() {
-                if content.len() == 1 && content[0].check_name(symbols::cfg) {
+                if content.len() == 1 && content[0].check_name(sym::cfg) {
                     gate_feature_post!(&self, doc_cfg, attr.span,
                         "#[doc(cfg(...))] is experimental"
                     );
-                } else if content.iter().any(|c| c.check_name(symbols::masked)) {
+                } else if content.iter().any(|c| c.check_name(sym::masked)) {
                     gate_feature_post!(&self, doc_masked, attr.span,
                         "#[doc(masked)] is experimental"
                     );
-                } else if content.iter().any(|c| c.check_name(symbols::spotlight)) {
+                } else if content.iter().any(|c| c.check_name(sym::spotlight)) {
                     gate_feature_post!(&self, doc_spotlight, attr.span,
                         "#[doc(spotlight)] is experimental"
                     );
-                } else if content.iter().any(|c| c.check_name(symbols::alias)) {
+                } else if content.iter().any(|c| c.check_name(sym::alias)) {
                     gate_feature_post!(&self, doc_alias, attr.span,
                         "#[doc(alias = \"...\")] is experimental"
                     );
-                } else if content.iter().any(|c| c.check_name(symbols::keyword)) {
+                } else if content.iter().any(|c| c.check_name(sym::keyword)) {
                     gate_feature_post!(&self, doc_keyword, attr.span,
                         "#[doc(keyword = \"...\")] is experimental"
                     );
@@ -1946,7 +1948,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_item(&mut self, i: &'a ast::Item) {
         match i.node {
             ast::ItemKind::Const(_,_) => {
-                if i.ident.name == "_" {
+                if i.ident.name == keywords::Underscore.name() {
                     gate_feature_post!(&self, underscore_const_names, i.span,
                                         "naming constants with `_` is unstable");
                 }
@@ -1957,17 +1959,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Fn(..) => {
-                if attr::contains_name(&i.attrs[..], "plugin_registrar") {
+                if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
                     gate_feature_post!(&self, plugin_registrar, i.span,
                                        "compiler plugins are experimental and possibly buggy");
                 }
-                if attr::contains_name(&i.attrs[..], "start") {
+                if attr::contains_name(&i.attrs[..], sym::start) {
                     gate_feature_post!(&self, start, i.span,
                                       "a #[start] function is an experimental \
                                        feature whose signature may change \
                                        over time");
                 }
-                if attr::contains_name(&i.attrs[..], "main") {
+                if attr::contains_name(&i.attrs[..], sym::main) {
                     gate_feature_post!(&self, main, i.span,
                                        "declaration of a nonstandard #[main] \
                                         function may change over time, for now \
@@ -1976,9 +1978,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Struct(..) => {
-                for attr in attr::filter_by_name(&i.attrs[..], "repr") {
+                for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-                        if item.check_name(symbols::simd) {
+                        if item.check_name(sym::simd) {
                             gate_feature_post!(&self, repr_simd, attr.span,
                                                "SIMD types are experimental and possibly buggy");
                         }
@@ -1987,9 +1989,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Enum(..) => {
-                for attr in attr::filter_by_name(&i.attrs[..], "repr") {
+                for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-                        if item.check_name(symbols::align) {
+                        if item.check_name(sym::align) {
                             gate_feature_post!(&self, repr_align_enum, attr.span,
                                                "`#[repr(align(x))]` on enums is experimental");
                         }
@@ -2051,7 +2053,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         match i.node {
             ast::ForeignItemKind::Fn(..) |
             ast::ForeignItemKind::Static(..) => {
-                let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name");
+                let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
                 let links_to_llvm = match link_name {
                     Some(val) => val.as_str().starts_with("llvm."),
                     _ => false
@@ -2303,7 +2305,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         if edition <= crate_edition {
             // The `crate_edition` implies its respective umbrella feature-gate
             // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
-            edition_enabled_features.insert(Symbol::intern(edition.feature_name()), edition);
+            edition_enabled_features.insert(edition.feature_name(), edition);
         }
     }
 
@@ -2311,7 +2313,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
         if let Some(f_edition) = f_edition {
             if f_edition <= crate_edition {
                 set(&mut features, DUMMY_SP);
-                edition_enabled_features.insert(Symbol::intern(name), crate_edition);
+                edition_enabled_features.insert(name, crate_edition);
             }
         }
     }
@@ -2319,7 +2321,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
     // Process the edition umbrella feature-gates first, to ensure
     // `edition_enabled_features` is completed before it's queried.
     for attr in krate_attrs {
-        if !attr.check_name(symbols::feature) {
+        if !attr.check_name(sym::feature) {
             continue
         }
 
@@ -2355,7 +2357,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
                             // FIXME(Manishearth) there is currently no way to set
                             // lib features by edition
                             set(&mut features, DUMMY_SP);
-                            edition_enabled_features.insert(Symbol::intern(name), *edition);
+                            edition_enabled_features.insert(name, *edition);
                         }
                     }
                 }
@@ -2364,7 +2366,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
     }
 
     for attr in krate_attrs {
-        if !attr.check_name(symbols::feature) {
+        if !attr.check_name(sym::feature) {
             continue
         }
 
@@ -2438,7 +2440,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
 pub fn check_crate(krate: &ast::Crate,
                    sess: &ParseSess,
                    features: &Features,
-                   plugin_attributes: &[(String, AttributeType)],
+                   plugin_attributes: &[(Symbol, AttributeType)],
                    unstable: UnstableFeatures) {
     maybe_stage_features(&sess.span_diagnostic, krate, unstable);
     let ctx = Context {
@@ -2496,7 +2498,7 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
     };
     if !allow_features {
         for attr in &krate.attrs {
-            if attr.check_name(symbols::feature) {
+            if attr.check_name(sym::feature) {
                 let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
                 span_err!(span_handler, attr.span, E0554,
                           "#![feature] may not be used on the {} release channel",
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 6eb8b1b5004..f587e63e12b 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -663,7 +663,6 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
         token::NtMeta(meta) => vis.visit_meta_item(meta),
         token::NtPath(path) => vis.visit_path(path),
         token::NtTT(tt) => vis.visit_tt(tt),
-        token::NtArm(arm) => vis.visit_arm(arm),
         token::NtImplItem(item) =>
             visit_clobber(item, |item| {
                 // See reasoning above.
@@ -676,9 +675,6 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
                 vis.flat_map_trait_item(item)
                     .expect_one("expected visitor to produce exactly one item")
             }),
-        token::NtGenerics(generics) => vis.visit_generics(generics),
-        token::NtWhereClause(where_clause) => vis.visit_where_clause(where_clause),
-        token::NtArg(arg) => vis.visit_arg(arg),
         token::NtVis(visib) => vis.visit_vis(visib),
         token::NtForeignItem(item) =>
             visit_clobber(item, |item| {
diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs
index b4103440e35..dfd6f451c28 100644
--- a/src/libsyntax/parse/classify.rs
+++ b/src/libsyntax/parse/classify.rs
@@ -25,16 +25,3 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
         _ => true,
     }
 }
-
-/// this statement requires a semicolon after it.
-/// note that in one case (`stmt_semi`), we've already
-/// seen the semicolon, and thus don't need another.
-pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool {
-    match *stmt {
-        ast::StmtKind::Local(_) => true,
-        ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e),
-        ast::StmtKind::Item(_) |
-        ast::StmtKind::Semi(..) |
-        ast::StmtKind::Mac(..) => false,
-    }
-}
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index 32e1ee94f0d..1a2393be806 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -1,14 +1,16 @@
 use crate::ast;
-use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
-use crate::parse::parser::PathStyle;
+use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
+use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode};
 use crate::parse::token;
 use crate::parse::PResult;
 use crate::parse::Parser;
 use crate::print::pprust;
 use crate::ptr::P;
+use crate::symbol::keywords;
 use crate::ThinVec;
-use errors::Applicability;
+use errors::{Applicability, DiagnosticBuilder};
 use syntax_pos::Span;
+use log::debug;
 
 pub trait RecoverQPath: Sized + 'static {
     const PATH_STYLE: PathStyle = PathStyle::Expr;
@@ -223,4 +225,300 @@ impl<'a> Parser<'a> {
             false
         }
     }
+
+    /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
+    /// and `await { <expr> }`.
+    crate fn parse_incorrect_await_syntax(
+        &mut self,
+        lo: Span,
+        await_sp: Span,
+    ) -> PResult<'a, (Span, ExprKind)> {
+        let is_question = self.eat(&token::Question); // Handle `await? <expr>`.
+        let expr = if self.token == token::OpenDelim(token::Brace) {
+            // Handle `await { <expr> }`.
+            // This needs to be handled separatedly from the next arm to avoid
+            // interpreting `await { <expr> }?` as `<expr>?.await`.
+            self.parse_block_expr(
+                None,
+                self.span,
+                BlockCheckMode::Default,
+                ThinVec::new(),
+            )
+        } else {
+            self.parse_expr()
+        }.map_err(|mut err| {
+            err.span_label(await_sp, "while parsing this incorrect await expression");
+            err
+        })?;
+        let expr_str = self.sess.source_map().span_to_snippet(expr.span)
+            .unwrap_or_else(|_| pprust::expr_to_string(&expr));
+        let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
+        let sp = lo.to(expr.span);
+        let app = match expr.node {
+            ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
+            _ => Applicability::MachineApplicable,
+        };
+        self.struct_span_err(sp, "incorrect use of `await`")
+            .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
+            .emit();
+        Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr)))
+    }
+
+    /// If encountering `future.await()`, consume and emit error.
+    crate fn recover_from_await_method_call(&mut self) {
+        if self.token == token::OpenDelim(token::Paren) &&
+            self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
+        {
+            // future.await()
+            let lo = self.span;
+            self.bump(); // (
+            let sp = lo.to(self.span);
+            self.bump(); // )
+            self.struct_span_err(sp, "incorrect use of `await`")
+                .span_suggestion(
+                    sp,
+                    "`await` is not a method call, remove the parentheses",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                ).emit()
+        }
+    }
+
+    crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
+        self.token.is_ident() &&
+            if let ast::ExprKind::Path(..) = node { true } else { false } &&
+            !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
+            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
+            self.look_ahead(1, |t| t == &token::Lt) &&     // `foo:bar<baz`
+            self.look_ahead(2, |t| t.is_ident()) ||
+            self.look_ahead(1, |t| t == &token::Colon) &&  // `foo:bar:baz`
+            self.look_ahead(2, |t| t.is_ident()) ||
+            self.look_ahead(1, |t| t == &token::ModSep) &&  // `foo:bar::baz`
+            self.look_ahead(2, |t| t.is_ident())
+    }
+
+    crate fn bad_type_ascription(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        lhs_span: Span,
+        cur_op_span: Span,
+        next_sp: Span,
+        maybe_path: bool,
+    ) {
+        err.span_label(self.span, "expecting a type here because of type ascription");
+        let cm = self.sess.source_map();
+        let next_pos = cm.lookup_char_pos(next_sp.lo());
+        let op_pos = cm.lookup_char_pos(cur_op_span.hi());
+        if op_pos.line != next_pos.line {
+            err.span_suggestion(
+                cur_op_span,
+                "try using a semicolon",
+                ";".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            if maybe_path {
+                err.span_suggestion(
+                    cur_op_span,
+                    "maybe you meant to write a path separator here",
+                    "::".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                err.note("type ascription is a nightly-only feature that lets \
+                          you annotate an expression with a type: `<expr>: <type>`")
+                    .span_note(
+                        lhs_span,
+                        "this expression expects an ascribed type after the colon",
+                    )
+                    .help("this might be indicative of a syntax error elsewhere");
+            }
+        }
+    }
+
+    crate fn recover_seq_parse_error(
+        &mut self,
+        delim: token::DelimToken,
+        lo: Span,
+        result: PResult<'a, P<Expr>>,
+    ) -> P<Expr> {
+        match result {
+            Ok(x) => x,
+            Err(mut err) => {
+                err.emit();
+                // recover from parse error
+                self.consume_block(delim);
+                self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
+            }
+        }
+    }
+
+    crate fn recover_closing_delimiter(
+        &mut self,
+        tokens: &[token::Token],
+        mut err: DiagnosticBuilder<'a>,
+    ) -> PResult<'a, bool> {
+        let mut pos = None;
+        // we want to use the last closing delim that would apply
+        for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
+            if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
+                && Some(self.span) > unmatched.unclosed_span
+            {
+                pos = Some(i);
+            }
+        }
+        match pos {
+            Some(pos) => {
+                // Recover and assume that the detected unclosed delimiter was meant for
+                // this location. Emit the diagnostic and act as if the delimiter was
+                // present for the parser's sake.
+
+                 // Don't attempt to recover from this unclosed delimiter more than once.
+                let unmatched = self.unclosed_delims.remove(pos);
+                let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
+
+                 // We want to suggest the inclusion of the closing delimiter where it makes
+                // the most sense, which is immediately after the last token:
+                //
+                //  {foo(bar {}}
+                //      -      ^
+                //      |      |
+                //      |      help: `)` may belong here (FIXME: #58270)
+                //      |
+                //      unclosed delimiter
+                if let Some(sp) = unmatched.unclosed_span {
+                    err.span_label(sp, "unclosed delimiter");
+                }
+                err.span_suggestion_short(
+                    self.sess.source_map().next_point(self.prev_span),
+                    &format!("{} may belong here", delim.to_string()),
+                    delim.to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+                err.emit();
+                self.expected_tokens.clear();  // reduce errors
+                Ok(true)
+            }
+            _ => Err(err),
+        }
+    }
+
+    /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
+    crate fn eat_bad_pub(&mut self) {
+        if self.token.is_keyword(keywords::Pub) {
+            match self.parse_visibility(false) {
+                Ok(vis) => {
+                    self.diagnostic()
+                        .struct_span_err(vis.span, "unnecessary visibility qualifier")
+                        .span_label(vis.span, "`pub` not permitted here")
+                        .emit();
+                }
+                Err(mut err) => err.emit(),
+            }
+        }
+    }
+
+    // Eat tokens until we can be relatively sure we reached the end of the
+    // statement. This is something of a best-effort heuristic.
+    //
+    // We terminate when we find an unmatched `}` (without consuming it).
+    crate fn recover_stmt(&mut self) {
+        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
+    }
+
+    // If `break_on_semi` is `Break`, then we will stop consuming tokens after
+    // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
+    // approximate - it can mean we break too early due to macros, but that
+    // should only lead to sub-optimal recovery, not inaccurate parsing).
+    //
+    // If `break_on_block` is `Break`, then we will stop consuming tokens
+    // after finding (and consuming) a brace-delimited block.
+    crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
+        let mut brace_depth = 0;
+        let mut bracket_depth = 0;
+        let mut in_block = false;
+        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
+               break_on_semi, break_on_block);
+        loop {
+            debug!("recover_stmt_ loop {:?}", self.token);
+            match self.token {
+                token::OpenDelim(token::DelimToken::Brace) => {
+                    brace_depth += 1;
+                    self.bump();
+                    if break_on_block == BlockMode::Break &&
+                       brace_depth == 1 &&
+                       bracket_depth == 0 {
+                        in_block = true;
+                    }
+                }
+                token::OpenDelim(token::DelimToken::Bracket) => {
+                    bracket_depth += 1;
+                    self.bump();
+                }
+                token::CloseDelim(token::DelimToken::Brace) => {
+                    if brace_depth == 0 {
+                        debug!("recover_stmt_ return - close delim {:?}", self.token);
+                        break;
+                    }
+                    brace_depth -= 1;
+                    self.bump();
+                    if in_block && bracket_depth == 0 && brace_depth == 0 {
+                        debug!("recover_stmt_ return - block end {:?}", self.token);
+                        break;
+                    }
+                }
+                token::CloseDelim(token::DelimToken::Bracket) => {
+                    bracket_depth -= 1;
+                    if bracket_depth < 0 {
+                        bracket_depth = 0;
+                    }
+                    self.bump();
+                }
+                token::Eof => {
+                    debug!("recover_stmt_ return - Eof");
+                    break;
+                }
+                token::Semi => {
+                    self.bump();
+                    if break_on_semi == SemiColonMode::Break &&
+                       brace_depth == 0 &&
+                       bracket_depth == 0 {
+                        debug!("recover_stmt_ return - Semi");
+                        break;
+                    }
+                }
+                token::Comma if break_on_semi == SemiColonMode::Comma &&
+                       brace_depth == 0 &&
+                       bracket_depth == 0 =>
+                {
+                    debug!("recover_stmt_ return - Semi");
+                    break;
+                }
+                _ => {
+                    self.bump()
+                }
+            }
+        }
+    }
+
+    crate fn consume_block(&mut self, delim: token::DelimToken) {
+        let mut brace_depth = 0;
+        loop {
+            if self.eat(&token::OpenDelim(delim)) {
+                brace_depth += 1;
+            } else if self.eat(&token::CloseDelim(delim)) {
+                if brace_depth == 0 {
+                    return;
+                } else {
+                    brace_depth -= 1;
+                    continue;
+                }
+            } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
+                return;
+            } else {
+                self.bump();
+            }
+        }
+    }
+
 }
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 74fff3324ea..97d3fc002e9 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -3,8 +3,7 @@ pub use CommentStyle::*;
 use crate::ast;
 use crate::source_map::SourceMap;
 use crate::parse::lexer::{is_block_doc_comment, is_pattern_whitespace};
-use crate::parse::lexer::{self, ParseSess, StringReader, TokenAndSpan};
-use crate::print::pprust;
+use crate::parse::lexer::{self, ParseSess, StringReader};
 
 use syntax_pos::{BytePos, CharPos, Pos, FileName};
 use log::debug;
@@ -339,16 +338,9 @@ fn consume_comment(rdr: &mut StringReader<'_>,
     debug!("<<< consume comment");
 }
 
-#[derive(Clone)]
-pub struct Literal {
-    pub lit: String,
-    pub pos: BytePos,
-}
-
 // it appears this function is called only from pprust... that's
 // probably not a good thing.
-pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut dyn Read)
-    -> (Vec<Comment>, Vec<Literal>)
+pub fn gather_comments(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) -> Vec<Comment>
 {
     let mut src = String::new();
     srdr.read_to_string(&mut src).unwrap();
@@ -357,7 +349,6 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut
     let mut rdr = lexer::StringReader::new_raw(sess, source_file, None);
 
     let mut comments: Vec<Comment> = Vec::new();
-    let mut literals: Vec<Literal> = Vec::new();
     let mut code_to_the_left = false; // Only code
     let mut anything_to_the_left = false; // Code or comments
 
@@ -382,26 +373,12 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut
             }
         }
 
-        let bstart = rdr.pos;
         rdr.next_token();
-        // discard, and look ahead; we're working with internal state
-        let TokenAndSpan { tok, sp } = rdr.peek();
-        if tok.is_lit() {
-            rdr.with_str_from(bstart, |s| {
-                debug!("tok lit: {}", s);
-                literals.push(Literal {
-                    lit: s.to_string(),
-                    pos: sp.lo(),
-                });
-            })
-        } else {
-            debug!("tok: {}", pprust::token_to_string(&tok));
-        }
         code_to_the_left = true;
         anything_to_the_left = true;
     }
 
-    (comments, literals)
+    comments
 }
 
 #[cfg(test)]
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 2882acb0e78..47da3ee6a6c 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -62,19 +62,7 @@ pub struct StringReader<'a> {
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time.
     src: Lrc<String>,
-    token: token::Token,
-    span: Span,
-    /// The raw source span which *does not* take `override_span` into account
-    span_src_raw: Span,
-    /// Stack of open delimiters and their spans. Used for error message.
-    open_braces: Vec<(token::DelimToken, Span)>,
-    crate unmatched_braces: Vec<UnmatchedBrace>,
-    /// The type and spans for all braces
-    ///
-    /// Used only for error recovery when arriving to EOF with mismatched braces.
-    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
-    crate override_span: Option<Span>,
-    last_unclosed_found_span: Option<Span>,
+    override_span: Option<Span>,
 }
 
 impl<'a> StringReader<'a> {
@@ -121,8 +109,6 @@ impl<'a> StringReader<'a> {
             sp: self.peek_span,
         };
         self.advance_token()?;
-        self.span_src_raw = self.peek_span_src_raw;
-
         Ok(ret_val)
     }
 
@@ -159,9 +145,6 @@ impl<'a> StringReader<'a> {
             }
         }
 
-        self.token = t.tok.clone();
-        self.span = t.sp;
-
         Ok(t)
     }
 
@@ -251,29 +234,10 @@ impl<'a> StringReader<'a> {
             peek_span_src_raw: syntax_pos::DUMMY_SP,
             src,
             fatal_errs: Vec::new(),
-            token: token::Eof,
-            span: syntax_pos::DUMMY_SP,
-            span_src_raw: syntax_pos::DUMMY_SP,
-            open_braces: Vec::new(),
-            unmatched_braces: Vec::new(),
-            matching_delim_spans: Vec::new(),
             override_span,
-            last_unclosed_found_span: None,
         }
     }
 
-    pub fn new(sess: &'a ParseSess,
-               source_file: Lrc<syntax_pos::SourceFile>,
-               override_span: Option<Span>) -> Self {
-        let mut sr = StringReader::new_raw(sess, source_file, override_span);
-        if sr.advance_token().is_err() {
-            sr.emit_fatal_errors();
-            FatalError.raise();
-        }
-
-        sr
-    }
-
     pub fn new_or_buffered_errs(sess: &'a ParseSess,
                                 source_file: Lrc<syntax_pos::SourceFile>,
                                 override_span: Option<Span>) -> Result<Self, Vec<Diagnostic>> {
@@ -1627,7 +1591,12 @@ mod tests {
                  teststr: String)
                  -> StringReader<'a> {
         let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr);
-        StringReader::new(sess, sf, None)
+        let mut sr = StringReader::new_raw(sess, sf, None);
+        if sr.advance_token().is_err() {
+            sr.emit_fatal_errors();
+            FatalError.raise();
+        }
+        sr
     }
 
     #[test]
diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs
index 0db36c84cdf..4bfc5bb16c0 100644
--- a/src/libsyntax/parse/lexer/tokentrees.rs
+++ b/src/libsyntax/parse/lexer/tokentrees.rs
@@ -1,13 +1,46 @@
+use syntax_pos::Span;
+
 use crate::print::pprust::token_to_string;
 use crate::parse::lexer::{StringReader, UnmatchedBrace};
 use crate::parse::{token, PResult};
 use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
 
 impl<'a> StringReader<'a> {
+    crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
+        let mut tt_reader = TokenTreesReader {
+            string_reader: self,
+            token: token::Eof,
+            span: syntax_pos::DUMMY_SP,
+            open_braces: Vec::new(),
+            unmatched_braces: Vec::new(),
+            matching_delim_spans: Vec::new(),
+            last_unclosed_found_span: None,
+        };
+        let res = tt_reader.parse_all_token_trees();
+        (res, tt_reader.unmatched_braces)
+    }
+}
+
+struct TokenTreesReader<'a> {
+    string_reader: StringReader<'a>,
+    token: token::Token,
+    span: Span,
+    /// Stack of open delimiters and their spans. Used for error message.
+    open_braces: Vec<(token::DelimToken, Span)>,
+    unmatched_braces: Vec<UnmatchedBrace>,
+    /// The type and spans for all braces
+    ///
+    /// Used only for error recovery when arriving to EOF with mismatched braces.
+    matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
+    last_unclosed_found_span: Option<Span>,
+}
+
+impl<'a> TokenTreesReader<'a> {
     // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
-    crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
+    fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
         let mut tts = Vec::new();
 
+        self.real_token();
         while self.token != token::Eof {
             tts.push(self.parse_token_tree()?);
         }
@@ -34,11 +67,12 @@ impl<'a> StringReader<'a> {
     }
 
     fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
-        let sm = self.sess.source_map();
+        let sm = self.string_reader.sess.source_map();
         match self.token {
             token::Eof => {
                 let msg = "this file contains an un-closed delimiter";
-                let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg);
+                let mut err = self.string_reader.sess.span_diagnostic
+                    .struct_span_err(self.span, msg);
                 for &(_, sp) in &self.open_braces {
                     err.span_label(sp, "un-closed delimiter");
                 }
@@ -46,13 +80,12 @@ impl<'a> StringReader<'a> {
                 if let Some((delim, _)) = self.open_braces.last() {
                     if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter()
                         .filter(|(d, open_sp, close_sp)| {
-
-                        if let Some(close_padding) = sm.span_to_margin(*close_sp) {
-                            if let Some(open_padding) = sm.span_to_margin(*open_sp) {
-                                return delim == d && close_padding != open_padding;
+                            if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+                                if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+                                    return delim == d && close_padding != open_padding;
+                                }
                             }
-                        }
-                        false
+                            false
                         }).next()  // these are in reverse order as they get inserted on close, but
                     {              // we want the last open/first close
                         err.span_label(
@@ -164,7 +197,8 @@ impl<'a> StringReader<'a> {
                 // matching opening delimiter).
                 let token_str = token_to_string(&self.token);
                 let msg = format!("unexpected close delimiter: `{}`", token_str);
-                let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
+                let mut err = self.string_reader.sess.span_diagnostic
+                    .struct_span_err(self.span, &msg);
                 err.span_label(self.span, "unexpected close delimiter");
                 Err(err)
             },
@@ -173,11 +207,20 @@ impl<'a> StringReader<'a> {
                 // Note that testing for joint-ness here is done via the raw
                 // source span as the joint-ness is a property of the raw source
                 // rather than wanting to take `override_span` into account.
-                let raw = self.span_src_raw;
+                // Additionally, we actually check if the *next* pair of tokens
+                // is joint, but this is equivalent to checking the current pair.
+                let raw = self.string_reader.peek_span_src_raw;
                 self.real_token();
-                let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
+                let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo()
+                    && token::is_op(&self.token);
                 Ok((tt, if is_joint { Joint } else { NonJoint }))
             }
         }
     }
+
+    fn real_token(&mut self) {
+        let t = self.string_reader.real_token();
+        self.token = t.tok;
+        self.span = t.sp;
+    }
 }
diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs
new file mode 100644
index 00000000000..53195421ddc
--- /dev/null
+++ b/src/libsyntax/parse/literal.rs
@@ -0,0 +1,487 @@
+//! Code related to parsing literals.
+
+use crate::ast::{self, Ident, Lit, LitKind};
+use crate::parse::parser::Parser;
+use crate::parse::PResult;
+use crate::parse::token::{self, Token};
+use crate::parse::unescape::{unescape_str, unescape_char, unescape_byte_str, unescape_byte};
+use crate::print::pprust;
+use crate::symbol::{keywords, Symbol};
+use crate::tokenstream::{TokenStream, TokenTree};
+
+use errors::{Applicability, Handler};
+use log::debug;
+use rustc_data_structures::sync::Lrc;
+use syntax_pos::Span;
+
+use std::ascii;
+
+macro_rules! err {
+    ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => {
+        match $opt_diag {
+            Some(($span, $diag)) => { $($body)* }
+            None => return None,
+        }
+    }
+}
+
+impl LitKind {
+    /// Converts literal token with a suffix into a semantic literal.
+    /// Works speculatively and may return `None` if diagnostic handler is not passed.
+    /// If diagnostic handler is passed, always returns `Some`,
+    /// possibly after reporting non-fatal errors and recovery.
+    fn from_lit_token(
+        lit: token::Lit,
+        suf: Option<Symbol>,
+        diag: Option<(Span, &Handler)>
+    ) -> Option<LitKind> {
+        if suf.is_some() && !lit.may_have_suffix() {
+            err!(diag, |span, diag| {
+                expect_no_suffix(span, diag, &format!("a {}", lit.literal_name()), suf)
+            });
+        }
+
+        Some(match lit {
+            token::Bool(i) => {
+                assert!(i == keywords::True.name() || i == keywords::False.name());
+                LitKind::Bool(i == keywords::True.name())
+            }
+            token::Byte(i) => {
+                match unescape_byte(&i.as_str()) {
+                    Ok(c) => LitKind::Byte(c),
+                    Err(_) => LitKind::Err(i),
+                }
+            },
+            token::Char(i) => {
+                match unescape_char(&i.as_str()) {
+                    Ok(c) => LitKind::Char(c),
+                    Err(_) => LitKind::Err(i),
+                }
+            },
+            token::Err(i) => LitKind::Err(i),
+
+            // There are some valid suffixes for integer and float literals,
+            // so all the handling is done internally.
+            token::Integer(s) => return integer_lit(&s.as_str(), suf, diag),
+            token::Float(s) => return float_lit(&s.as_str(), suf, diag),
+
+            token::Str_(mut sym) => {
+                // If there are no characters requiring special treatment we can
+                // reuse the symbol from the Token. Otherwise, we must generate a
+                // new symbol because the string in the LitKind is different to the
+                // string in the Token.
+                let mut has_error = false;
+                let s = &sym.as_str();
+                if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') {
+                    let mut buf = String::with_capacity(s.len());
+                    unescape_str(s, &mut |_, unescaped_char| {
+                        match unescaped_char {
+                            Ok(c) => buf.push(c),
+                            Err(_) => has_error = true,
+                        }
+                    });
+                    if has_error {
+                        return Some(LitKind::Err(sym));
+                    }
+                    sym = Symbol::intern(&buf)
+                }
+
+                LitKind::Str(sym, ast::StrStyle::Cooked)
+            }
+            token::StrRaw(mut sym, n) => {
+                // Ditto.
+                let s = &sym.as_str();
+                if s.contains('\r') {
+                    sym = Symbol::intern(&raw_str_lit(s));
+                }
+                LitKind::Str(sym, ast::StrStyle::Raw(n))
+            }
+            token::ByteStr(i) => {
+                let s = &i.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut has_error = false;
+                unescape_byte_str(s, &mut |_, unescaped_byte| {
+                    match unescaped_byte {
+                        Ok(c) => buf.push(c),
+                        Err(_) => has_error = true,
+                    }
+                });
+                if has_error {
+                    return Some(LitKind::Err(i));
+                }
+                buf.shrink_to_fit();
+                LitKind::ByteStr(Lrc::new(buf))
+            }
+            token::ByteStrRaw(i, _) => {
+                LitKind::ByteStr(Lrc::new(i.to_string().into_bytes()))
+            }
+        })
+    }
+
+    /// Attempts to recover a token from semantic literal.
+    /// This function is used when the original token doesn't exist (e.g. the literal is created
+    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
+    pub fn to_lit_token(&self) -> (token::Lit, Option<Symbol>) {
+        match *self {
+            LitKind::Str(string, ast::StrStyle::Cooked) => {
+                let escaped = string.as_str().escape_default().to_string();
+                (token::Lit::Str_(Symbol::intern(&escaped)), None)
+            }
+            LitKind::Str(string, ast::StrStyle::Raw(n)) => {
+                (token::Lit::StrRaw(string, n), None)
+            }
+            LitKind::ByteStr(ref bytes) => {
+                let string = bytes.iter().cloned().flat_map(ascii::escape_default)
+                    .map(Into::<char>::into).collect::<String>();
+                (token::Lit::ByteStr(Symbol::intern(&string)), None)
+            }
+            LitKind::Byte(byte) => {
+                let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
+                (token::Lit::Byte(Symbol::intern(&string)), None)
+            }
+            LitKind::Char(ch) => {
+                let string: String = ch.escape_default().map(Into::<char>::into).collect();
+                (token::Lit::Char(Symbol::intern(&string)), None)
+            }
+            LitKind::Int(n, ty) => {
+                let suffix = match ty {
+                    ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())),
+                    ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())),
+                    ast::LitIntType::Unsuffixed => None,
+                };
+                (token::Lit::Integer(Symbol::intern(&n.to_string())), suffix)
+            }
+            LitKind::Float(symbol, ty) => {
+                (token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string())))
+            }
+            LitKind::FloatUnsuffixed(symbol) => (token::Lit::Float(symbol), None),
+            LitKind::Bool(value) => {
+                let kw = if value { keywords::True } else { keywords::False };
+                (token::Lit::Bool(kw.name()), None)
+            }
+            LitKind::Err(val) => (token::Lit::Err(val), None),
+        }
+    }
+}
+
+impl Lit {
+    /// Converts literal token with a suffix into an AST literal.
+    /// Works speculatively and may return `None` if diagnostic handler is not passed.
+    /// If diagnostic handler is passed, may return `Some`,
+    /// possibly after reporting non-fatal errors and recovery, or `None` for irrecoverable errors.
+    crate fn from_token(
+        token: &token::Token,
+        span: Span,
+        diag: Option<(Span, &Handler)>,
+    ) -> Option<Lit> {
+        let (token, suffix) = match *token {
+            token::Ident(ident, false) if ident.name == keywords::True.name() ||
+                                          ident.name == keywords::False.name() =>
+                (token::Bool(ident.name), None),
+            token::Literal(token, suffix) =>
+                (token, suffix),
+            token::Interpolated(ref nt) => {
+                if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
+                    if let ast::ExprKind::Lit(lit) = &expr.node {
+                        return Some(lit.clone());
+                    }
+                }
+                return None;
+            }
+            _ => return None,
+        };
+
+        let node = LitKind::from_lit_token(token, suffix, diag)?;
+        Some(Lit { node, token, suffix, span })
+    }
+
+    /// Attempts to recover an AST literal from semantic literal.
+    /// This function is used when the original token doesn't exist (e.g. the literal is created
+    /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing).
+    pub fn from_lit_kind(node: LitKind, span: Span) -> Lit {
+        let (token, suffix) = node.to_lit_token();
+        Lit { node, token, suffix, span }
+    }
+
+    /// Losslessly convert an AST literal into a token stream.
+    crate fn tokens(&self) -> TokenStream {
+        let token = match self.token {
+            token::Bool(symbol) => Token::Ident(Ident::with_empty_ctxt(symbol), false),
+            token => Token::Literal(token, self.suffix),
+        };
+        TokenTree::Token(self.span, token).into()
+    }
+}
+
+impl<'a> Parser<'a> {
+    /// Matches `lit = true | false | token_lit`.
+    crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
+        let diag = Some((self.span, &self.sess.span_diagnostic));
+        if let Some(lit) = Lit::from_token(&self.token, self.span, diag) {
+            self.bump();
+            return Ok(lit);
+        } else if self.token == token::Dot {
+            // Recover `.4` as `0.4`.
+            let recovered = self.look_ahead(1, |t| {
+                if let token::Literal(token::Integer(val), suf) = *t {
+                    let next_span = self.look_ahead_span(1);
+                    if self.span.hi() == next_span.lo() {
+                        let sym = String::from("0.") + &val.as_str();
+                        let token = token::Literal(token::Float(Symbol::intern(&sym)), suf);
+                        return Some((token, self.span.to(next_span)));
+                    }
+                }
+                None
+            });
+            if let Some((token, span)) = recovered {
+                self.diagnostic()
+                    .struct_span_err(span, "float literals must have an integer part")
+                    .span_suggestion(
+                        span,
+                        "must have an integer part",
+                        pprust::token_to_string(&token),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                let diag = Some((span, &self.sess.span_diagnostic));
+                if let Some(lit) = Lit::from_token(&token, span, diag) {
+                    self.bump();
+                    self.bump();
+                    return Ok(lit);
+                }
+            }
+        }
+
+        Err(self.span_fatal(self.span, &format!("unexpected token: {}", self.this_token_descr())))
+    }
+}
+
+crate fn expect_no_suffix(sp: Span, diag: &Handler, kind: &str, suffix: Option<ast::Name>) {
+    match suffix {
+        None => {/* everything ok */}
+        Some(suf) => {
+            let text = suf.as_str();
+            if text.is_empty() {
+                diag.span_bug(sp, "found empty literal suffix in Some")
+            }
+            let mut err = if kind == "a tuple index" &&
+                ["i32", "u32", "isize", "usize"].contains(&text.to_string().as_str())
+            {
+                // #59553: warn instead of reject out of hand to allow the fix to percolate
+                // through the ecosystem when people fix their macros
+                let mut err = diag.struct_span_warn(
+                    sp,
+                    &format!("suffixes on {} are invalid", kind),
+                );
+                err.note(&format!(
+                    "`{}` is *temporarily* accepted on tuple index fields as it was \
+                        incorrectly accepted on stable for a few releases",
+                    text,
+                ));
+                err.help(
+                    "on proc macros, you'll want to use `syn::Index::from` or \
+                        `proc_macro::Literal::*_unsuffixed` for code that will desugar \
+                        to tuple field access",
+                );
+                err.note(
+                    "for more context, see https://github.com/rust-lang/rust/issues/60210",
+                );
+                err
+            } else {
+                diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
+            };
+            err.span_label(sp, format!("invalid suffix `{}`", text));
+            err.emit();
+        }
+    }
+}
+
+/// Parses a string representing a raw string literal into its final form. The
+/// only operation this does is convert embedded CRLF into a single LF.
+fn raw_str_lit(lit: &str) -> String {
+    debug!("raw_str_lit: given {}", lit.escape_default());
+    let mut res = String::with_capacity(lit.len());
+
+    let mut chars = lit.chars().peekable();
+    while let Some(c) = chars.next() {
+        if c == '\r' {
+            if *chars.peek().unwrap() != '\n' {
+                panic!("lexer accepted bare CR");
+            }
+            chars.next();
+            res.push('\n');
+        } else {
+            res.push(c);
+        }
+    }
+
+    res.shrink_to_fit();
+    res
+}
+
+// check if `s` looks like i32 or u1234 etc.
+fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
+    s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
+}
+
+fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
+                      -> Option<LitKind> {
+    debug!("filtered_float_lit: {}, {:?}", data, suffix);
+    let suffix = match suffix {
+        Some(suffix) => suffix,
+        None => return Some(LitKind::FloatUnsuffixed(data)),
+    };
+
+    Some(match &*suffix.as_str() {
+        "f32" => LitKind::Float(data, ast::FloatTy::F32),
+        "f64" => LitKind::Float(data, ast::FloatTy::F64),
+        suf => {
+            err!(diag, |span, diag| {
+                if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) {
+                    // if it looks like a width, lets try to be helpful.
+                    let msg = format!("invalid width `{}` for float literal", &suf[1..]);
+                    diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit()
+                } else {
+                    let msg = format!("invalid suffix `{}` for float literal", suf);
+                    diag.struct_span_err(span, &msg)
+                        .span_label(span, format!("invalid suffix `{}`", suf))
+                        .help("valid suffixes are `f32` and `f64`")
+                        .emit();
+                }
+            });
+
+            LitKind::FloatUnsuffixed(data)
+        }
+    })
+}
+fn float_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
+                 -> Option<LitKind> {
+    debug!("float_lit: {:?}, {:?}", s, suffix);
+    // FIXME #2252: bounds checking float literals is deferred until trans
+
+    // Strip underscores without allocating a new String unless necessary.
+    let s2;
+    let s = if s.chars().any(|c| c == '_') {
+        s2 = s.chars().filter(|&c| c != '_').collect::<String>();
+        &s2
+    } else {
+        s
+    };
+
+    filtered_float_lit(Symbol::intern(s), suffix, diag)
+}
+
+fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
+                   -> Option<LitKind> {
+    // s can only be ascii, byte indexing is fine
+
+    // Strip underscores without allocating a new String unless necessary.
+    let s2;
+    let mut s = if s.chars().any(|c| c == '_') {
+        s2 = s.chars().filter(|&c| c != '_').collect::<String>();
+        &s2
+    } else {
+        s
+    };
+
+    debug!("integer_lit: {}, {:?}", s, suffix);
+
+    let mut base = 10;
+    let orig = s;
+    let mut ty = ast::LitIntType::Unsuffixed;
+
+    if s.starts_with('0') && s.len() > 1 {
+        match s.as_bytes()[1] {
+            b'x' => base = 16,
+            b'o' => base = 8,
+            b'b' => base = 2,
+            _ => { }
+        }
+    }
+
+    // 1f64 and 2f32 etc. are valid float literals.
+    if let Some(suf) = suffix {
+        if looks_like_width_suffix(&['f'], &suf.as_str()) {
+            let err = match base {
+                16 => Some("hexadecimal float literal is not supported"),
+                8 => Some("octal float literal is not supported"),
+                2 => Some("binary float literal is not supported"),
+                _ => None,
+            };
+            if let Some(err) = err {
+                err!(diag, |span, diag| {
+                    diag.struct_span_err(span, err)
+                        .span_label(span, "not supported")
+                        .emit();
+                });
+            }
+            return filtered_float_lit(Symbol::intern(s), Some(suf), diag)
+        }
+    }
+
+    if base != 10 {
+        s = &s[2..];
+    }
+
+    if let Some(suf) = suffix {
+        if suf.as_str().is_empty() {
+            err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some"));
+        }
+        ty = match &*suf.as_str() {
+            "isize" => ast::LitIntType::Signed(ast::IntTy::Isize),
+            "i8"  => ast::LitIntType::Signed(ast::IntTy::I8),
+            "i16" => ast::LitIntType::Signed(ast::IntTy::I16),
+            "i32" => ast::LitIntType::Signed(ast::IntTy::I32),
+            "i64" => ast::LitIntType::Signed(ast::IntTy::I64),
+            "i128" => ast::LitIntType::Signed(ast::IntTy::I128),
+            "usize" => ast::LitIntType::Unsigned(ast::UintTy::Usize),
+            "u8"  => ast::LitIntType::Unsigned(ast::UintTy::U8),
+            "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16),
+            "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32),
+            "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64),
+            "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128),
+            suf => {
+                // i<digits> and u<digits> look like widths, so lets
+                // give an error message along those lines
+                err!(diag, |span, diag| {
+                    if looks_like_width_suffix(&['i', 'u'], suf) {
+                        let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
+                        diag.struct_span_err(span, &msg)
+                            .help("valid widths are 8, 16, 32, 64 and 128")
+                            .emit();
+                    } else {
+                        let msg = format!("invalid suffix `{}` for numeric literal", suf);
+                        diag.struct_span_err(span, &msg)
+                            .span_label(span, format!("invalid suffix `{}`", suf))
+                            .help("the suffix must be one of the integral types \
+                                   (`u32`, `isize`, etc)")
+                            .emit();
+                    }
+                });
+
+                ty
+            }
+        }
+    }
+
+    debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \
+           string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix);
+
+    Some(match u128::from_str_radix(s, base) {
+        Ok(r) => LitKind::Int(r, ty),
+        Err(_) => {
+            // small bases are lexed as if they were base 10, e.g, the string
+            // might be `0b10201`. This will cause the conversion above to fail,
+            // but these cases have errors in the lexer: we don't want to emit
+            // two errors, and we especially don't want to emit this error since
+            // it isn't necessarily true.
+            let already_errored = base < 10 &&
+                s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
+
+            if !already_errored {
+                err!(diag, |span, diag| diag.span_err(span, "int literal is too large"));
+            }
+            LitKind::Int(0, ty)
+        }
+    })
+}
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index be44b964ba5..0611c1d9b42 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -5,7 +5,6 @@ use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
 use crate::source_map::{SourceMap, FilePathMapping};
 use crate::feature_gate::UnstableFeatures;
 use crate::parse::parser::Parser;
-use crate::symbol::Symbol;
 use crate::syntax::parse::parser::emit_unclosed_delims;
 use crate::tokenstream::{TokenStream, TokenTree};
 use crate::diagnostics::plugin::ErrorMap;
@@ -14,7 +13,6 @@ use crate::print::pprust::token_to_string;
 use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
 use rustc_data_structures::sync::{Lrc, Lock};
 use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
-use log::debug;
 
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use std::borrow::Cow;
@@ -25,18 +23,15 @@ pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
 
 #[macro_use]
 pub mod parser;
-
+pub mod attr;
 pub mod lexer;
 pub mod token;
-pub mod attr;
-pub mod diagnostics;
-
-pub mod classify;
-
-pub(crate) mod unescape;
-use unescape::{unescape_str, unescape_char, unescape_byte_str, unescape_byte};
 
-pub(crate) mod unescape_error_reporting;
+crate mod classify;
+crate mod diagnostics;
+crate mod literal;
+crate mod unescape;
+crate mod unescape_error_reporting;
 
 /// Info about a parsing session.
 pub struct ParseSess {
@@ -295,22 +290,22 @@ pub fn source_file_to_stream(
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
-/// parsing the token tream.
+/// parsing the token stream.
 pub fn maybe_file_to_stream(
     sess: &ParseSess,
     source_file: Lrc<SourceFile>,
     override_span: Option<Span>,
 ) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
-    let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
-    srdr.real_token();
+    let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
+    let (token_trees, unmatched_braces) = srdr.into_token_trees();
 
-    match srdr.parse_all_token_trees() {
-        Ok(stream) => Ok((stream, srdr.unmatched_braces)),
+    match token_trees {
+        Ok(stream) => Ok((stream, unmatched_braces)),
         Err(err) => {
             let mut buffer = Vec::with_capacity(1);
             err.buffer(&mut buffer);
             // Not using `emit_unclosed_delims` to use `db.buffer`
-            for unmatched in srdr.unmatched_braces {
+            for unmatched in unmatched_braces {
                 let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!(
                     "incorrect close delimiter: `{}`",
                     token_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
@@ -334,284 +329,6 @@ pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> {
     Parser::new(sess, stream, None, true, false)
 }
 
-/// Parses a string representing a raw string literal into its final form. The
-/// only operation this does is convert embedded CRLF into a single LF.
-fn raw_str_lit(lit: &str) -> String {
-    debug!("raw_str_lit: given {}", lit.escape_default());
-    let mut res = String::with_capacity(lit.len());
-
-    let mut chars = lit.chars().peekable();
-    while let Some(c) = chars.next() {
-        if c == '\r' {
-            if *chars.peek().unwrap() != '\n' {
-                panic!("lexer accepted bare CR");
-            }
-            chars.next();
-            res.push('\n');
-        } else {
-            res.push(c);
-        }
-    }
-
-    res.shrink_to_fit();
-    res
-}
-
-// check if `s` looks like i32 or u1234 etc.
-fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
-    s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
-}
-
-macro_rules! err {
-    ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => {
-        match $opt_diag {
-            Some(($span, $diag)) => { $($body)* }
-            None => return None,
-        }
-    }
-}
-
-crate fn lit_token(lit: token::Lit, suf: Option<Symbol>, diag: Option<(Span, &Handler)>)
-                 -> (bool /* suffix illegal? */, Option<ast::LitKind>) {
-    use ast::LitKind;
-
-    match lit {
-        token::Byte(i) => {
-            let lit_kind = match unescape_byte(&i.as_str()) {
-                Ok(c) => LitKind::Byte(c),
-                Err(_) => LitKind::Err(i),
-            };
-            (true, Some(lit_kind))
-        },
-        token::Char(i) => {
-            let lit_kind = match unescape_char(&i.as_str()) {
-                Ok(c) => LitKind::Char(c),
-                Err(_) => LitKind::Err(i),
-            };
-            (true, Some(lit_kind))
-        },
-        token::Err(i) => (true, Some(LitKind::Err(i))),
-
-        // There are some valid suffixes for integer and float literals,
-        // so all the handling is done internally.
-        token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)),
-        token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)),
-
-        token::Str_(mut sym) => {
-            // If there are no characters requiring special treatment we can
-            // reuse the symbol from the Token. Otherwise, we must generate a
-            // new symbol because the string in the LitKind is different to the
-            // string in the Token.
-            let mut has_error = false;
-            let s = &sym.as_str();
-            if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') {
-                let mut buf = String::with_capacity(s.len());
-                unescape_str(s, &mut |_, unescaped_char| {
-                    match unescaped_char {
-                        Ok(c) => buf.push(c),
-                        Err(_) => has_error = true,
-                    }
-                });
-                if has_error {
-                    return (true, Some(LitKind::Err(sym)));
-                }
-                sym = Symbol::intern(&buf)
-            }
-
-            (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked)))
-        }
-        token::StrRaw(mut sym, n) => {
-            // Ditto.
-            let s = &sym.as_str();
-            if s.contains('\r') {
-                sym = Symbol::intern(&raw_str_lit(s));
-            }
-            (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n))))
-        }
-        token::ByteStr(i) => {
-            let s = &i.as_str();
-            let mut buf = Vec::with_capacity(s.len());
-            let mut has_error = false;
-            unescape_byte_str(s, &mut |_, unescaped_byte| {
-                match unescaped_byte {
-                    Ok(c) => buf.push(c),
-                    Err(_) => has_error = true,
-                }
-            });
-            if has_error {
-                return (true, Some(LitKind::Err(i)));
-            }
-            buf.shrink_to_fit();
-            (true, Some(LitKind::ByteStr(Lrc::new(buf))))
-        }
-        token::ByteStrRaw(i, _) => {
-            (true, Some(LitKind::ByteStr(Lrc::new(i.to_string().into_bytes()))))
-        }
-    }
-}
-
-fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
-                      -> Option<ast::LitKind> {
-    debug!("filtered_float_lit: {}, {:?}", data, suffix);
-    let suffix = match suffix {
-        Some(suffix) => suffix,
-        None => return Some(ast::LitKind::FloatUnsuffixed(data)),
-    };
-
-    Some(match &*suffix.as_str() {
-        "f32" => ast::LitKind::Float(data, ast::FloatTy::F32),
-        "f64" => ast::LitKind::Float(data, ast::FloatTy::F64),
-        suf => {
-            err!(diag, |span, diag| {
-                if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) {
-                    // if it looks like a width, lets try to be helpful.
-                    let msg = format!("invalid width `{}` for float literal", &suf[1..]);
-                    diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit()
-                } else {
-                    let msg = format!("invalid suffix `{}` for float literal", suf);
-                    diag.struct_span_err(span, &msg)
-                        .span_label(span, format!("invalid suffix `{}`", suf))
-                        .help("valid suffixes are `f32` and `f64`")
-                        .emit();
-                }
-            });
-
-            ast::LitKind::FloatUnsuffixed(data)
-        }
-    })
-}
-fn float_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
-                 -> Option<ast::LitKind> {
-    debug!("float_lit: {:?}, {:?}", s, suffix);
-    // FIXME #2252: bounds checking float literals is deferred until trans
-
-    // Strip underscores without allocating a new String unless necessary.
-    let s2;
-    let s = if s.chars().any(|c| c == '_') {
-        s2 = s.chars().filter(|&c| c != '_').collect::<String>();
-        &s2
-    } else {
-        s
-    };
-
-    filtered_float_lit(Symbol::intern(s), suffix, diag)
-}
-
-fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
-                   -> Option<ast::LitKind> {
-    // s can only be ascii, byte indexing is fine
-
-    // Strip underscores without allocating a new String unless necessary.
-    let s2;
-    let mut s = if s.chars().any(|c| c == '_') {
-        s2 = s.chars().filter(|&c| c != '_').collect::<String>();
-        &s2
-    } else {
-        s
-    };
-
-    debug!("integer_lit: {}, {:?}", s, suffix);
-
-    let mut base = 10;
-    let orig = s;
-    let mut ty = ast::LitIntType::Unsuffixed;
-
-    if s.starts_with('0') && s.len() > 1 {
-        match s.as_bytes()[1] {
-            b'x' => base = 16,
-            b'o' => base = 8,
-            b'b' => base = 2,
-            _ => { }
-        }
-    }
-
-    // 1f64 and 2f32 etc. are valid float literals.
-    if let Some(suf) = suffix {
-        if looks_like_width_suffix(&['f'], &suf.as_str()) {
-            let err = match base {
-                16 => Some("hexadecimal float literal is not supported"),
-                8 => Some("octal float literal is not supported"),
-                2 => Some("binary float literal is not supported"),
-                _ => None,
-            };
-            if let Some(err) = err {
-                err!(diag, |span, diag| {
-                    diag.struct_span_err(span, err)
-                        .span_label(span, "not supported")
-                        .emit();
-                });
-            }
-            return filtered_float_lit(Symbol::intern(s), Some(suf), diag)
-        }
-    }
-
-    if base != 10 {
-        s = &s[2..];
-    }
-
-    if let Some(suf) = suffix {
-        if suf.as_str().is_empty() {
-            err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some"));
-        }
-        ty = match &*suf.as_str() {
-            "isize" => ast::LitIntType::Signed(ast::IntTy::Isize),
-            "i8"  => ast::LitIntType::Signed(ast::IntTy::I8),
-            "i16" => ast::LitIntType::Signed(ast::IntTy::I16),
-            "i32" => ast::LitIntType::Signed(ast::IntTy::I32),
-            "i64" => ast::LitIntType::Signed(ast::IntTy::I64),
-            "i128" => ast::LitIntType::Signed(ast::IntTy::I128),
-            "usize" => ast::LitIntType::Unsigned(ast::UintTy::Usize),
-            "u8"  => ast::LitIntType::Unsigned(ast::UintTy::U8),
-            "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16),
-            "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32),
-            "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64),
-            "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128),
-            suf => {
-                // i<digits> and u<digits> look like widths, so lets
-                // give an error message along those lines
-                err!(diag, |span, diag| {
-                    if looks_like_width_suffix(&['i', 'u'], suf) {
-                        let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
-                        diag.struct_span_err(span, &msg)
-                            .help("valid widths are 8, 16, 32, 64 and 128")
-                            .emit();
-                    } else {
-                        let msg = format!("invalid suffix `{}` for numeric literal", suf);
-                        diag.struct_span_err(span, &msg)
-                            .span_label(span, format!("invalid suffix `{}`", suf))
-                            .help("the suffix must be one of the integral types \
-                                   (`u32`, `isize`, etc)")
-                            .emit();
-                    }
-                });
-
-                ty
-            }
-        }
-    }
-
-    debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \
-           string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix);
-
-    Some(match u128::from_str_radix(s, base) {
-        Ok(r) => ast::LitKind::Int(r, ty),
-        Err(_) => {
-            // small bases are lexed as if they were base 10, e.g, the string
-            // might be `0b10201`. This will cause the conversion above to fail,
-            // but these cases have errors in the lexer: we don't want to emit
-            // two errors, and we especially don't want to emit this error since
-            // it isn't necessarily true.
-            let already_errored = base < 10 &&
-                s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
-
-            if !already_errored {
-                err!(diag, |span, diag| diag.span_err(span, "int literal is too large"));
-            }
-            ast::LitKind::Int(0, ty)
-        }
-    })
-}
-
 /// A sequence separator.
 pub struct SeqSep {
     /// The seperator token.
@@ -674,6 +391,8 @@ mod tests {
     #[test]
     fn string_to_tts_macro () {
         with_globals(|| {
+            use crate::symbol::sym;
+
             let tts: Vec<_> =
                 string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect();
             let tts: &[TokenTree] = &tts[..];
@@ -686,8 +405,8 @@ mod tests {
                     Some(&TokenTree::Token(_, token::Ident(name_zip, false))),
                     Some(&TokenTree::Delimited(_, macro_delim, ref macro_tts)),
                 )
-                if name_macro_rules.name == "macro_rules"
-                && name_zip.name == "zip" => {
+                if name_macro_rules.name == sym::macro_rules
+                && name_zip.name.as_str() == "zip" => {
                     let tts = &macro_tts.trees().collect::<Vec<_>>();
                     match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) {
                         (
@@ -704,7 +423,7 @@ mod tests {
                                     Some(&TokenTree::Token(_, token::Dollar)),
                                     Some(&TokenTree::Token(_, token::Ident(ident, false))),
                                 )
-                                if first_delim == token::Paren && ident.name == "a" => {},
+                                if first_delim == token::Paren && ident.name.as_str() == "a" => {},
                                 _ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
                             }
                             let tts = &second_tts.trees().collect::<Vec<_>>();
@@ -714,7 +433,7 @@ mod tests {
                                     Some(&TokenTree::Token(_, token::Dollar)),
                                     Some(&TokenTree::Token(_, token::Ident(ident, false))),
                                 )
-                                if second_delim == token::Paren && ident.name == "a" => {},
+                                if second_delim == token::Paren && ident.name.as_str() == "a" => {},
                                 _ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
                             }
                         },
@@ -858,20 +577,22 @@ mod tests {
 
     #[test] fn crlf_doc_comments() {
         with_globals(|| {
+            use crate::symbol::sym;
+
             let sess = ParseSess::new(FilePathMapping::empty());
 
             let name_1 = FileName::Custom("crlf_source_1".to_string());
             let source = "/// doc comment\r\nfn foo() {}".to_string();
             let item = parse_item_from_source_str(name_1, source, &sess)
                 .unwrap().unwrap();
-            let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
-            assert_eq!(doc, "/// doc comment");
+            let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap();
+            assert_eq!(doc.as_str(), "/// doc comment");
 
             let name_2 = FileName::Custom("crlf_source_2".to_string());
             let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
             let item = parse_item_from_source_str(name_2, source, &sess)
                 .unwrap().unwrap();
-            let docs = item.attrs.iter().filter(|a| a.path == "doc")
+            let docs = item.attrs.iter().filter(|a| a.path == sym::doc)
                         .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>();
             let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()];
             assert_eq!(&docs[..], b);
@@ -879,8 +600,8 @@ mod tests {
             let name_3 = FileName::Custom("clrf_source_3".to_string());
             let source = "/** doc comment\r\n *  with CRLF */\r\nfn foo() {}".to_string();
             let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap();
-            let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
-            assert_eq!(doc, "/** doc comment\n *  with CRLF */");
+            let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap();
+            assert_eq!(doc.as_str(), "/** doc comment\n *  with CRLF */");
         });
     }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d97d1e2f0f4..24d120376de 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -15,7 +15,7 @@ use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
 use crate::ast::{GenericParam, GenericParamKind};
 use crate::ast::GenericArg;
 use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind};
-use crate::ast::{Label, Lifetime, Lit, LitKind};
+use crate::ast::{Label, Lifetime};
 use crate::ast::{Local, LocalSource};
 use crate::ast::MacStmtStyle;
 use crate::ast::{Mac, Mac_, MacDelimiter};
@@ -35,7 +35,7 @@ use crate::ast::{RangeEnd, RangeSyntax};
 use crate::{ast, attr};
 use crate::ext::base::DummyResult;
 use crate::source_map::{self, SourceMap, Spanned, respan};
-use crate::parse::{self, SeqSep, classify, token};
+use crate::parse::{SeqSep, classify, literal, token};
 use crate::parse::lexer::{TokenAndSpan, UnmatchedBrace};
 use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
 use crate::parse::token::DelimToken;
@@ -46,7 +46,7 @@ use crate::ptr::P;
 use crate::parse::PResult;
 use crate::ThinVec;
 use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
-use crate::symbol::{Symbol, keywords};
+use crate::symbol::{keywords, sym, Symbol};
 
 use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
 use rustc_target::spec::abi::{self, Abi};
@@ -104,14 +104,14 @@ pub enum PathStyle {
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
-enum SemiColonMode {
+crate enum SemiColonMode {
     Break,
     Ignore,
     Comma,
 }
 
 #[derive(Clone, Copy, PartialEq, Debug)]
-enum BlockMode {
+crate enum BlockMode {
     Break,
     Ignore,
 }
@@ -352,7 +352,7 @@ impl TokenCursor {
         let body = TokenTree::Delimited(
             delim_span,
             token::Bracket,
-            [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)),
+            [TokenTree::Token(sp, token::Ident(ast::Ident::with_empty_ctxt(sym::doc), false)),
              TokenTree::Token(sp, token::Eq),
              TokenTree::Token(sp, token::Literal(
                 token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None))
@@ -389,7 +389,7 @@ crate enum TokenType {
 }
 
 impl TokenType {
-    fn to_string(&self) -> String {
+    crate fn to_string(&self) -> String {
         match *self {
             TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)),
             TokenType::Keyword(kw) => format!("`{}`", kw.name()),
@@ -613,7 +613,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn this_token_descr(&self) -> String {
+    crate fn this_token_descr(&self) -> String {
         if let Some(prefix) = self.token_descr() {
             format!("{} `{}`", prefix, self.this_token_to_string())
         } else {
@@ -621,11 +621,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> {
-        let token_str = pprust::token_to_string(t);
-        Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str)))
-    }
-
     crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
@@ -678,56 +673,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn recover_closing_delimiter(
-        &mut self,
-        tokens: &[token::Token],
-        mut err: DiagnosticBuilder<'a>,
-    ) -> PResult<'a, bool> {
-        let mut pos = None;
-        // we want to use the last closing delim that would apply
-        for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
-            if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
-                && Some(self.span) > unmatched.unclosed_span
-            {
-                pos = Some(i);
-            }
-        }
-        match pos {
-            Some(pos) => {
-                // Recover and assume that the detected unclosed delimiter was meant for
-                // this location. Emit the diagnostic and act as if the delimiter was
-                // present for the parser's sake.
-
-                 // Don't attempt to recover from this unclosed delimiter more than once.
-                let unmatched = self.unclosed_delims.remove(pos);
-                let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
-
-                 // We want to suggest the inclusion of the closing delimiter where it makes
-                // the most sense, which is immediately after the last token:
-                //
-                //  {foo(bar {}}
-                //      -      ^
-                //      |      |
-                //      |      help: `)` may belong here (FIXME: #58270)
-                //      |
-                //      unclosed delimiter
-                if let Some(sp) = unmatched.unclosed_span {
-                    err.span_label(sp, "unclosed delimiter");
-                }
-                err.span_suggestion_short(
-                    self.sess.source_map().next_point(self.prev_span),
-                    &format!("{} may belong here", delim.to_string()),
-                    delim.to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-                err.emit();
-                self.expected_tokens.clear();  // reduce errors
-                Ok(true)
-            }
-            _ => Err(err),
-        }
-    }
-
     /// Expect next token to be edible or inedible token.  If edible,
     /// then consume it; if inedible, then return without consuming
     /// anything.  Signal a fatal error if next token is unexpected.
@@ -1109,43 +1054,7 @@ impl<'a> Parser<'a> {
     }
 
     fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
-        match suffix {
-            None => {/* everything ok */}
-            Some(suf) => {
-                let text = suf.as_str();
-                if text.is_empty() {
-                    self.span_bug(sp, "found empty literal suffix in Some")
-                }
-                let mut err = if kind == "a tuple index" &&
-                    ["i32", "u32", "isize", "usize"].contains(&text.to_string().as_str())
-                {
-                    // #59553: warn instead of reject out of hand to allow the fix to percolate
-                    // through the ecosystem when people fix their macros
-                    let mut err = self.struct_span_warn(
-                        sp,
-                        &format!("suffixes on {} are invalid", kind),
-                    );
-                    err.note(&format!(
-                        "`{}` is *temporarily* accepted on tuple index fields as it was \
-                         incorrectly accepted on stable for a few releases",
-                        text,
-                    ));
-                    err.help(
-                        "on proc macros, you'll want to use `syn::Index::from` or \
-                         `proc_macro::Literal::*_unsuffixed` for code that will desugar \
-                         to tuple field access",
-                    );
-                    err.note(
-                        "for more context, see https://github.com/rust-lang/rust/issues/60210",
-                    );
-                    err
-                } else {
-                    self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
-                };
-                err.span_label(sp, format!("invalid suffix `{}`", text));
-                err.emit();
-            }
-        }
+        literal::expect_no_suffix(sp, &self.sess.span_diagnostic, kind, suffix)
     }
 
     /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single
@@ -1423,7 +1332,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn look_ahead_span(&self, dist: usize) -> Span {
+    crate fn look_ahead_span(&self, dist: usize) -> Span {
         if dist == 0 {
             return self.span
         }
@@ -1452,9 +1361,6 @@ impl<'a> Parser<'a> {
     crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
         self.sess.span_diagnostic.struct_span_err(sp, m)
     }
-    fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
-        self.sess.span_diagnostic.struct_span_warn(sp, m)
-    }
     crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
         self.sess.span_diagnostic.span_bug(sp, m)
     }
@@ -1877,7 +1783,7 @@ impl<'a> Parser<'a> {
         Ok(MutTy { ty: t, mutbl: mutbl })
     }
 
-    fn is_named_argument(&mut self) -> bool {
+    fn is_named_argument(&self) -> bool {
         let offset = match self.token {
             token::Interpolated(ref nt) => match **nt {
                 token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
@@ -1925,8 +1831,6 @@ impl<'a> Parser<'a> {
     /// This version of parse arg doesn't necessarily require identifier names.
     fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool,
                          allow_c_variadic: bool) -> PResult<'a, Arg> {
-        maybe_whole!(self, NtArg, |x| x);
-
         if let Ok(Some(_)) = self.parse_self_arg() {
             let mut err = self.struct_span_err(self.prev_span,
                 "unexpected `self` argument in function");
@@ -2069,88 +1973,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Matches `token_lit = LIT_INTEGER | ...`.
-    fn parse_lit_token(&mut self) -> PResult<'a, LitKind> {
-        let out = match self.token {
-            token::Interpolated(ref nt) => match **nt {
-                token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
-                    ExprKind::Lit(ref lit) => { lit.node.clone() }
-                    _ => { return self.unexpected_last(&self.token); }
-                },
-                _ => { return self.unexpected_last(&self.token); }
-            },
-            token::Literal(lit, suf) => {
-                let diag = Some((self.span, &self.sess.span_diagnostic));
-                let (suffix_illegal, result) = parse::lit_token(lit, suf, diag);
-
-                if suffix_illegal {
-                    let sp = self.span;
-                    self.expect_no_suffix(sp, &format!("a {}", lit.literal_name()), suf)
-                }
-
-                result.unwrap()
-            }
-            token::Dot if self.look_ahead(1, |t| match t {
-                token::Literal(parse::token::Lit::Integer(_) , _) => true,
-                _ => false,
-            }) => { // recover from `let x = .4;`
-                let lo = self.span;
-                self.bump();
-                if let token::Literal(
-                    parse::token::Lit::Integer(val),
-                    suffix,
-                ) = self.token {
-                    let suffix = suffix.and_then(|s| {
-                        let s = s.as_str();
-                        if s == "f32" {
-                            Some("f32")
-                        } else if s == "f64" {
-                            Some("f64")
-                        } else {
-                            None
-                        }
-                    }).unwrap_or("");
-                    self.bump();
-                    let sp = lo.to(self.prev_span);
-                    let mut err = self.diagnostic()
-                        .struct_span_err(sp, "float literals must have an integer part");
-                    err.span_suggestion(
-                        sp,
-                        "must have an integer part",
-                        format!("0.{}{}", val, suffix),
-                        Applicability::MachineApplicable,
-                    );
-                    err.emit();
-                    return Ok(match suffix {
-                        "f32" => ast::LitKind::Float(val, ast::FloatTy::F32),
-                        "f64" => ast::LitKind::Float(val, ast::FloatTy::F64),
-                        _ => ast::LitKind::FloatUnsuffixed(val),
-                    });
-                } else {
-                    unreachable!();
-                };
-            }
-            _ => { return self.unexpected_last(&self.token); }
-        };
-
-        self.bump();
-        Ok(out)
-    }
-
-    /// Matches `lit = true | false | token_lit`.
-    crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
-        let lo = self.span;
-        let lit = if self.eat_keyword(keywords::True) {
-            LitKind::Bool(true)
-        } else if self.eat_keyword(keywords::False) {
-            LitKind::Bool(false)
-        } else {
-            let lit = self.parse_lit_token()?;
-            lit
-        };
-        Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) })
-    }
-
     /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
     crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
         maybe_whole_expr!(self);
@@ -2471,27 +2293,27 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
+    crate fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
         P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
     }
 
-    fn mk_unary(&mut self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
+    fn mk_unary(&self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
         ExprKind::Unary(unop, expr)
     }
 
-    fn mk_binary(&mut self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
+    fn mk_binary(&self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
         ExprKind::Binary(binop, lhs, rhs)
     }
 
-    fn mk_call(&mut self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind {
+    fn mk_call(&self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind {
         ExprKind::Call(f, args)
     }
 
-    fn mk_index(&mut self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
+    fn mk_index(&self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
         ExprKind::Index(expr, idx)
     }
 
-    fn mk_range(&mut self,
+    fn mk_range(&self,
                     start: Option<P<Expr>>,
                     end: Option<P<Expr>>,
                     limits: RangeLimits)
@@ -2503,7 +2325,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn mk_assign_op(&mut self, binop: ast::BinOp,
+    fn mk_assign_op(&self, binop: ast::BinOp,
                         lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
         ExprKind::AssignOp(binop, lhs, rhs)
     }
@@ -2643,13 +2465,12 @@ impl<'a> Parser<'a> {
                     hi = path.span;
                     return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
                 }
-                if self.span.rust_2018() && self.check_keyword(keywords::Async)
-                {
-                    if self.is_async_block() { // check for `async {` and `async move {`
-                        return self.parse_async_block(attrs);
+                if self.span.rust_2018() && self.check_keyword(keywords::Async) {
+                    return if self.is_async_block() { // check for `async {` and `async move {`
+                        self.parse_async_block(attrs)
                     } else {
-                        return self.parse_lambda_expr(attrs);
-                    }
+                        self.parse_lambda_expr(attrs)
+                    };
                 }
                 if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) {
                     return self.parse_lambda_expr(attrs);
@@ -2758,13 +2579,9 @@ impl<'a> Parser<'a> {
                     db.note("variable declaration using `let` is a statement");
                     return Err(db);
                 } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
-                    // FIXME: remove this branch when `await!` is no longer supported
-                    // https://github.com/rust-lang/rust/issues/60610
-                    self.expect(&token::Not)?;
-                    self.expect(&token::OpenDelim(token::Paren))?;
-                    let expr = self.parse_expr()?;
-                    self.expect(&token::CloseDelim(token::Paren))?;
-                    ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
+                    let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?;
+                    hi = await_hi;
+                    ex = e_kind;
                 } else if self.token.is_path_start() {
                     let path = self.parse_path(PathStyle::Expr)?;
 
@@ -2829,6 +2646,31 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    /// Parse `await!(<expr>)` calls, or alternatively recover from incorrect but reasonable
+    /// alternative syntaxes `await <expr>`, `await? <expr>`, `await(<expr>)` and
+    /// `await { <expr> }`.
+    fn parse_await_macro_or_alt(
+        &mut self,
+        lo: Span,
+        await_sp: Span,
+    ) -> PResult<'a, (Span, ExprKind)> {
+        if self.token == token::Not {
+            // Handle correct `await!(<expr>)`.
+            // FIXME: make this an error when `await!` is no longer supported
+            // https://github.com/rust-lang/rust/issues/60610
+            self.expect(&token::Not)?;
+            self.expect(&token::OpenDelim(token::Paren))?;
+            let expr = self.parse_expr().map_err(|mut err| {
+                err.span_label(await_sp, "while parsing this await macro call");
+                err
+            })?;
+            self.expect(&token::CloseDelim(token::Paren))?;
+            Ok((self.prev_span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr)))
+        } else { // Handle `await <expr>`.
+            self.parse_incorrect_await_syntax(lo, await_sp)
+        }
+    }
+
     fn maybe_parse_struct_expr(
         &mut self,
         lo: Span,
@@ -2977,10 +2819,13 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a block or unsafe block.
-    fn parse_block_expr(&mut self, opt_label: Option<Label>,
-                            lo: Span, blk_mode: BlockCheckMode,
-                            outer_attrs: ThinVec<Attribute>)
-                            -> PResult<'a, P<Expr>> {
+    crate fn parse_block_expr(
+        &mut self,
+        opt_label: Option<Label>,
+        lo: Span,
+        blk_mode: BlockCheckMode,
+        outer_attrs: ThinVec<Attribute>,
+    ) -> PResult<'a, P<Expr>> {
         self.expect(&token::OpenDelim(token::Brace))?;
 
         let mut attrs = outer_attrs;
@@ -3041,6 +2886,7 @@ impl<'a> Parser<'a> {
                 ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
                 ThinVec::new(),
             );
+            self.recover_from_await_method_call();
             return Ok(await_expr);
         }
         let segment = self.parse_path_segment(PathStyle::Expr)?;
@@ -3279,23 +3125,6 @@ impl<'a> Parser<'a> {
         return Ok(e);
     }
 
-    fn recover_seq_parse_error(
-        &mut self,
-        delim: token::DelimToken,
-        lo: Span,
-        result: PResult<'a, P<Expr>>,
-    ) -> P<Expr> {
-        match result {
-            Ok(x) => x,
-            Err(mut err) => {
-                err.emit();
-                // recover from parse error
-                self.consume_block(delim);
-                self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new())
-            }
-        }
-    }
-
     crate fn process_potential_macro_variable(&mut self) {
         let (token, span) = match self.token {
             token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
@@ -3574,7 +3403,8 @@ impl<'a> Parser<'a> {
             } else {
                 self.restrictions
             };
-            if op.precedence() < min_prec {
+            let prec = op.precedence();
+            if prec < min_prec {
                 break;
             }
             // Check for deprecated `...` syntax
@@ -3615,8 +3445,7 @@ impl<'a> Parser<'a> {
                 // We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other
                 // two variants are handled with `parse_prefix_range_expr` call above.
                 let rhs = if self.is_at_start_of_range_notation_rhs() {
-                    Some(self.parse_assoc_expr_with(op.precedence() + 1,
-                                                    LhsExpr::NotYetParsed)?)
+                    Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?)
                 } else {
                     None
                 };
@@ -3636,28 +3465,18 @@ impl<'a> Parser<'a> {
                 break
             }
 
-            let rhs = match op.fixity() {
-                Fixity::Right => self.with_res(
-                    restrictions - Restrictions::STMT_EXPR,
-                    |this| {
-                        this.parse_assoc_expr_with(op.precedence(),
-                            LhsExpr::NotYetParsed)
-                }),
-                Fixity::Left => self.with_res(
-                    restrictions - Restrictions::STMT_EXPR,
-                    |this| {
-                        this.parse_assoc_expr_with(op.precedence() + 1,
-                            LhsExpr::NotYetParsed)
-                }),
+            let fixity = op.fixity();
+            let prec_adjustment = match fixity {
+                Fixity::Right => 0,
+                Fixity::Left => 1,
                 // We currently have no non-associative operators that are not handled above by
                 // the special cases. The code is here only for future convenience.
-                Fixity::None => self.with_res(
-                    restrictions - Restrictions::STMT_EXPR,
-                    |this| {
-                        this.parse_assoc_expr_with(op.precedence() + 1,
-                            LhsExpr::NotYetParsed)
-                }),
-            }?;
+                Fixity::None => 1,
+            };
+            let rhs = self.with_res(
+                restrictions - Restrictions::STMT_EXPR,
+                |this| this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed)
+            )?;
 
             // Make sure that the span of the parent node is larger than the span of lhs and rhs,
             // including the attributes.
@@ -3678,8 +3497,7 @@ impl<'a> Parser<'a> {
                     let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
                     self.mk_expr(span, binary, ThinVec::new())
                 }
-                AssocOp::Assign =>
-                    self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
+                AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
                 AssocOp::ObsoleteInPlace =>
                     self.mk_expr(span, ExprKind::ObsoleteInPlace(lhs, rhs), ThinVec::new()),
                 AssocOp::AssignOp(k) => {
@@ -3703,63 +3521,11 @@ impl<'a> Parser<'a> {
                 }
             };
 
-            if op.fixity() == Fixity::None { break }
+            if let Fixity::None = fixity { break }
         }
         Ok(lhs)
     }
 
-    fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
-        self.token.is_ident() &&
-            if let ast::ExprKind::Path(..) = node { true } else { false } &&
-            !self.token.is_reserved_ident() &&           // v `foo:bar(baz)`
-            self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) ||
-            self.look_ahead(1, |t| t == &token::Lt) &&     // `foo:bar<baz`
-            self.look_ahead(2, |t| t.is_ident()) ||
-            self.look_ahead(1, |t| t == &token::Colon) &&  // `foo:bar:baz`
-            self.look_ahead(2, |t| t.is_ident()) ||
-            self.look_ahead(1, |t| t == &token::ModSep) &&  // `foo:bar::baz`
-            self.look_ahead(2, |t| t.is_ident())
-    }
-
-    fn bad_type_ascription(
-        &self,
-        err: &mut DiagnosticBuilder<'a>,
-        lhs_span: Span,
-        cur_op_span: Span,
-        next_sp: Span,
-        maybe_path: bool,
-    ) {
-        err.span_label(self.span, "expecting a type here because of type ascription");
-        let cm = self.sess.source_map();
-        let next_pos = cm.lookup_char_pos(next_sp.lo());
-        let op_pos = cm.lookup_char_pos(cur_op_span.hi());
-        if op_pos.line != next_pos.line {
-            err.span_suggestion(
-                cur_op_span,
-                "try using a semicolon",
-                ";".to_string(),
-                Applicability::MaybeIncorrect,
-            );
-        } else {
-            if maybe_path {
-                err.span_suggestion(
-                    cur_op_span,
-                    "maybe you meant to write a path separator here",
-                    "::".to_string(),
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                err.note("type ascription is a nightly-only feature that lets \
-                          you annotate an expression with a type: `<expr>: <type>`");
-                err.span_note(
-                    lhs_span,
-                    "this expression expects an ascribed type after the colon",
-                );
-                err.help("this might be indicative of a syntax error elsewhere");
-            }
-        }
-    }
-
     fn parse_assoc_op_cast(&mut self, lhs: P<Expr>, lhs_span: Span,
                            expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind)
                            -> PResult<'a, P<Expr>> {
@@ -3840,7 +3606,7 @@ impl<'a> Parser<'a> {
     /// Produce an error if comparison operators are chained (RFC #558).
     /// We only need to check lhs, not rhs, because all comparison ops
     /// have same precedence and are left-associative
-    fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) {
+    fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
         debug_assert!(outer_op.is_comparison(),
                       "check_no_chained_comparison: {:?} is not comparison",
                       outer_op);
@@ -4179,8 +3945,6 @@ impl<'a> Parser<'a> {
     }
 
     crate fn parse_arm(&mut self) -> PResult<'a, Arm> {
-        maybe_whole!(self, NtArm, |x| x);
-
         let attrs = self.parse_outer_attributes()?;
         let pats = self.parse_pats()?;
         let guard = if self.eat_keyword(keywords::If) {
@@ -5043,92 +4807,6 @@ impl<'a> Parser<'a> {
         Ok(self.parse_stmt_(true))
     }
 
-    // Eat tokens until we can be relatively sure we reached the end of the
-    // statement. This is something of a best-effort heuristic.
-    //
-    // We terminate when we find an unmatched `}` (without consuming it).
-    fn recover_stmt(&mut self) {
-        self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
-    }
-
-    // If `break_on_semi` is `Break`, then we will stop consuming tokens after
-    // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is
-    // approximate - it can mean we break too early due to macros, but that
-    // should only lead to sub-optimal recovery, not inaccurate parsing).
-    //
-    // If `break_on_block` is `Break`, then we will stop consuming tokens
-    // after finding (and consuming) a brace-delimited block.
-    fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) {
-        let mut brace_depth = 0;
-        let mut bracket_depth = 0;
-        let mut in_block = false;
-        debug!("recover_stmt_ enter loop (semi={:?}, block={:?})",
-               break_on_semi, break_on_block);
-        loop {
-            debug!("recover_stmt_ loop {:?}", self.token);
-            match self.token {
-                token::OpenDelim(token::DelimToken::Brace) => {
-                    brace_depth += 1;
-                    self.bump();
-                    if break_on_block == BlockMode::Break &&
-                       brace_depth == 1 &&
-                       bracket_depth == 0 {
-                        in_block = true;
-                    }
-                }
-                token::OpenDelim(token::DelimToken::Bracket) => {
-                    bracket_depth += 1;
-                    self.bump();
-                }
-                token::CloseDelim(token::DelimToken::Brace) => {
-                    if brace_depth == 0 {
-                        debug!("recover_stmt_ return - close delim {:?}", self.token);
-                        break;
-                    }
-                    brace_depth -= 1;
-                    self.bump();
-                    if in_block && bracket_depth == 0 && brace_depth == 0 {
-                        debug!("recover_stmt_ return - block end {:?}", self.token);
-                        break;
-                    }
-                }
-                token::CloseDelim(token::DelimToken::Bracket) => {
-                    bracket_depth -= 1;
-                    if bracket_depth < 0 {
-                        bracket_depth = 0;
-                    }
-                    self.bump();
-                }
-                token::Eof => {
-                    debug!("recover_stmt_ return - Eof");
-                    break;
-                }
-                token::Semi => {
-                    self.bump();
-                    if break_on_semi == SemiColonMode::Break &&
-                       brace_depth == 0 &&
-                       bracket_depth == 0 {
-                        debug!("recover_stmt_ return - Semi");
-                        break;
-                    }
-                }
-                token::Comma => {
-                    if break_on_semi == SemiColonMode::Comma &&
-                       brace_depth == 0 &&
-                       bracket_depth == 0 {
-                        debug!("recover_stmt_ return - Semi");
-                        break;
-                    } else {
-                        self.bump();
-                    }
-                }
-                _ => {
-                    self.bump()
-                }
-            }
-        }
-    }
-
     fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option<Stmt> {
         self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| {
             e.emit();
@@ -5137,7 +4815,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn is_async_block(&mut self) -> bool {
+    fn is_async_block(&self) -> bool {
         self.token.is_keyword(keywords::Async) &&
         (
             ( // `async move {`
@@ -5149,19 +4827,19 @@ impl<'a> Parser<'a> {
         )
     }
 
-    fn is_async_fn(&mut self) -> bool {
+    fn is_async_fn(&self) -> bool {
         self.token.is_keyword(keywords::Async) &&
             self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
     }
 
-    fn is_do_catch_block(&mut self) -> bool {
+    fn is_do_catch_block(&self) -> bool {
         self.token.is_keyword(keywords::Do) &&
         self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
         self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
         !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
     }
 
-    fn is_try_block(&mut self) -> bool {
+    fn is_try_block(&self) -> bool {
         self.token.is_keyword(keywords::Try) &&
         self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
         self.span.rust_2018() &&
@@ -5183,7 +4861,7 @@ impl<'a> Parser<'a> {
         self.look_ahead(1, |t| t.is_keyword(keywords::Type))
     }
 
-    fn is_auto_trait_item(&mut self) -> bool {
+    fn is_auto_trait_item(&self) -> bool {
         // auto trait
         (self.token.is_keyword(keywords::Auto)
             && self.look_ahead(1, |t| t.is_keyword(keywords::Trait)))
@@ -5225,7 +4903,7 @@ impl<'a> Parser<'a> {
 
                 (ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
             }
-            token::Ident(ident, _) if ident.name == "macro_rules" &&
+            token::Ident(ident, _) if ident.name == sym::macro_rules &&
                                    self.look_ahead(1, |t| *t == token::Not) => {
                 let prev_span = self.prev_span;
                 self.complain_if_pub_macro(&vis.node, prev_span);
@@ -5445,7 +5123,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Checks if this expression is a successfully parsed statement.
-    fn expr_is_complete(&mut self, e: &Expr) -> bool {
+    fn expr_is_complete(&self, e: &Expr) -> bool {
         self.restrictions.contains(Restrictions::STMT_EXPR) &&
             !classify::expr_requires_semi_to_be_stmt(e)
     }
@@ -5915,8 +5593,6 @@ impl<'a> Parser<'a> {
     ///                  | ( < lifetimes , typaramseq ( , )? > )
     /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
     fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
-        maybe_whole!(self, NtGenerics, |x| x);
-
         let span_lo = self.span;
         if self.eat_lt() {
             let params = self.parse_generic_params()?;
@@ -6169,8 +5845,6 @@ impl<'a> Parser<'a> {
     /// where T : Trait<U, V> + 'b, 'a : 'b
     /// ```
     fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
-        maybe_whole!(self, NtWhereClause, |x| x);
-
         let mut where_clause = WhereClause {
             id: ast::DUMMY_NODE_ID,
             predicates: Vec::new(),
@@ -6517,7 +6191,7 @@ impl<'a> Parser<'a> {
         Ok((id, generics))
     }
 
-    fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility,
+    fn mk_item(&self, span: Span, ident: Ident, node: ItemKind, vis: Visibility,
                attrs: Vec<Attribute>) -> P<Item> {
         P(Item {
             ident,
@@ -6549,7 +6223,7 @@ 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(&mut self) -> bool {
+    fn is_const_item(&self) -> bool {
         self.token.is_keyword(keywords::Const) &&
             !self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) &&
             !self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe))
@@ -6657,7 +6331,7 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn complain_if_pub_macro(&mut self, vis: &VisibilityKind, sp: Span) {
+    fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) {
         match *vis {
             VisibilityKind::Inherited => {}
             _ => {
@@ -6686,7 +6360,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span)
+    fn missing_assoc_item_kind_err(&self, item_type: &str, prev_span: Span)
                                    -> DiagnosticBuilder<'a>
     {
         let expected_kinds = if item_type == "extern" {
@@ -7036,26 +6710,6 @@ impl<'a> Parser<'a> {
         Ok((class_name, ItemKind::Union(vdata, generics), None))
     }
 
-    fn consume_block(&mut self, delim: token::DelimToken) {
-        let mut brace_depth = 0;
-        loop {
-            if self.eat(&token::OpenDelim(delim)) {
-                brace_depth += 1;
-            } else if self.eat(&token::CloseDelim(delim)) {
-                if brace_depth == 0 {
-                    return;
-                } else {
-                    brace_depth -= 1;
-                    continue;
-                }
-            } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) {
-                return;
-            } else {
-                self.bump();
-            }
-        }
-    }
-
     fn parse_record_struct_body(
         &mut self,
     ) -> PResult<'a, (Vec<StructField>, /* recovered */ bool)> {
@@ -7357,7 +7011,8 @@ impl<'a> Parser<'a> {
                     let attr = Attribute {
                         id: attr::mk_attr_id(),
                         style: ast::AttrStyle::Outer,
-                        path: ast::Path::from_ident(Ident::from_str("warn_directory_ownership")),
+                        path: ast::Path::from_ident(
+                            Ident::with_empty_ctxt(sym::warn_directory_ownership)),
                         tokens: TokenStream::empty(),
                         is_sugared_doc: false,
                         span: syntax_pos::DUMMY_SP,
@@ -7389,7 +7044,7 @@ impl<'a> Parser<'a> {
     }
 
     fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
-        if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") {
+        if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) {
             self.directory.path.to_mut().push(&path.as_str());
             self.directory.ownership = DirectoryOwnership::Owned { relative: None };
         } else {
@@ -7409,7 +7064,7 @@ impl<'a> Parser<'a> {
     }
 
     pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
-        if let Some(s) = attr::first_attr_value_str_by_name(attrs, "path") {
+        if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) {
             let s = s.as_str();
 
             // On windows, the base path might have the form
@@ -8753,21 +8408,6 @@ impl<'a> Parser<'a> {
         ).emit();
     }
 
-    /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid.
-    fn eat_bad_pub(&mut self) {
-        if self.token.is_keyword(keywords::Pub) {
-            match self.parse_visibility(false) {
-                Ok(vis) => {
-                    let mut err = self.diagnostic()
-                        .struct_span_err(vis.span, "unnecessary visibility qualifier");
-                    err.span_label(vis.span, "`pub` not permitted here");
-                    err.emit();
-                }
-                Err(mut err) => err.emit(),
-            }
-        }
-    }
-
     /// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
     /// into the generated closure so that they are dropped when the future is polled and not when
     /// it is created.
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index fd7a39c576d..068fc41c87a 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -19,7 +19,7 @@ use log::info;
 use std::fmt;
 use std::mem;
 #[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert;
+use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::Lrc;
 
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
@@ -61,6 +61,7 @@ impl DelimToken {
 
 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum Lit {
+    Bool(ast::Name), // AST only, must never appear in a `Token`
     Byte(ast::Name),
     Char(ast::Name),
     Err(ast::Name),
@@ -72,9 +73,13 @@ pub enum Lit {
     ByteStrRaw(ast::Name, u16), /* raw byte str delimited by n hash symbols */
 }
 
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(Lit, 8);
+
 impl Lit {
     crate fn literal_name(&self) -> &'static str {
         match *self {
+            Bool(_) => panic!("literal token contains `Lit::Bool`"),
             Byte(_) => "byte literal",
             Char(_) => "char literal",
             Err(_) => "invalid literal",
@@ -85,6 +90,13 @@ impl Lit {
         }
     }
 
+    crate fn may_have_suffix(&self) -> bool {
+        match *self {
+            Integer(..) | Float(..) => true,
+            _ => false,
+        }
+    }
+
     // See comments in `Nonterminal::to_tokenstream` for why we care about
     // *probably* equal here rather than actual equality
     fn probably_equal_for_proc_macro(&self, other: &Lit) -> bool {
@@ -208,7 +220,7 @@ pub enum Token {
 
 // `Token` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::<Token>() == 16);
+static_assert_size!(Token, 16);
 
 impl Token {
     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
@@ -585,14 +597,12 @@ pub enum Nonterminal {
     NtPath(ast::Path),
     NtVis(ast::Visibility),
     NtTT(TokenTree),
-    // These are not exposed to macros, but are used by quasiquote.
-    NtArm(ast::Arm),
-    NtImplItem(ast::ImplItem),
+    // 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),
     NtForeignItem(ast::ForeignItem),
-    NtGenerics(ast::Generics),
-    NtWhereClause(ast::WhereClause),
-    NtArg(ast::Arg),
 }
 
 impl PartialEq for Nonterminal {
@@ -625,13 +635,9 @@ impl fmt::Debug for Nonterminal {
             NtMeta(..) => f.pad("NtMeta(..)"),
             NtPath(..) => f.pad("NtPath(..)"),
             NtTT(..) => f.pad("NtTT(..)"),
-            NtArm(..) => f.pad("NtArm(..)"),
             NtImplItem(..) => f.pad("NtImplItem(..)"),
             NtTraitItem(..) => f.pad("NtTraitItem(..)"),
             NtForeignItem(..) => f.pad("NtForeignItem(..)"),
-            NtGenerics(..) => f.pad("NtGenerics(..)"),
-            NtWhereClause(..) => f.pad("NtWhereClause(..)"),
-            NtArg(..) => f.pad("NtArg(..)"),
             NtVis(..) => f.pad("NtVis(..)"),
             NtLifetime(..) => f.pad("NtLifetime(..)"),
         }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 682621d40ab..cd86d94f4b8 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -13,17 +13,15 @@ use crate::print::pp::{self, Breaks};
 use crate::print::pp::Breaks::{Consistent, Inconsistent};
 use crate::ptr::P;
 use crate::std_inject;
-use crate::symbol::keywords;
+use crate::symbol::{keywords, sym};
 use crate::tokenstream::{self, TokenStream, TokenTree};
 
 use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{self, BytePos};
 use syntax_pos::{DUMMY_SP, FileName};
 
-use std::ascii;
 use std::borrow::Cow;
 use std::io::{self, Write, Read};
-use std::iter::Peekable;
 use std::vec;
 
 pub enum AnnNode<'a> {
@@ -49,8 +47,7 @@ impl PpAnn for NoAnn {}
 pub struct State<'a> {
     pub s: pp::Printer<'a>,
     cm: Option<&'a SourceMap>,
-    comments: Option<Vec<comments::Comment> >,
-    literals: Peekable<vec::IntoIter<comments::Literal>>,
+    comments: Option<Vec<comments::Comment>>,
     cur_cmnt: usize,
     boxes: Vec<pp::Breaks>,
     ann: &'a (dyn PpAnn+'a),
@@ -62,7 +59,6 @@ fn rust_printer<'a>(writer: Box<dyn Write+'a>, ann: &'a dyn PpAnn) -> State<'a>
         s: pp::mk_printer(writer, DEFAULT_COLUMNS),
         cm: None,
         comments: None,
-        literals: vec![].into_iter().peekable(),
         cur_cmnt: 0,
         boxes: Vec::new(),
         ann,
@@ -75,8 +71,7 @@ pub const INDENT_UNIT: usize = 4;
 pub const DEFAULT_COLUMNS: usize = 78;
 
 /// Requires you to pass an input filename and reader so that
-/// it can scan the input text for comments and literals to
-/// copy forward.
+/// it can scan the input text for comments to copy forward.
 pub fn print_crate<'a>(cm: &'a SourceMap,
                        sess: &ParseSess,
                        krate: &ast::Crate,
@@ -94,13 +89,14 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
         // of the feature gate, so we fake them up here.
 
         // #![feature(prelude_import)]
-        let pi_nested = attr::mk_nested_word_item(ast::Ident::from_str("prelude_import"));
-        let list = attr::mk_list_item(DUMMY_SP, ast::Ident::from_str("feature"), vec![pi_nested]);
+        let pi_nested = attr::mk_nested_word_item(ast::Ident::with_empty_ctxt(sym::prelude_import));
+        let list = attr::mk_list_item(
+            DUMMY_SP, ast::Ident::with_empty_ctxt(sym::feature), vec![pi_nested]);
         let fake_attr = attr::mk_attr_inner(DUMMY_SP, attr::mk_attr_id(), list);
         s.print_attribute(&fake_attr)?;
 
         // #![no_std]
-        let no_std_meta = attr::mk_word_item(ast::Ident::from_str("no_std"));
+        let no_std_meta = attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::no_std));
         let fake_attr = attr::mk_attr_inner(DUMMY_SP, attr::mk_attr_id(), no_std_meta);
         s.print_attribute(&fake_attr)?;
     }
@@ -118,36 +114,23 @@ impl<'a> State<'a> {
                           out: Box<dyn Write+'a>,
                           ann: &'a dyn PpAnn,
                           is_expanded: bool) -> State<'a> {
-        let (cmnts, lits) = comments::gather_comments_and_literals(sess, filename, input);
-
-        State::new(
-            cm,
-            out,
-            ann,
-            Some(cmnts),
-            // If the code is post expansion, don't use the table of
-            // literals, since it doesn't correspond with the literals
-            // in the AST anymore.
-            if is_expanded { None } else { Some(lits) },
-            is_expanded
-        )
+        let comments = comments::gather_comments(sess, filename, input);
+        State::new(cm, out, ann, Some(comments), is_expanded)
     }
 
     pub fn new(cm: &'a SourceMap,
                out: Box<dyn Write+'a>,
                ann: &'a dyn PpAnn,
                comments: Option<Vec<comments::Comment>>,
-               literals: Option<Vec<comments::Literal>>,
                is_expanded: bool) -> State<'a> {
         State {
             s: pp::mk_printer(out, DEFAULT_COLUMNS),
             cm: Some(cm),
             comments,
-            literals: literals.unwrap_or_default().into_iter().peekable(),
             cur_cmnt: 0,
             boxes: Vec::new(),
             ann,
-            is_expanded: is_expanded
+            is_expanded,
         }
     }
 }
@@ -180,6 +163,31 @@ fn binop_to_string(op: BinOpToken) -> &'static str {
     }
 }
 
+pub fn literal_to_string(lit: token::Lit, suffix: Option<ast::Name>) -> String {
+    let mut out = match lit {
+        token::Byte(b)           => format!("b'{}'", b),
+        token::Char(c)           => format!("'{}'", c),
+        token::Err(c)            => format!("'{}'", c),
+        token::Bool(c)           |
+        token::Float(c)          |
+        token::Integer(c)        => c.to_string(),
+        token::Str_(s)           => format!("\"{}\"", s),
+        token::StrRaw(s, n)      => format!("r{delim}\"{string}\"{delim}",
+                                            delim="#".repeat(n as usize),
+                                            string=s),
+        token::ByteStr(v)        => format!("b\"{}\"", v),
+        token::ByteStrRaw(s, n)  => format!("br{delim}\"{string}\"{delim}",
+                                            delim="#".repeat(n as usize),
+                                            string=s),
+    };
+
+    if let Some(suffix) = suffix {
+        out.push_str(&suffix.as_str())
+    }
+
+    out
+}
+
 pub fn token_to_string(tok: &Token) -> String {
     match *tok {
         token::Eq                   => "=".to_string(),
@@ -223,29 +231,7 @@ pub fn token_to_string(tok: &Token) -> String {
         token::SingleQuote          => "'".to_string(),
 
         /* Literals */
-        token::Literal(lit, suf) => {
-            let mut out = match lit {
-                token::Byte(b)           => format!("b'{}'", b),
-                token::Char(c)           => format!("'{}'", c),
-                token::Err(c)            => format!("'{}'", c),
-                token::Float(c)          |
-                token::Integer(c)        => c.to_string(),
-                token::Str_(s)           => format!("\"{}\"", s),
-                token::StrRaw(s, n)      => format!("r{delim}\"{string}\"{delim}",
-                                                    delim="#".repeat(n as usize),
-                                                    string=s),
-                token::ByteStr(v)         => format!("b\"{}\"", v),
-                token::ByteStrRaw(s, n)   => format!("br{delim}\"{string}\"{delim}",
-                                                    delim="#".repeat(n as usize),
-                                                    string=s),
-            };
-
-            if let Some(s) = suf {
-                out.push_str(&s.as_str())
-            }
-
-            out
-        }
+        token::Literal(lit, suf) => literal_to_string(lit, suf),
 
         /* Name components */
         token::Ident(s, false)      => s.to_string(),
@@ -278,12 +264,8 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
         token::NtLifetime(e)        => ident_to_string(e),
         token::NtLiteral(ref e)     => expr_to_string(e),
         token::NtTT(ref tree)       => tt_to_string(tree.clone()),
-        token::NtArm(ref e)         => arm_to_string(e),
         token::NtImplItem(ref e)    => impl_item_to_string(e),
         token::NtTraitItem(ref e)   => trait_item_to_string(e),
-        token::NtGenerics(ref e)    => generic_params_to_string(&e.params),
-        token::NtWhereClause(ref e) => where_clause_to_string(e),
-        token::NtArg(ref e)         => arg_to_string(e),
         token::NtVis(ref e)         => vis_to_string(e),
         token::NtForeignItem(ref e) => foreign_item_to_string(e),
     }
@@ -438,8 +420,6 @@ pub trait PrintState<'a> {
     fn boxes(&mut self) -> &mut Vec<pp::Breaks>;
     fn comments(&mut self) -> &mut Option<Vec<comments::Comment>>;
     fn cur_cmnt(&mut self) -> &mut usize;
-    fn cur_lit(&mut self) -> Option<&comments::Literal>;
-    fn bump_lit(&mut self) -> Option<comments::Literal>;
 
     fn word_space<S: Into<Cow<'static, str>>>(&mut self, w: S) -> io::Result<()> {
         self.writer().word(w)?;
@@ -504,21 +484,6 @@ pub trait PrintState<'a> {
         self.end()
     }
 
-    fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
-        while let Some(ltrl) = self.cur_lit().cloned() {
-            if ltrl.pos > pos { break; }
-
-            // we don't need the value here since we're forced to clone cur_lit
-            // due to lack of NLL.
-            self.bump_lit();
-            if ltrl.pos == pos {
-                return Some(ltrl);
-            }
-        }
-
-        None
-    }
-
     fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
         while let Some(ref cmnt) = self.next_comment() {
             if cmnt.pos < pos {
@@ -606,60 +571,7 @@ pub trait PrintState<'a> {
 
     fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
         self.maybe_print_comment(lit.span.lo())?;
-        if let Some(ltrl) = self.next_lit(lit.span.lo()) {
-            return self.writer().word(ltrl.lit.clone());
-        }
-        match lit.node {
-            ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style),
-            ast::LitKind::Err(st) => {
-                let st = st.as_str().escape_debug().to_string();
-                let mut res = String::with_capacity(st.len() + 2);
-                res.push('\'');
-                res.push_str(&st);
-                res.push('\'');
-                self.writer().word(res)
-            }
-            ast::LitKind::Byte(byte) => {
-                let mut res = String::from("b'");
-                res.extend(ascii::escape_default(byte).map(|c| c as char));
-                res.push('\'');
-                self.writer().word(res)
-            }
-            ast::LitKind::Char(ch) => {
-                let mut res = String::from("'");
-                res.extend(ch.escape_default());
-                res.push('\'');
-                self.writer().word(res)
-            }
-            ast::LitKind::Int(i, t) => {
-                match t {
-                    ast::LitIntType::Signed(st) => {
-                        self.writer().word(st.val_to_string(i as i128))
-                    }
-                    ast::LitIntType::Unsigned(ut) => {
-                        self.writer().word(ut.val_to_string(i))
-                    }
-                    ast::LitIntType::Unsuffixed => {
-                        self.writer().word(i.to_string())
-                    }
-                }
-            }
-            ast::LitKind::Float(ref f, t) => {
-                self.writer().word(format!("{}{}", &f, t.ty_to_string()))
-            }
-            ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(f.as_str().to_string()),
-            ast::LitKind::Bool(val) => {
-                if val { self.writer().word("true") } else { self.writer().word("false") }
-            }
-            ast::LitKind::ByteStr(ref v) => {
-                let mut escaped: String = String::new();
-                for &ch in v.iter() {
-                    escaped.extend(ascii::escape_default(ch)
-                                         .map(|c| c as char));
-                }
-                self.writer().word(format!("b\"{}\"", escaped))
-            }
-        }
+        self.writer().word(literal_to_string(lit.token, lit.suffix))
     }
 
     fn print_string(&mut self, st: &str,
@@ -880,14 +792,6 @@ impl<'a> PrintState<'a> for State<'a> {
     fn cur_cmnt(&mut self) -> &mut usize {
         &mut self.cur_cmnt
     }
-
-    fn cur_lit(&mut self) -> Option<&comments::Literal> {
-        self.literals.peek()
-    }
-
-    fn bump_lit(&mut self) -> Option<comments::Literal> {
-        self.literals.next()
-    }
 }
 
 impl<'a> State<'a> {
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index b9758bd655c..1be7986ad53 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -2,7 +2,7 @@ use crate::ast;
 use crate::attr;
 use crate::edition::Edition;
 use crate::ext::hygiene::{Mark, SyntaxContext};
-use crate::symbol::{Symbol, keywords};
+use crate::symbol::{Ident, Symbol, keywords, sym};
 use crate::source_map::{ExpnInfo, MacroAttribute, dummy_spanned, hygiene, respan};
 use crate::ptr::P;
 use crate::tokenstream::TokenStream;
@@ -35,6 +35,9 @@ pub fn injected_crate_name() -> Option<&'static str> {
 }
 
 thread_local! {
+    // A `Symbol` might make more sense here, but it doesn't work, probably for
+    // reasons relating to the use of thread-local storage for the Symbol
+    // interner.
     static INJECTED_CRATE_NAME: Cell<Option<&'static str>> = Cell::new(None);
 }
 
@@ -46,10 +49,10 @@ pub fn maybe_inject_crates_ref(
     let rust_2018 = edition >= Edition::Edition2018;
 
     // the first name in this list is the crate name of the crate with the prelude
-    let names: &[&str] = if attr::contains_name(&krate.attrs, "no_core") {
+    let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) {
         return krate;
-    } else if attr::contains_name(&krate.attrs, "no_std") {
-        if attr::contains_name(&krate.attrs, "compiler_builtins") {
+    } else if attr::contains_name(&krate.attrs, sym::no_std) {
+        if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
             &["core"]
         } else {
             &["core", "compiler_builtins"]
@@ -60,26 +63,25 @@ pub fn maybe_inject_crates_ref(
 
     // .rev() to preserve ordering above in combination with insert(0, ...)
     let alt_std_name = alt_std_name.map(Symbol::intern);
-    for orig_name in names.iter().rev() {
-        let orig_name = Symbol::intern(orig_name);
-        let mut rename = orig_name;
+    for orig_name_str in names.iter().rev() {
         // HACK(eddyb) gensym the injected crates on the Rust 2018 edition,
         // so they don't accidentally interfere with the new import paths.
-        if rust_2018 {
-            rename = orig_name.gensymed();
-        }
-        let orig_name = if rename != orig_name {
-            Some(orig_name)
+        let orig_name_sym = Symbol::intern(orig_name_str);
+        let orig_name_ident = Ident::with_empty_ctxt(orig_name_sym);
+        let (rename, orig_name) = if rust_2018 {
+            (orig_name_ident.gensym(), Some(orig_name_sym))
         } else {
-            None
+            (orig_name_ident, None)
         };
         krate.module.items.insert(0, P(ast::Item {
-            attrs: vec![attr::mk_attr_outer(DUMMY_SP,
-                                            attr::mk_attr_id(),
-                                            attr::mk_word_item(ast::Ident::from_str("macro_use")))],
+            attrs: vec![attr::mk_attr_outer(
+                DUMMY_SP,
+                attr::mk_attr_id(),
+                attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::macro_use))
+            )],
             vis: dummy_spanned(ast::VisibilityKind::Inherited),
             node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)),
-            ident: ast::Ident::with_empty_ctxt(rename),
+            ident: rename,
             id: ast::DUMMY_NODE_ID,
             span: DUMMY_SP,
             tokens: None,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 03d0eff266e..3dc7aad9459 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -29,7 +29,7 @@ use crate::parse::{token, ParseSess};
 use crate::print::pprust;
 use crate::ast::{self, Ident};
 use crate::ptr::P;
-use crate::symbol::{self, Symbol, keywords};
+use crate::symbol::{self, Symbol, keywords, sym};
 use crate::ThinVec;
 
 struct Test {
@@ -65,8 +65,7 @@ pub fn modify_for_testing(sess: &ParseSess,
     // unconditional, so that the attribute is still marked as used in
     // non-test builds.
     let reexport_test_harness_main =
-        attr::first_attr_value_str_by_name(&krate.attrs,
-                                           "reexport_test_harness_main");
+        attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
 
     // Do this here so that the test_runner crate attribute gets marked as used
     // even in non-test builds
@@ -172,7 +171,7 @@ impl MutVisitor for EntryPointCleaner {
             EntryPointType::MainAttr |
             EntryPointType::Start =>
                 item.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| {
-                    let allow_ident = Ident::from_str("allow");
+                    let allow_ident = Ident::with_empty_ctxt(sym::allow);
                     let dc_nested = attr::mk_nested_word_item(Ident::from_str("dead_code"));
                     let allow_dead_code_item = attr::mk_list_item(DUMMY_SP, allow_ident,
                                                                   vec![dc_nested]);
@@ -185,7 +184,7 @@ impl MutVisitor for EntryPointCleaner {
                         ident,
                         attrs: attrs.into_iter()
                             .filter(|attr| {
-                                !attr.check_name("main") && !attr.check_name("start")
+                                !attr.check_name(sym::main) && !attr.check_name(sym::start)
                             })
                             .chain(iter::once(allow_dead_code))
                             .collect(),
@@ -216,7 +215,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
                    tests: Vec<Ident>,
                    tested_submods: Vec<(Ident, Ident)>)
                    -> (P<ast::Item>, Ident) {
-    let super_ = Ident::from_str("super");
+    let super_ = Ident::with_empty_ctxt(keywords::Super.name());
 
     let items = tests.into_iter().map(|r| {
         cx.ext_cx.item_use_simple(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public),
@@ -233,11 +232,11 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
         items,
     };
 
-    let sym = Ident::with_empty_ctxt(Symbol::gensym("__test_reexports"));
+    let name = Ident::from_str("__test_reexports").gensym();
     let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
     cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
     let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item {
-        ident: sym,
+        ident: name,
         attrs: Vec::new(),
         id: ast::DUMMY_NODE_ID,
         node: ast::ItemKind::Mod(reexport_mod),
@@ -246,7 +245,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
         tokens: None,
     })).pop().unwrap();
 
-    (it, sym)
+    (it, name)
 }
 
 /// Crawl over the crate, inserting test reexports and the test main function
@@ -273,7 +272,8 @@ fn generate_test_harness(sess: &ParseSess,
         test_cases: Vec::new(),
         reexport_test_harness_main,
         // N.B., doesn't consider the value of `--crate-name` passed on the command line.
-        is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false),
+        is_libtest: attr::find_crate_name(&krate.attrs)
+            .map(|s| s == sym::test).unwrap_or(false),
         toplevel_reexport: None,
         ctxt: SyntaxContext::empty().apply_mark(mark),
         features,
@@ -373,9 +373,10 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
                            main_body);
 
     // Honor the reexport_test_harness_main attribute
-    let main_id = Ident::new(
-        cx.reexport_test_harness_main.unwrap_or(Symbol::gensym("main")),
-        sp);
+    let main_id = match cx.reexport_test_harness_main {
+        Some(sym) => Ident::new(sym, sp),
+        None => Ident::from_str_and_span("main", sp).gensym(),
+    };
 
     P(ast::Item {
         ident: main_id,
@@ -428,11 +429,11 @@ fn visible_path(cx: &TestCtxt<'_>, path: &[Ident]) -> Vec<Ident>{
 }
 
 fn is_test_case(i: &ast::Item) -> bool {
-    attr::contains_name(&i.attrs, "rustc_test_marker")
+    attr::contains_name(&i.attrs, sym::rustc_test_marker)
 }
 
 fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
-    let test_attr = attr::find_by_name(&krate.attrs, "test_runner")?;
+    let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
     test_attr.meta_item_list().map(|meta_list| {
         if meta_list.len() != 1 {
             sd.span_fatal(test_attr.span,
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 93b5ecadd14..3cb16c30a50 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -21,7 +21,7 @@ use crate::print::pprust;
 
 use syntax_pos::{BytePos, Mark, Span, DUMMY_SP};
 #[cfg(target_arch = "x86_64")]
-use rustc_data_structures::static_assert;
+use rustc_data_structures::static_assert_size;
 use rustc_data_structures::sync::Lrc;
 use serialize::{Decoder, Decodable, Encoder, Encodable};
 use smallvec::{SmallVec, smallvec};
@@ -158,7 +158,7 @@ pub type TreeAndJoint = (TokenTree, IsJoint);
 
 // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 8);
+static_assert_size!(TokenStream, 8);
 
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum IsJoint {
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 8edd0e1ae38..b8e89c3ecf8 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -11,7 +11,7 @@ use syntax::ext::base::{self, *};
 use syntax::feature_gate;
 use syntax::parse::{self, token};
 use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::ast::AsmDialect;
 use syntax_pos::Span;
 use syntax::tokenstream;
@@ -39,7 +39,7 @@ impl State {
     }
 }
 
-const OPTIONS: &[&str] = &["volatile", "alignstack", "intel"];
+const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel];
 
 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
                        sp: Span,
@@ -47,7 +47,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
                        -> Box<dyn base::MacResult + 'cx> {
     if !cx.ecfg.enable_asm() {
         feature_gate::emit_feature_err(&cx.parse_sess,
-                                       "asm",
+                                       sym::asm,
                                        sp,
                                        feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_ASM);
@@ -233,13 +233,13 @@ fn parse_inline_asm<'a>(
             Options => {
                 let (option, _) = p.parse_str()?;
 
-                if option == "volatile" {
+                if option == sym::volatile {
                     // Indicates that the inline assembly has side effects
                     // and must not be optimized out along with its outputs.
                     volatile = true;
-                } else if option == "alignstack" {
+                } else if option == sym::alignstack {
                     alignstack = true;
-                } else if option == "intel" {
+                } else if option == sym::intel {
                     dialect = AsmDialect::Intel;
                 } else {
                     cx.span_warn(p.prev_span, "unrecognized option");
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index 8c9eb4bf2d8..77c53f402cc 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -6,7 +6,7 @@ use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax_pos::Span;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::{Symbol, sym};
 use syntax::tokenstream::TokenTree;
 
 pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>,
@@ -15,7 +15,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>,
                               -> Box<dyn base::MacResult + 'cx> {
     if !cx.ecfg.enable_concat_idents() {
         feature_gate::emit_feature_err(&cx.parse_sess,
-                                       "concat_idents",
+                                       sym::concat_idents,
                                        sp,
                                        feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_CONCAT_IDENTS);
diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs
index b347092e1bc..1b0d572324a 100644
--- a/src/libsyntax_ext/deriving/clone.rs
+++ b/src/libsyntax_ext/deriving/clone.rs
@@ -7,7 +7,7 @@ use syntax::attr;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::ptr::P;
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::{Symbol, keywords, sym};
 use syntax_pos::Span;
 
 pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>,
@@ -37,7 +37,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>,
             match annitem.node {
                 ItemKind::Struct(_, Generics { ref params, .. }) |
                 ItemKind::Enum(_, Generics { ref params, .. }) => {
-                    if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") &&
+                    if attr::contains_name(&annitem.attrs, sym::rustc_copy_clone_marker) &&
                         !params.iter().any(|param| match param.kind {
                             ast::GenericParamKind::Type { .. } => true,
                             _ => false,
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index e5939e396e5..a13dc07085f 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -191,7 +191,7 @@ use syntax::ext::build::AstBuilder;
 use syntax::source_map::{self, respan};
 use syntax::util::map_in_place::MapInPlace;
 use syntax::ptr::P;
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::{Symbol, keywords, sym};
 use syntax::parse::ParseSess;
 use syntax_pos::{DUMMY_SP, Span};
 
@@ -426,7 +426,7 @@ impl<'a> TraitDef<'a> {
                     }
                 };
                 let is_always_copy =
-                    attr::contains_name(&item.attrs, "rustc_copy_clone_marker") &&
+                    attr::contains_name(&item.attrs, sym::rustc_copy_clone_marker) &&
                     has_no_type_params;
                 let use_temporaries = is_packed && is_always_copy;
 
@@ -464,8 +464,8 @@ impl<'a> TraitDef<'a> {
                 attrs.extend(item.attrs
                     .iter()
                     .filter(|a| {
-                        ["allow", "warn", "deny", "forbid", "stable", "unstable"]
-                            .contains(&a.name_or_empty().get())
+                        [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
+                            .contains(&a.name_or_empty())
                     })
                     .cloned());
                 push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() })))
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index fff54814a38..c27de692d88 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -6,7 +6,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
 use syntax::ext::build::AstBuilder;
 use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 
 macro path_local($x:ident) {
@@ -139,7 +139,7 @@ fn call_intrinsic(cx: &ExtCtxt<'_>,
     let intrinsic_allowed_via_allow_internal_unstable = cx
         .current_expansion.mark.expn_info().unwrap()
         .allow_internal_unstable.map_or(false, |features| features.iter().any(|&s|
-            s == "core_intrinsics"
+            s == sym::core_intrinsics
         ));
     if intrinsic_allowed_via_allow_internal_unstable {
         span = span.with_ctxt(cx.backtrace());
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
index ccff4aec2c8..2127179eecb 100644
--- a/src/libsyntax_ext/env.rs
+++ b/src/libsyntax_ext/env.rs
@@ -6,7 +6,7 @@
 use syntax::ast::{self, Ident, GenericArg};
 use syntax::ext::base::{self, *};
 use syntax::ext::build::AstBuilder;
-use syntax::symbol::{keywords, Symbol};
+use syntax::symbol::{keywords, Symbol, sym};
 use syntax_pos::Span;
 use syntax::tokenstream;
 
@@ -29,7 +29,8 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>,
                                      true,
                                      cx.std_path(&["option", "Option", "None"]),
                                      vec![GenericArg::Type(cx.ty_rptr(sp,
-                                                     cx.ty_ident(sp, Ident::from_str("str")),
+                                                     cx.ty_ident(sp,
+                                                                 Ident::with_empty_ctxt(sym::str)),
                                                      Some(lt),
                                                      ast::Mutability::Immutable))],
                                      vec![]))
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 24fbc9b6caf..9e54c0634b6 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -12,7 +12,7 @@ use syntax::ext::build::AstBuilder;
 use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::tokenstream;
 use syntax_pos::{MultiSpan, Span, DUMMY_SP};
 
@@ -711,12 +711,12 @@ pub fn expand_format_args_nl<'cx>(
     //if !ecx.ecfg.enable_allow_internal_unstable() {
 
     // For some reason, the only one that actually works for `println` is the first check
-    if !sp.allows_unstable("format_args_nl") // the span is marked as `#[allow_insternal_unsable]`
+    if !sp.allows_unstable(sym::format_args_nl) // the span is marked `#[allow_insternal_unsable]`
         && !ecx.ecfg.enable_allow_internal_unstable()  // NOTE: when is this enabled?
         && !ecx.ecfg.enable_format_args_nl()  // enabled using `#[feature(format_args_nl]`
     {
         feature_gate::emit_feature_err(&ecx.parse_sess,
-                                       "format_args_nl",
+                                       sym::format_args_nl,
                                        sp,
                                        feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_FORMAT_ARGS_NL);
diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs
index 2baf530aeda..3f2853e4b0e 100644
--- a/src/libsyntax_ext/global_asm.rs
+++ b/src/libsyntax_ext/global_asm.rs
@@ -16,12 +16,12 @@ use syntax::ext::base::{self, *};
 use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::ptr::P;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 use syntax::tokenstream;
 use smallvec::smallvec;
 
-pub const MACRO: &str = "global_asm";
+pub const MACRO: Symbol = sym::global_asm;
 
 pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
                               sp: Span,
diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs
index 658ce98d268..1be3990837c 100644
--- a/src/libsyntax_ext/log_syntax.rs
+++ b/src/libsyntax_ext/log_syntax.rs
@@ -2,6 +2,7 @@ use syntax::ext::base;
 use syntax::feature_gate;
 use syntax::print;
 use syntax::tokenstream;
+use syntax::symbol::sym;
 use syntax_pos;
 
 pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt<'_>,
@@ -10,7 +11,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt<'_>,
                               -> Box<dyn base::MacResult + 'cx> {
     if !cx.ecfg.enable_log_syntax() {
         feature_gate::emit_feature_err(&cx.parse_sess,
-                                       "log_syntax",
+                                       sym::log_syntax,
                                        sp,
                                        feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_LOG_SYNTAX);
diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs
index f0390ba3d40..200445d1248 100644
--- a/src/libsyntax_ext/proc_macro_decls.rs
+++ b/src/libsyntax_ext/proc_macro_decls.rs
@@ -13,12 +13,16 @@ use syntax::mut_visit::MutVisitor;
 use syntax::parse::ParseSess;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax::visit::{self, Visitor};
 
 use syntax_pos::{Span, DUMMY_SP};
 
-const PROC_MACRO_KINDS: [&str; 3] = ["proc_macro_derive", "proc_macro_attribute", "proc_macro"];
+const PROC_MACRO_KINDS: [Symbol; 3] = [
+    sym::proc_macro_derive,
+    sym::proc_macro_attribute,
+    sym::proc_macro
+];
 
 struct ProcMacroDerive {
     trait_name: ast::Name,
@@ -139,7 +143,7 @@ impl<'a> CollectProcMacros<'a> {
 
         let attributes_attr = list.get(1);
         let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
-            if !attr.check_name("attributes") {
+            if !attr.check_name(sym::attributes) {
                 self.handler.span_err(attr.span(), "second argument must be `attributes`")
             }
             attr.meta_item_list().unwrap_or_else(|| {
@@ -231,7 +235,7 @@ impl<'a> CollectProcMacros<'a> {
 impl<'a> Visitor<'a> for CollectProcMacros<'a> {
     fn visit_item(&mut self, item: &'a ast::Item) {
         if let ast::ItemKind::MacroDef(..) = item.node {
-            if self.is_proc_macro_crate && attr::contains_name(&item.attrs, "macro_export") {
+            if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
                 let msg =
                     "cannot export macro_rules! macros from a `proc-macro` crate type currently";
                 self.handler.span_err(item.span, msg);
@@ -304,11 +308,11 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
             return;
         }
 
-        if attr.check_name("proc_macro_derive") {
+        if attr.check_name(sym::proc_macro_derive) {
             self.collect_custom_derive(item, attr);
-        } else if attr.check_name("proc_macro_attribute") {
+        } else if attr.check_name(sym::proc_macro_attribute) {
             self.collect_attr_proc_macro(item);
-        } else if attr.check_name("proc_macro") {
+        } else if attr.check_name(sym::proc_macro) {
             self.collect_bang_proc_macro(item);
         };
 
@@ -324,6 +328,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
 
 // Creates a new module which looks like:
 //
+//      #[doc(hidden)]
 //      mod $gensym {
 //          extern crate proc_macro;
 //
@@ -357,7 +362,11 @@ fn mk_decls(
     });
     let span = DUMMY_SP.apply_mark(mark);
 
-    let proc_macro = Ident::from_str("proc_macro");
+    let hidden = cx.meta_list_item_word(span, sym::hidden);
+    let doc = cx.meta_list(span, sym::doc, vec![hidden]);
+    let doc_hidden = cx.attribute(span, doc);
+
+    let proc_macro = Ident::with_empty_ctxt(sym::proc_macro);
     let krate = cx.item(span,
                         proc_macro,
                         Vec::new(),
@@ -420,8 +429,8 @@ fn mk_decls(
     let module = cx.item_mod(
         span,
         span,
-        ast::Ident::with_empty_ctxt(Symbol::gensym("decls")),
-        vec![],
+        ast::Ident::from_str("decls").gensym(),
+        vec![doc_hidden],
         vec![krate, decls_static],
     ).map(|mut i| {
         i.vis = respan(span, ast::VisibilityKind::Public);
diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs
index 0fa5cd64360..211a098022f 100644
--- a/src/libsyntax_ext/test.rs
+++ b/src/libsyntax_ext/test.rs
@@ -7,7 +7,7 @@ use syntax::ext::hygiene::{self, Mark, SyntaxContext};
 use syntax::attr;
 use syntax::ast;
 use syntax::print::pprust;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::{DUMMY_SP, Span};
 use syntax::source_map::{ExpnInfo, MacroAttribute};
 use std::iter;
@@ -127,7 +127,7 @@ pub fn expand_test_or_bench(
         ])
     };
 
-    let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name.gensymed(), sp),
+    let mut test_const = cx.item(sp, ast::Ident::new(item.ident.name, sp).gensym(),
         vec![
             // #[cfg(test)]
             cx.attribute(attr_sp, cx.meta_list(attr_sp, Symbol::intern("cfg"), vec![
@@ -206,15 +206,15 @@ enum ShouldPanic {
 }
 
 fn should_ignore(i: &ast::Item) -> bool {
-    attr::contains_name(&i.attrs, "ignore")
+    attr::contains_name(&i.attrs, sym::ignore)
 }
 
 fn should_fail(i: &ast::Item) -> bool {
-    attr::contains_name(&i.attrs, "allow_fail")
+    attr::contains_name(&i.attrs, sym::allow_fail)
 }
 
 fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
-    match attr::find_by_name(&i.attrs, "should_panic") {
+    match attr::find_by_name(&i.attrs, sym::should_panic) {
         Some(attr) => {
             let ref sd = cx.parse_sess.span_diagnostic;
 
@@ -222,7 +222,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
                 // Handle #[should_panic(expected = "foo")]
                 Some(list) => {
                     let msg = list.iter()
-                        .find(|mi| mi.check_name("expected"))
+                        .find(|mi| mi.check_name(sym::expected))
                         .and_then(|mi| mi.meta_item())
                         .and_then(|mi| mi.value_str());
                     if list.len() != 1 || msg.is_none() {
@@ -247,7 +247,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
 }
 
 fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
-    let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
+    let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let ref sd = cx.parse_sess.span_diagnostic;
     if let ast::ItemKind::Fn(ref decl, ref header, ref generics, _) = i.node {
         if header.unsafety == ast::Unsafety::Unsafe {
diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs
index 1ed1ab0a07b..802037f6d22 100644
--- a/src/libsyntax_ext/test_case.rs
+++ b/src/libsyntax_ext/test_case.rs
@@ -14,7 +14,7 @@ use syntax::ext::build::AstBuilder;
 use syntax::ext::hygiene::{self, Mark, SyntaxContext};
 use syntax::ast;
 use syntax::source_map::respan;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax_pos::{DUMMY_SP, Span};
 use syntax::source_map::{ExpnInfo, MacroAttribute};
 use syntax::feature_gate;
@@ -27,7 +27,7 @@ pub fn expand(
 ) -> Vec<Annotatable> {
     if !ecx.ecfg.enable_custom_test_frameworks() {
         feature_gate::emit_feature_err(&ecx.parse_sess,
-                                       "custom_test_frameworks",
+                                       sym::custom_test_frameworks,
                                        attr_sp,
                                        feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_CUSTOM_TEST_FRAMEWORKS);
diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs
index 4d35daf3de9..eca658cb547 100644
--- a/src/libsyntax_ext/trace_macros.rs
+++ b/src/libsyntax_ext/trace_macros.rs
@@ -1,6 +1,6 @@
 use syntax::ext::base::{self, ExtCtxt};
 use syntax::feature_gate;
-use syntax::symbol::keywords;
+use syntax::symbol::{keywords, sym};
 use syntax_pos::Span;
 use syntax::tokenstream::TokenTree;
 
@@ -10,7 +10,7 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt<'_>,
                            -> Box<dyn base::MacResult + 'static> {
     if !cx.ecfg.enable_trace_macros() {
         feature_gate::emit_feature_err(&cx.parse_sess,
-                                       "trace_macros",
+                                       sym::trace_macros,
                                        sp,
                                        feature_gate::GateIssue::Language,
                                        feature_gate::EXPLAIN_TRACE_MACROS);
diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs
index a0b0052f26d..00cd00f2837 100644
--- a/src/libsyntax_pos/edition.rs
+++ b/src/libsyntax_pos/edition.rs
@@ -1,3 +1,4 @@
+use crate::symbol::{Symbol, sym};
 use std::fmt;
 use std::str::FromStr;
 
@@ -44,10 +45,10 @@ impl Edition {
         }
     }
 
-    pub fn feature_name(&self) -> &'static str {
+    pub fn feature_name(&self) -> Symbol {
         match *self {
-            Edition::Edition2015 => "rust_2015_preview",
-            Edition::Edition2018 => "rust_2018_preview",
+            Edition::Edition2015 => sym::rust_2015_preview,
+            Edition::Edition2018 => sym::rust_2018_preview,
         }
     }
 
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index a901afdff43..1d9dc26bf60 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -591,6 +591,10 @@ impl ExpnFormat {
 /// The kind of compiler desugaring.
 #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum CompilerDesugaringKind {
+    /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
+    /// However, we do not want to blame `c` for unreachability but rather say that `i`
+    /// is unreachable. This desugaring kind allows us to avoid blaming `c`.
+    IfTemporary,
     QuestionMark,
     TryBlock,
     /// Desugaring of an `impl Trait` in return type position
@@ -605,6 +609,7 @@ pub enum CompilerDesugaringKind {
 impl CompilerDesugaringKind {
     pub fn name(self) -> Symbol {
         Symbol::intern(match self {
+            CompilerDesugaringKind::IfTemporary => "if",
             CompilerDesugaringKind::Async => "async",
             CompilerDesugaringKind::Await => "await",
             CompilerDesugaringKind::QuestionMark => "?",
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 3f09405a5c8..39859f25f97 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -33,7 +33,7 @@ mod span_encoding;
 pub use span_encoding::{Span, DUMMY_SP};
 
 pub mod symbol;
-pub use symbol::symbols;
+pub use symbol::{Symbol, sym};
 
 mod analyze_source_file;
 
@@ -388,12 +388,12 @@ impl Span {
     /// Checks if a span is "internal" to a macro in which `#[unstable]`
     /// items can be used (that is, a macro marked with
     /// `#[allow_internal_unstable]`).
-    pub fn allows_unstable(&self, feature: &str) -> bool {
+    pub fn allows_unstable(&self, feature: Symbol) -> bool {
         match self.ctxt().outer().expn_info() {
             Some(info) => info
                 .allow_internal_unstable
                 .map_or(false, |features| features.iter().any(|&f|
-                    f == feature || f == "allow_internal_unstable_backcompat_hack"
+                    f == feature || f == sym::allow_internal_unstable_backcompat_hack
                 )),
             None => false,
         }
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 20759217b54..a07c7eb897e 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -30,7 +30,6 @@ symbols! {
 
         // Keywords that are used in stable Rust.
         As:                 "as",
-        Box:                "box",
         Break:              "break",
         Const:              "const",
         Continue:           "continue",
@@ -69,6 +68,7 @@ symbols! {
         // Keywords that are used in unstable Rust or reserved for future use.
         Abstract:           "abstract",
         Become:             "become",
+        Box:                "box",
         Do:                 "do",
         Final:              "final",
         Macro:              "macro",
@@ -99,88 +99,388 @@ symbols! {
         Union:              "union",
     }
 
-    // Other symbols that can be referred to with syntax_pos::symbols::*
-    Other {
+    // Symbols that can be referred to with syntax_pos::sym::*. The symbol is
+    // the stringified identifier unless otherwise specified (e.g.
+    // `proc_dash_macro` represents "proc-macro").
+    Symbols {
+        aarch64_target_feature,
+        abi,
+        abi_amdgpu_kernel,
+        abi_msp430_interrupt,
+        abi_ptx,
+        abi_sysv64,
+        abi_thiscall,
+        abi_unadjusted,
+        abi_vectorcall,
+        abi_x86_interrupt,
+        aborts,
+        advanced_slice_patterns,
+        adx_target_feature,
         alias,
         align,
+        alignstack,
+        all,
+        allocator,
+        allocator_internals,
         alloc_error_handler,
         allow,
+        allowed,
         allow_fail,
         allow_internal_unsafe,
         allow_internal_unstable,
+        allow_internal_unstable_backcompat_hack,
+        always,
+        any,
+        arbitrary_self_types,
+        arm_target_feature,
+        asm,
+        associated_consts,
+        associated_type_defaults,
+        associated_types,
+        async_await,
+        attr,
+        attributes,
+        attr_literals,
+        augmented_assignments,
         automatically_derived,
+        avx512_target_feature,
+        await_macro,
+        bin,
+        bind_by_move_pattern_guards,
+        block,
+        borrowck_graphviz_postflow,
+        borrowck_graphviz_preflow,
+        box_patterns,
+        box_syntax,
+        braced_empty_structs,
+        C,
+        cdylib,
         cfg,
         cfg_attr,
+        cfg_attr_multi,
+        cfg_target_feature,
+        cfg_target_has_atomic,
+        cfg_target_thread_local,
+        cfg_target_vendor,
+        clone,
+        clone_closures,
+        clone_from,
+        closure_to_fn_coercion,
+        cmpxchg16b_target_feature,
         cold,
+        compile_error,
         compiler_builtins,
+        concat_idents,
+        conservative_impl_trait,
+        console,
+        const_compare_raw_pointers,
+        const_fn,
+        const_fn_union,
+        const_generics,
+        const_indexing,
+        const_let,
+        const_panic,
+        const_raw_ptr_deref,
+        const_raw_ptr_to_usize_cast,
+        const_transmute,
+        contents,
+        convert,
+        copy_closures,
+        core,
+        core_intrinsics,
         crate_id,
+        crate_in_paths,
         crate_name,
         crate_type,
+        crate_visibility_modifier,
+        custom_attribute,
+        custom_derive,
+        custom_inner_attributes,
+        custom_test_frameworks,
+        c_variadic,
+        decl_macro,
         default_lib_allocator,
+        default_type_parameter_fallback,
+        default_type_params,
         deny,
         deprecated,
         derive,
         doc,
+        doc_alias,
+        doc_cfg,
+        doc_keyword,
+        doc_masked,
+        doc_spotlight,
+        document_private_items,
+        dotdoteq_in_patterns,
+        dotdot_in_tuple_patterns,
+        double_braced_crate: "{{crate}}",
+        double_braced_impl: "{{impl}}",
+        double_braced_misc: "{{misc}}",
+        double_braced_closure: "{{closure}}",
+        double_braced_constructor: "{{constructor}}",
+        double_braced_constant: "{{constant}}",
+        double_braced_opaque: "{{opaque}}",
+        dropck_eyepatch,
+        dropck_parametricity,
+        drop_types_in_const,
+        dylib,
+        dyn_trait,
+        eh_personality,
+        eh_unwind_resume,
+        enable,
+        err,
+        Err,
+        except,
+        exclusive_range_pattern,
+        exhaustive_integer_patterns,
+        exhaustive_patterns,
+        existential_type,
+        expected,
         export_name,
+        extern_absolute_paths,
+        external_doc,
+        extern_crate_item_prelude,
+        extern_crate_self,
+        extern_in_paths,
+        extern_prelude,
+        extern_types,
+        f16c_target_feature,
         feature,
         ffi_returns_twice,
+        field_init_shorthand,
+        file,
+        fn_must_use,
         forbid,
+        format_args_nl,
+        from,
+        From,
+        from_error,
+        from_generator,
+        from_ok,
         fundamental,
+        future,
+        Future,
+        gen_future,
+        generators,
+        generic_associated_types,
+        generic_param_attrs,
         global_allocator,
+        global_asm,
+        globs,
+        hexagon_target_feature,
+        hidden,
+        homogeneous_aggregate,
+        html_favicon_url,
+        html_logo_url,
+        html_no_source,
+        html_playground_url,
+        html_root_url,
+        i128,
+        i128_type,
+        i16,
+        i32,
+        i64,
+        i8,
+        ident,
+        if_let,
+        if_while_or_patterns,
         ignore,
+        impl_header_lifetime_elision,
+        impl_trait_in_bindings,
+        import_shadowing,
+        in_band_lifetimes,
         include,
+        inclusive_range_syntax,
+        infer_outlives_requirements,
+        infer_static_outlives_requirements,
         inline,
+        intel,
+        into_iter,
+        IntoIterator,
+        into_result,
+        intrinsics,
+        irrefutable_let_patterns,
+        isize,
+        issue,
+        issue_5723_bootstrap,
+        issue_tracker_base_url,
+        item_like_imports,
+        iter,
+        Iterator,
         keyword,
+        kind,
+        label,
+        label_break_value,
         lang,
+        lang_items,
+        lib,
         link,
+        linkage,
         link_args,
+        link_cfg,
+        link_llvm_intrinsics,
         link_name,
         link_section,
-        linkage,
+        lint_reasons,
+        local_inner_macros,
+        log_syntax,
+        loop_break_value,
+        macro_at_most_once_rep,
         macro_escape,
         macro_export,
+        macro_lifetime_matcher,
+        macro_literal_matcher,
+        macro_reexport,
+        macro_rules,
+        macros_in_extern,
         macro_use,
+        macro_vis_matcher,
         main,
+        managed_boxes,
         marker,
+        marker_trait_attr,
         masked,
+        match_beginning_vert,
+        match_default_bindings,
         may_dangle,
+        message,
+        meta,
+        min_const_fn,
+        min_const_unsafe_fn,
+        mips_target_feature,
+        mmx_target_feature,
+        module,
+        more_struct_aliases,
+        movbe_target_feature,
         must_use,
         naked,
+        naked_functions,
+        name,
         needs_allocator,
         needs_panic_runtime,
+        negate_unsigned,
+        never,
+        never_type,
+        next,
+        __next,
+        nll,
         no_builtins,
         no_core,
+        no_crate_inject,
         no_debug,
+        no_default_passes,
         no_implicit_prelude,
+        no_inline,
         no_link,
         no_main,
         no_mangle,
+        non_ascii_idents,
+        None,
+        non_exhaustive,
+        non_modrs_mods,
+        no_stack_check,
         no_start,
         no_std,
-        non_exhaustive,
+        not,
+        note,
+        Ok,
         omit_gdb_pretty_printer_section,
+        on,
+        on_unimplemented,
+        oom,
+        ops,
         optimize,
+        optimize_attribute,
+        optin_builtin_traits,
+        option,
+        Option,
+        opt_out_copy,
+        Output,
+        overlapping_marker_traits,
+        packed,
         panic_handler,
+        panic_impl,
+        panic_implementation,
         panic_runtime,
+        passes,
         path,
+        pattern_parentheses,
+        Pending,
+        pin,
+        Pin,
+        pinned,
+        platform_intrinsics,
         plugin,
         plugin_registrar,
+        plugins,
+        Poll,
+        poll_with_tls_context,
+        powerpc_target_feature,
+        precise_pointer_size_matching,
+        prelude,
         prelude_import,
+        primitive,
+        proc_dash_macro: "proc-macro",
         proc_macro,
         proc_macro_attribute,
         proc_macro_derive,
+        proc_macro_expr,
+        proc_macro_gen,
+        proc_macro_hygiene,
+        proc_macro_mod,
+        proc_macro_non_items,
+        proc_macro_path_invoc,
         profiler_runtime,
+        pub_restricted,
+        pushpop_unsafe,
+        quad_precision_float,
+        question_mark,
+        quote,
+        Range,
+        RangeFrom,
+        RangeFull,
+        RangeInclusive,
+        RangeTo,
+        RangeToInclusive,
+        raw_identifiers,
+        Ready,
+        reason,
         recursion_limit,
         reexport_test_harness_main,
+        reflect,
+        relaxed_adts,
         repr,
+        repr128,
+        repr_align,
+        repr_align_enum,
+        repr_packed,
+        repr_simd,
+        repr_transparent,
+        re_rebalance_coherence,
+        result,
+        Result,
+        Return,
+        rlib,
+        rtm_target_feature,
+        rust,
+        rust_2015_preview,
+        rust_2018_preview,
+        rust_begin_unwind,
+        rustc_allocator_nounwind,
+        rustc_allow_const_fn_ptr,
         rustc_args_required_const,
+        rustc_attrs,
         rustc_clean,
         rustc_const_unstable,
         rustc_conversion_suggestion,
         rustc_copy_clone_marker,
         rustc_def_path,
         rustc_deprecated,
+        rustc_diagnostic_macros,
         rustc_dirty,
+        rustc_doc_only_macro,
+        rustc_dump_env_program_clauses,
         rustc_dump_program_clauses,
         rustc_dump_user_substs,
         rustc_error,
@@ -191,13 +491,21 @@ symbols! {
         rustc_layout_scalar_valid_range_end,
         rustc_layout_scalar_valid_range_start,
         rustc_mir,
+        rustc_object_lifetime_default,
         rustc_on_unimplemented,
         rustc_outlives,
         rustc_paren_sugar,
         rustc_partition_codegened,
         rustc_partition_reused,
+        rustc_peek,
+        rustc_peek_definite_init,
+        rustc_peek_maybe_init,
+        rustc_peek_maybe_uninit,
+        rustc_private,
         rustc_proc_macro_decls,
+        rustc_promotable,
         rustc_regions,
+        rustc_stable,
         rustc_std_internal_symbol,
         rustc_symbol_name,
         rustc_synthetic,
@@ -205,23 +513,112 @@ symbols! {
         rustc_then_this_would_need,
         rustc_transparent_macro,
         rustc_variance,
+        rustdoc,
+        rust_eh_personality,
+        rust_eh_unwind_resume,
+        rust_oom,
+        __rust_unstable_column,
+        rvalue_static_promotion,
         sanitizer_runtime,
+        self_in_typedefs,
+        self_struct_ctor,
+        Send,
         should_panic,
         simd,
+        simd_ffi,
+        since,
+        size,
+        slice_patterns,
+        slicing_syntax,
+        Some,
+        specialization,
+        speed,
         spotlight,
+        sse4a_target_feature,
         stable,
+        staged_api,
         start,
+        static_in_const,
+        staticlib,
+        static_nobundle,
+        static_recursion,
+        std,
+        str,
+        stmt_expr_attributes,
+        stop_after_dataflow,
+        struct_field_attributes,
+        struct_inherit,
         structural_match,
+        struct_variant,
+        suggestion,
         target_feature,
+        target_has_atomic,
+        target_thread_local,
+        task,
+        tbm_target_feature,
+        termination_trait,
+        termination_trait_test,
+        test,
+        test_2018_feature,
+        test_accepted_feature,
+        test_removed_feature,
         test_runner,
         thread_local,
+        tool_attributes,
+        tool_lints,
+        trace_macros,
+        trait_alias,
+        transmute,
+        transparent,
+        trivial_bounds,
+        Try,
+        try_blocks,
+        try_trait,
+        tuple_indexing,
+        ty,
+        type_alias_enum_variants,
+        type_ascription,
         type_length_limit,
+        type_macros,
+        u128,
+        u16,
+        u32,
+        u64,
+        u8,
+        unboxed_closures,
+        underscore_const_names,
+        underscore_imports,
+        underscore_lifetimes,
+        uniform_paths,
+        universal_impl_trait,
+        unmarked_api,
+        unreachable_code,
+        unrestricted_attribute_tokens,
         unsafe_destructor_blind_to_params,
+        unsafe_no_drop_flag,
+        unsized_locals,
+        unsized_tuple_coercion,
         unstable,
+        untagged_unions,
         unwind,
+        unwind_attributes,
         used,
+        use_extern_macros,
+        use_nested_groups,
+        usize,
+        v1,
+        val,
+        vis,
+        visible_private_types,
+        volatile,
         warn,
+        warn_directory_ownership,
+        wasm_import_module,
+        wasm_target_feature,
+        while_let,
+        windows,
         windows_subsystem,
+        Yield,
     }
 }
 
@@ -233,10 +630,12 @@ pub struct Ident {
 
 impl Ident {
     #[inline]
+    /// Constructs a new identifier from a symbol and a span.
     pub const fn new(name: Symbol, span: Span) -> Ident {
         Ident { name, span }
     }
 
+    /// Constructs a new identifier with an empty syntax context.
     #[inline]
     pub const fn with_empty_ctxt(name: Symbol) -> Ident {
         Ident::new(name, DUMMY_SP)
@@ -247,11 +646,16 @@ impl Ident {
         Ident::with_empty_ctxt(string.as_symbol())
     }
 
-    /// Maps a string to an identifier with an empty syntax context.
+    /// Maps a string to an identifier with an empty span.
     pub fn from_str(string: &str) -> Ident {
         Ident::with_empty_ctxt(Symbol::intern(string))
     }
 
+    /// Maps a string and a span to an identifier.
+    pub fn from_str_and_span(string: &str, span: Span) -> Ident {
+        Ident::new(Symbol::intern(string), span)
+    }
+
     /// Replaces `lo` and `hi` with those from `span`, but keep hygiene context.
     pub fn with_span_pos(self, span: Span) -> Ident {
         Ident::new(self.name, span.with_ctxt(self.span.ctxt()))
@@ -279,14 +683,23 @@ impl Ident {
         Ident::new(self.name, self.span.modern_and_legacy())
     }
 
+    /// Transforms an identifier into one with the same name, but gensymed.
     pub fn gensym(self) -> Ident {
-        Ident::new(self.name.gensymed(), self.span)
+        let name = with_interner(|interner| interner.gensymed(self.name));
+        Ident::new(name, self.span)
     }
 
+    /// Transforms an underscore identifier into one with the same name, but
+    /// gensymed. Leaves non-underscore identifiers unchanged.
     pub fn gensym_if_underscore(self) -> Ident {
         if self.name == keywords::Underscore.name() { self.gensym() } else { self }
     }
 
+    // WARNING: this function is deprecated and will be removed in the future.
+    pub fn is_gensymed(self) -> bool {
+        with_interner(|interner| interner.is_gensymed(self.name))
+    }
+
     pub fn as_str(self) -> LocalInternedString {
         self.name.as_str()
     }
@@ -339,17 +752,34 @@ impl Decodable for Ident {
         Ok(if !string.starts_with('#') {
             Ident::from_str(&string)
         } else { // FIXME(jseyfried): intercrate hygiene
-            Ident::with_empty_ctxt(Symbol::gensym(&string[1..]))
+            Ident::from_str(&string[1..]).gensym()
         })
     }
 }
 
-/// A symbol is an interned or gensymed string. The use of `newtype_index!` means
-/// that `Option<Symbol>` only takes up 4 bytes, because `newtype_index!` reserves
-/// the last 256 values for tagging purposes.
+/// A symbol is an interned or gensymed string. A gensym is a symbol that is
+/// never equal to any other symbol.
 ///
-/// Note that `Symbol` cannot directly be a `newtype_index!` because it implements
-/// `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
+/// Conceptually, a gensym can be thought of as a normal symbol with an
+/// invisible unique suffix. Gensyms are useful when creating new identifiers
+/// that must not match any existing identifiers, e.g. during macro expansion
+/// and syntax desugaring. Because gensyms should always be identifiers, all
+/// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
+/// future the gensym-ness may be moved from `Symbol` to hygiene data.)
+///
+/// Examples:
+/// ```
+/// assert_eq!(Ident::from_str("x"), Ident::from_str("x"))
+/// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x"))
+/// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x").gensym())
+/// ```
+/// Internally, a symbol is implemented as an index, and all operations
+/// (including hashing, equality, and ordering) operate on that index. The use
+/// of `newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
+/// because `newtype_index!` reserves the last 256 values for tagging purposes.
+///
+/// Note that `Symbol` cannot directly be a `newtype_index!` because it
+/// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Symbol(SymbolIndex);
 
@@ -367,23 +797,6 @@ impl Symbol {
         with_interner(|interner| interner.intern(string))
     }
 
-    pub fn interned(self) -> Self {
-        with_interner(|interner| interner.interned(self))
-    }
-
-    /// Gensyms a new `usize`, using the current interner.
-    pub fn gensym(string: &str) -> Self {
-        with_interner(|interner| interner.gensym(string))
-    }
-
-    pub fn gensymed(self) -> Self {
-        with_interner(|interner| interner.gensymed(self))
-    }
-
-    pub fn is_gensymed(self) -> bool {
-        with_interner(|interner| interner.is_gensymed(self))
-    }
-
     pub fn as_str(self) -> LocalInternedString {
         with_interner(|interner| unsafe {
             LocalInternedString {
@@ -432,12 +845,6 @@ impl Decodable for Symbol {
     }
 }
 
-impl<T: std::ops::Deref<Target=str>> PartialEq<T> for Symbol {
-    fn eq(&self, other: &T) -> bool {
-        self.as_str() == other.deref()
-    }
-}
-
 // The `&'static str`s in this type actually point into the arena.
 //
 // Note that normal symbols are indexed upward from 0, and gensyms are indexed
@@ -453,15 +860,16 @@ pub struct Interner {
 impl Interner {
     fn prefill(init: &[&str]) -> Self {
         let mut this = Interner::default();
-        for &string in init {
-            if string == "" {
-                // We can't allocate empty strings in the arena, so handle this here.
-                let name = Symbol::new(this.strings.len() as u32);
-                this.names.insert("", name);
-                this.strings.push("");
-            } else {
-                this.intern(string);
-            }
+        this.names.reserve(init.len());
+        this.strings.reserve(init.len());
+
+        // We can't allocate empty strings in the arena, so handle this here.
+        assert!(keywords::Invalid.name().as_u32() == 0 && init[0].is_empty());
+        this.names.insert("", keywords::Invalid.name());
+        this.strings.push("");
+
+        for string in &init[1..] {
+            this.intern(string);
         }
         this
     }
@@ -488,19 +896,14 @@ impl Interner {
         name
     }
 
-    pub fn interned(&self, symbol: Symbol) -> Symbol {
+    fn interned(&self, symbol: Symbol) -> Symbol {
         if (symbol.0.as_usize()) < self.strings.len() {
             symbol
         } else {
-            self.interned(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize])
+            self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]
         }
     }
 
-    fn gensym(&mut self, string: &str) -> Symbol {
-        let symbol = self.intern(string);
-        self.gensymed(symbol)
-    }
-
     fn gensymed(&mut self, symbol: Symbol) -> Symbol {
         self.gensyms.push(symbol);
         Symbol::new(SymbolIndex::MAX_AS_U32 - self.gensyms.len() as u32 + 1)
@@ -510,10 +913,15 @@ impl Interner {
         symbol.0.as_usize() >= self.strings.len()
     }
 
+    // Get the symbol as a string. `Symbol::as_str()` should be used in
+    // preference to this function.
     pub fn get(&self, symbol: Symbol) -> &str {
         match self.strings.get(symbol.0.as_usize()) {
             Some(string) => string,
-            None => self.get(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]),
+            None => {
+                let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize];
+                self.strings[symbol.0.as_usize()]
+            }
         }
     }
 }
@@ -541,7 +949,8 @@ pub mod keywords {
     keywords!();
 }
 
-pub mod symbols {
+// This module has a very short name because it's used a lot.
+pub mod sym {
     use super::Symbol;
     symbols!();
 }
@@ -611,17 +1020,34 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
     GLOBALS.with(|globals| f(&mut *globals.symbol_interner.lock()))
 }
 
-/// Represents a string stored in the interner. Because the interner outlives any thread
-/// which uses this type, we can safely treat `string` which points to interner data,
-/// as an immortal string, as long as this type never crosses between threads.
-// FIXME: ensure that the interner outlives any thread which uses `LocalInternedString`,
-// by creating a new thread right after constructing the interner.
+/// An alternative to `Symbol` and `InternedString`, useful when the chars
+/// within the symbol need to be accessed. It is best used for temporary
+/// values.
+///
+/// Because the interner outlives any thread which uses this type, we can
+/// safely treat `string` which points to interner data, as an immortal string,
+/// as long as this type never crosses between threads.
+//
+// FIXME: ensure that the interner outlives any thread which uses
+// `LocalInternedString`, by creating a new thread right after constructing the
+// interner.
 #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)]
 pub struct LocalInternedString {
     string: &'static str,
 }
 
 impl LocalInternedString {
+    /// Maps a string to its interned representation.
+    pub fn intern(string: &str) -> Self {
+        let string = with_interner(|interner| {
+            let symbol = interner.intern(string);
+            interner.strings[symbol.0.as_usize()]
+        });
+        LocalInternedString {
+            string: unsafe { std::mem::transmute::<&str, &str>(string) }
+        }
+    }
+
     pub fn as_interned_str(self) -> InternedString {
         InternedString {
             symbol: Symbol::intern(self.string)
@@ -698,7 +1124,7 @@ impl fmt::Display for LocalInternedString {
 
 impl Decodable for LocalInternedString {
     fn decode<D: Decoder>(d: &mut D) -> Result<LocalInternedString, D::Error> {
-        Ok(Symbol::intern(&d.read_str()?).as_str())
+        Ok(LocalInternedString::intern(&d.read_str()?))
     }
 }
 
@@ -708,13 +1134,32 @@ impl Encodable for LocalInternedString {
     }
 }
 
-/// Represents a string stored in the string interner.
+/// An alternative to `Symbol` that is focused on string contents. It has two
+/// main differences to `Symbol`.
+///
+/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the
+/// string chars rather than the symbol integer. This is useful when hash
+/// stability is required across compile sessions, or a guaranteed sort
+/// ordering is required.
+///
+/// Second, gensym-ness is irrelevant. E.g.:
+/// ```
+/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
+/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str())
+/// ```
 #[derive(Clone, Copy, Eq)]
 pub struct InternedString {
     symbol: Symbol,
 }
 
 impl InternedString {
+    /// Maps a string to its interned representation.
+    pub fn intern(string: &str) -> Self {
+        InternedString {
+            symbol: Symbol::intern(string)
+        }
+    }
+
     pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
         let str = with_interner(|interner| {
             interner.get(self.symbol) as *const str
@@ -725,6 +1170,15 @@ impl InternedString {
         unsafe { f(&*str) }
     }
 
+    fn with2<F: FnOnce(&str, &str) -> R, R>(self, other: &InternedString, f: F) -> R {
+        let (self_str, other_str) = with_interner(|interner| {
+            (interner.get(self.symbol) as *const str,
+             interner.get(other.symbol) as *const str)
+        });
+        // This is safe for the same reason that `with` is safe.
+        unsafe { f(&*self_str, &*other_str) }
+    }
+
     pub fn as_symbol(self) -> Symbol {
         self.symbol
     }
@@ -745,7 +1199,7 @@ impl PartialOrd<InternedString> for InternedString {
         if self.symbol == other.symbol {
             return Some(Ordering::Equal);
         }
-        self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str)))
+        self.with2(other, |self_str, other_str| self_str.partial_cmp(other_str))
     }
 }
 
@@ -754,7 +1208,7 @@ impl Ord for InternedString {
         if self.symbol == other.symbol {
             return Ordering::Equal;
         }
-        self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str)))
+        self.with2(other, |self_str, other_str| self_str.cmp(other_str))
     }
 }
 
@@ -794,12 +1248,6 @@ impl<'a> PartialEq<InternedString> for &'a String {
     }
 }
 
-impl std::convert::From<InternedString> for String {
-    fn from(val: InternedString) -> String {
-        val.as_symbol().to_string()
-    }
-}
-
 impl fmt::Debug for InternedString {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.with(|str| fmt::Debug::fmt(&str, f))
@@ -814,7 +1262,7 @@ impl fmt::Display for InternedString {
 
 impl Decodable for InternedString {
     fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
-        Ok(Symbol::intern(&d.read_str()?).as_interned_str())
+        Ok(InternedString::intern(&d.read_str()?))
     }
 }
 
@@ -841,11 +1289,13 @@ mod tests {
         assert_eq!(i.intern("cat"), Symbol::new(1));
         // dog is still at zero
         assert_eq!(i.intern("dog"), Symbol::new(0));
-        assert_eq!(i.gensym("zebra"), Symbol::new(SymbolIndex::MAX_AS_U32));
+        let z = i.intern("zebra");
+        assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32));
         // gensym of same string gets new number:
-        assert_eq!(i.gensym("zebra"), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
+        assert_eq!(i.gensymed(z), Symbol::new(SymbolIndex::MAX_AS_U32 - 1));
         // gensym of *existing* string gets new number:
-        assert_eq!(i.gensym("dog"), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
+        let d = i.intern("dog");
+        assert_eq!(i.gensymed(d), Symbol::new(SymbolIndex::MAX_AS_U32 - 2));
     }
 
     #[test]
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 26612964c30..7f7db2a2125 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -37,12 +37,13 @@ extern crate libc;
 use term;
 
 // FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
-//                on aarch64-pc-windows-msvc, so we don't link libtest against
-//                libunwind (for the time being), even though it means that
-//                libtest won't be fully functional on this platform.
+//                on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc
+//                so we don't link libtest against libunwind (for the time being)
+//                even though it means that libtest won't be fully functional on
+//                these platforms.
 //
 // See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
-#[cfg(not(all(windows, target_arch = "aarch64")))]
+#[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))]
 extern crate panic_unwind;
 
 pub use self::ColorConfig::*;
@@ -1289,7 +1290,6 @@ fn get_concurrency() -> usize {
     #[cfg(any(
         target_os = "freebsd",
         target_os = "dragonfly",
-        target_os = "bitrig",
         target_os = "netbsd"
     ))]
     fn num_cpus() -> usize {
diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs
index f3fda9eaa75..20280aa3c41 100644
--- a/src/libunwind/build.rs
+++ b/src/libunwind/build.rs
@@ -26,8 +26,6 @@ fn main() {
         println!("cargo:rustc-link-lib=c++abi");
     } else if target.contains("solaris") {
         println!("cargo:rustc-link-lib=gcc_s");
-    } else if target.contains("bitrig") {
-        println!("cargo:rustc-link-lib=c++abi");
     } else if target.contains("dragonfly") {
         println!("cargo:rustc-link-lib=gcc_pic");
     } else if target.contains("windows-gnu") {
@@ -69,13 +67,10 @@ mod llvm_libunwind {
             cfg.flag("-std=c99");
             cfg.flag("-std=c++11");
             cfg.flag("-nostdinc++");
-            if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() &&
-               cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() {
-                cfg.flag("-funwind-tables");
-                cfg.flag("-fno-exceptions");
-            }
+            cfg.flag("-fno-exceptions");
             cfg.flag("-fno-rtti");
             cfg.flag("-fstrict-aliasing");
+            cfg.flag("-funwind-tables");
         }
 
         let mut unwind_sources = vec![
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 84abffda0e03b03c62bdfc3cfeda1c2cf1f88c8
+Subproject 2c5656ae593851d0b2336a727cc14b77a06b8ac
diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs
index 0dd67bb95cc..5004f787cde 100644
--- a/src/test/codegen/box-maybe-uninit.rs
+++ b/src/test/codegen/box-maybe-uninit.rs
@@ -1,6 +1,5 @@
 // compile-flags: -O
 #![crate_type="lib"]
-#![feature(maybe_uninit)]
 
 use std::mem::MaybeUninit;
 
diff --git a/src/test/codegen/dllimports/main.rs b/src/test/codegen/dllimports/main.rs
index 40bbd2821ef..73631b92c1f 100644
--- a/src/test/codegen/dllimports/main.rs
+++ b/src/test/codegen/dllimports/main.rs
@@ -1,6 +1,5 @@
 // This test is for *-windows-msvc only.
 // ignore-android
-// ignore-bitrig
 // ignore-cloudabi
 // ignore-dragonfly
 // ignore-emscripten
@@ -13,6 +12,7 @@
 // ignore-netbsd
 // ignore-openbsd
 // ignore-solaris
+// ignore-sgx no dynamic linking
 
 // aux-build:dummy.rs
 // aux-build:wrapper.rs
diff --git a/src/test/codegen/enum-debug-niche-2.rs b/src/test/codegen/enum-debug-niche-2.rs
index aa6cbf66b4a..0f17976ef49 100644
--- a/src/test/codegen/enum-debug-niche-2.rs
+++ b/src/test/codegen/enum-debug-niche-2.rs
@@ -13,7 +13,6 @@
 // CHECK: {{.*}}DIDerivedType{{.*}}tag: DW_TAG_member,{{.*}}name: "Error",{{.*}}extraData: i64 0{{[,)].*}}
 
 #![feature(never_type)]
-#![feature(nll)]
 
 #[derive(Copy, Clone)]
 pub struct Entity {
diff --git a/src/test/codegen/i686-no-macosx-deployment-target.rs b/src/test/codegen/i686-no-macosx-deployment-target.rs
index eb826590523..1cebc49236f 100644
--- a/src/test/codegen/i686-no-macosx-deployment-target.rs
+++ b/src/test/codegen/i686-no-macosx-deployment-target.rs
@@ -19,7 +19,7 @@ pub struct Bool {
     b: bool,
 }
 
-// CHECK: target triple = "i686-apple-darwin"
+// CHECK: target triple = "i686-apple-macosx10.7.0"
 #[no_mangle]
 pub extern "C" fn structbool() -> Bool {
     Bool { b: true }
diff --git a/src/test/codegen/panic-abort-windows.rs b/src/test/codegen/panic-abort-windows.rs
index bbe0d81de3d..8e38245267d 100644
--- a/src/test/codegen/panic-abort-windows.rs
+++ b/src/test/codegen/panic-abort-windows.rs
@@ -1,6 +1,5 @@
 // This test is for *-windows-msvc only.
 // ignore-android
-// ignore-bitrig
 // ignore-cloudabi
 // ignore-dragonfly
 // ignore-emscripten
@@ -12,6 +11,7 @@
 // ignore-netbsd
 // ignore-openbsd
 // ignore-solaris
+// ignore-sgx
 
 // compile-flags: -C no-prepopulate-passes -C panic=abort -O
 
diff --git a/src/test/codegen/x86_64-no-macosx-deployment-target.rs b/src/test/codegen/x86_64-no-macosx-deployment-target.rs
index 58a11d1095b..c5ac73b54e1 100644
--- a/src/test/codegen/x86_64-no-macosx-deployment-target.rs
+++ b/src/test/codegen/x86_64-no-macosx-deployment-target.rs
@@ -19,7 +19,7 @@ pub struct Bool {
     b: bool,
 }
 
-// CHECK: target triple = "x86_64-apple-darwin"
+// CHECK: target triple = "x86_64-apple-macosx10.7.0"
 #[no_mangle]
 pub extern "C" fn structbool() -> Bool {
     Bool { b: true }
diff --git a/src/test/incremental/foreign.rs b/src/test/incremental/foreign.rs
index 0581cd79975..498bf892250 100644
--- a/src/test/incremental/foreign.rs
+++ b/src/test/incremental/foreign.rs
@@ -1,5 +1,6 @@
 // Test what happens we save incremental compilation state that makes
 // use of foreign items. This used to ICE (#34991).
+// ignore-sgx no libc
 
 // revisions: rpass1
 
diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs
index 5bfd540eca6..5165f9821fd 100644
--- a/src/test/incremental/hashes/closure_expressions.rs
+++ b/src/test/incremental/hashes/closure_expressions.rs
@@ -49,14 +49,14 @@ pub fn add_parameter() {
 // Change parameter pattern ----------------------------------------------------
 #[cfg(cfail1)]
 pub fn change_parameter_pattern() {
-    let _ = |x: &u32| x;
+    let _ = |x: (u32,)| x;
 }
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_parameter_pattern() {
-    let _ = |&x: &u32| x;
+    let _ = |(x,): (u32,)| x;
 }
 
 
diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs
index fba7869af42..6bc7d286e3a 100644
--- a/src/test/incremental/hashes/if_expressions.rs
+++ b/src/test/incremental/hashes/if_expressions.rs
@@ -94,7 +94,7 @@ pub fn add_else_branch(x: bool) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_else_branch(x: bool) -> u32 {
     let mut ret = 1;
@@ -191,7 +191,7 @@ pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")]
+#[rustc_clean(cfg="cfail2", except="HirBody")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
     let mut ret = 1;
diff --git a/src/test/incremental/issue-60629.rs b/src/test/incremental/issue-60629.rs
new file mode 100644
index 00000000000..4807af4b3cf
--- /dev/null
+++ b/src/test/incremental/issue-60629.rs
@@ -0,0 +1,10 @@
+// revisions:rpass1 rpass2
+
+struct A;
+
+#[cfg(rpass2)]
+impl From<A> for () {
+    fn from(_: A) {}
+}
+
+fn main() {}
diff --git a/src/test/incremental/no_mangle.rs b/src/test/incremental/no_mangle.rs
new file mode 100644
index 00000000000..1b17886a4f9
--- /dev/null
+++ b/src/test/incremental/no_mangle.rs
@@ -0,0 +1,10 @@
+// revisions:rpass1 rpass2
+// compile-flags: --crate-type cdylib
+// skip-codegen
+
+#![deny(unused_attributes)]
+
+#[no_mangle]
+pub extern "C" fn rust_no_mangle() -> i32 {
+    42
+}
diff --git a/src/test/mir-opt/const_prop/array_index.rs b/src/test/mir-opt/const_prop/array_index.rs
new file mode 100644
index 00000000000..dd22eb5d604
--- /dev/null
+++ b/src/test/mir-opt/const_prop/array_index.rs
@@ -0,0 +1,33 @@
+fn main() {
+    let x: u32 = [0, 1, 2, 3][2];
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _2 = [const 0u32, const 1u32, const 2u32, const 3u32];
+//      ...
+//      _3 = const 2usize;
+//      _4 = const 4usize;
+//      _5 = Lt(_3, _4);
+//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
+//  }
+//  bb1: {
+//      _1 = _2[_3];
+//      ...
+//      return;
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _5 = const true;
+//      assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
+//  }
+//  bb1: {
+//      _1 = _2[_3];
+//      ...
+//      return;
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/checked_add.rs b/src/test/mir-opt/const_prop/checked_add.rs
new file mode 100644
index 00000000000..fe98cf24eec
--- /dev/null
+++ b/src/test/mir-opt/const_prop/checked_add.rs
@@ -0,0 +1,21 @@
+// compile-flags: -C overflow-checks=on
+
+fn main() {
+    let x: u32 = 1 + 1;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _2 = CheckedAdd(const 1u32, const 1u32);
+//      assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _2 = (const 2u32, const false);
+//      assert(!const false, "attempt to add with overflow") -> bb1;
+//  }
+// END rustc.main.ConstProp.after.mir
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
new file mode 100644
index 00000000000..97d3abdcc6c
--- /dev/null
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.rs
@@ -0,0 +1,34 @@
+#[inline(never)]
+fn read(_: usize) { }
+
+fn main() {
+    const FOO: &i32 = &1;
+    let x = FOO as *const i32 as usize;
+    read(x);
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _3 = _4;
+//      _2 = move _3 as *const i32 (Misc);
+//      ...
+//      _1 = move _2 as usize (Misc);
+//      ...
+//      _6 = _1;
+//      _5 = const read(move _6) -> bb1;
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = _4;
+//      _2 = move _3 as *const i32 (Misc);
+//      ...
+//      _1 = move _2 as usize (Misc);
+//      ...
+//      _6 = _1;
+//      _5 = const read(move _6) -> bb1;
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs
new file mode 100644
index 00000000000..3435ca07f4c
--- /dev/null
+++ b/src/test/mir-opt/const_prop/slice_len.rs
@@ -0,0 +1,37 @@
+fn test() -> &'static [u32] {
+    &[1, 2]
+}
+
+fn main() {
+    let x = test()[0];
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb1: {
+//      ...
+//      _3 = const 0usize;
+//      _4 = Len((*_2));
+//      _5 = Lt(_3, _4);
+//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+//  }
+//  bb2: {
+//      _1 = (*_2)[_3];
+//      ...
+//      return;
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      _3 = const 0usize;
+//      _4 = Len((*_2));
+//      _5 = Lt(_3, _4);
+//      assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+//  }
+//  bb2: {
+//      _1 = (*_2)[_3];
+//      ...
+//      return;
+//  }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/switch_int.rs b/src/test/mir-opt/const_prop/switch_int.rs
new file mode 100644
index 00000000000..0df1112ec3e
--- /dev/null
+++ b/src/test/mir-opt/const_prop/switch_int.rs
@@ -0,0 +1,38 @@
+#[inline(never)]
+fn foo(_: i32) { }
+
+fn main() {
+    match 1 {
+        1 => foo(0),
+        _ => foo(-1),
+    }
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+//  bb0: {
+//      ...
+//      _1 = const 1i32;
+//      switchInt(_1) -> [1i32: bb1, otherwise: bb2];
+//  }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+//  bb0: {
+//      ...
+//      switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
+//  }
+// END rustc.main.ConstProp.after.mir
+// START rustc.main.SimplifyBranches-after-const-prop.before.mir
+//  bb0: {
+//      ...
+//      _1 = const 1i32;
+//      switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
+//  }
+// END rustc.main.SimplifyBranches-after-const-prop.before.mir
+// START rustc.main.SimplifyBranches-after-const-prop.after.mir
+//  bb0: {
+//      ...
+//      _1 = const 1i32;
+//      goto -> bb1;
+//  }
+// END rustc.main.SimplifyBranches-after-const-prop.after.mir
diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs
index 047e623941b..e8ab690bb46 100644
--- a/src/test/mir-opt/issue-38669.rs
+++ b/src/test/mir-opt/issue-38669.rs
@@ -27,15 +27,17 @@ fn main() {
 //     bb3: {
 //         StorageLive(_4);
 //         _4 = _1;
-//         switchInt(move _4) -> [false: bb5, otherwise: bb4];
+//         FakeRead(ForMatchedPlace, _4);
+//         switchInt(_4) -> [false: bb5, otherwise: bb4];
 //     }
-//     bb4: {
+//     ...
+//     bb7: {
 //         _0 = ();
 //         StorageDead(_4);
 //         StorageDead(_1);
 //         return;
 //     }
-//     bb5: {
+//     bb8: {
 //         _3 = ();
 //         StorageDead(_4);
 //         _1 = const true;
diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs
index 34891ee70b5..e75955b9b24 100644
--- a/src/test/mir-opt/loop_test.rs
+++ b/src/test/mir-opt/loop_test.rs
@@ -22,19 +22,20 @@ fn main() {
 //        resume;
 //    }
 //    ...
-//    bb3: { // Entry into the loop
+//    bb6: { // Entry into the loop
 //        _1 = ();
-//        goto -> bb4;
+//        StorageDead(_2);
+//        goto -> bb7;
 //    }
-//    bb4: { // The loop_block
-//        falseUnwind -> [real: bb5, cleanup: bb1];
+//    bb7: { // The loop_block
+//        falseUnwind -> [real: bb8, cleanup: bb1];
 //    }
-//    bb5: { // The loop body (body_block)
-//        StorageLive(_5);
-//        _5 = const 1i32;
-//        FakeRead(ForLet, _5);
-//        StorageDead(_5);
-//        goto -> bb4;
+//    bb8: { // The loop body (body_block)
+//        StorageLive(_6);
+//        _6 = const 1i32;
+//        FakeRead(ForLet, _6);
+//        StorageDead(_6);
+//        goto -> bb7;
 //    }
 //    ...
 // END rustc.main.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs
index bb27461bb1e..622cc999830 100644
--- a/src/test/mir-opt/nll/region-subtyping-basic.rs
+++ b/src/test/mir-opt/nll/region-subtyping-basic.rs
@@ -22,9 +22,9 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#2r    | U0 | {bb2[0..=5], bb3[0..=1]}
-// | '_#3r    | U0 | {bb2[1..=5], bb3[0..=1]}
-// | '_#4r    | U0 | {bb2[4..=5], bb3[0..=1]}
+// | '_#2r | U0 | {bb2[0..=8], bb3[0], bb6[0..=1]}
+// | '_#3r | U0 | {bb2[1..=8], bb3[0], bb6[0..=1]}
+// | '_#4r | U0 | {bb2[4..=8], bb3[0], bb6[0..=1]}
 // END rustc.main.nll.0.mir
 // START rustc.main.nll.0.mir
 // let _2: &'_#3r usize;
diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs
index 144348450a9..8348f9a7746 100644
--- a/src/test/mir-opt/remove_fake_borrows.rs
+++ b/src/test/mir-opt/remove_fake_borrows.rs
@@ -2,8 +2,6 @@
 
 // ignore-wasm32-bare
 
-#![feature(nll)]
-
 fn match_guard(x: Option<&&i32>, c: bool) -> i32 {
     match x {
         Some(0) if c => 0,
diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs
index f6e6c6baf7a..35512b94c0c 100644
--- a/src/test/mir-opt/simplify_if.rs
+++ b/src/test/mir-opt/simplify_if.rs
@@ -5,13 +5,15 @@ fn main() {
 }
 
 // END RUST SOURCE
-// START rustc.main.SimplifyBranches-initial.before.mir
+// START rustc.main.SimplifyBranches-after-const-prop.before.mir
 // bb0: {
-//     switchInt(const false) -> [false: bb3, otherwise: bb2];
+//     ...
+//     switchInt(const false) -> [false: bb3, otherwise: bb1];
 // }
-// END rustc.main.SimplifyBranches-initial.before.mir
-// START rustc.main.SimplifyBranches-initial.after.mir
+// END rustc.main.SimplifyBranches-after-const-prop.before.mir
+// START rustc.main.SimplifyBranches-after-const-prop.after.mir
 // bb0: {
+//     ...
 //     goto -> bb3;
 // }
-// END rustc.main.SimplifyBranches-initial.after.mir
+// END rustc.main.SimplifyBranches-after-const-prop.after.mir
diff --git a/src/test/run-fail/issue-51345.rs b/src/test/run-fail/issue-51345.rs
index 3c7f6a68db5..c62f98ea78d 100644
--- a/src/test/run-fail/issue-51345.rs
+++ b/src/test/run-fail/issue-51345.rs
@@ -1,7 +1,5 @@
 // error-pattern: thread 'main' panicked at 'explicit panic'
 
-#![feature(nll)]
-
 fn main() {
     let mut vec = vec![];
     vec.push((vec.len(), panic!()));
diff --git a/src/test/run-make-fulldeps/issue-14500/Makefile b/src/test/run-make-fulldeps/issue-14500/Makefile
index bd94db09520..0c0e331da1d 100644
--- a/src/test/run-make-fulldeps/issue-14500/Makefile
+++ b/src/test/run-make-fulldeps/issue-14500/Makefile
@@ -6,10 +6,6 @@
 # is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
 # only way that `foo.c` will successfully compile.
 
-ifeq ($(UNAME),Bitrig)
-	EXTRACFLAGS := -lc $(EXTRACFLAGS) $(EXTRACXXFLAGS)
-endif
-
 all:
 	$(RUSTC) foo.rs --crate-type=rlib
 	$(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
diff --git a/src/test/run-make-fulldeps/link-cfg/Makefile b/src/test/run-make-fulldeps/link-cfg/Makefile
index 188cba5fe41..2701b4a593c 100644
--- a/src/test/run-make-fulldeps/link-cfg/Makefile
+++ b/src/test/run-make-fulldeps/link-cfg/Makefile
@@ -2,7 +2,7 @@
 
 all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3)
 	ls $(TMPDIR)
-	$(RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static
+	$(BARE_RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static
 
 	$(RUSTC) no-deps.rs --cfg foo
 	$(call RUN,no-deps)
diff --git a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile
index 3fffd1e7aa2..b47ce17ec8b 100644
--- a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile
+++ b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile
@@ -20,4 +20,4 @@ all:
 	$(RUSTC) library.rs
 	mkdir $(bad_dir)
 	mv $(TMPDIR)/liblibrary.a $(bad_dir)
-	LIBRARY_PATH=$(bad_dir) $(RUSTC) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined
+	$(RUSTC) -L $(bad_dir) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined
diff --git a/src/test/run-make-fulldeps/reproducible-build/Makefile b/src/test/run-make-fulldeps/reproducible-build/Makefile
index ca76a5e5d77..a17ec212cfd 100644
--- a/src/test/run-make-fulldeps/reproducible-build/Makefile
+++ b/src/test/run-make-fulldeps/reproducible-build/Makefile
@@ -1,4 +1,8 @@
 -include ../tools.mk
+
+# ignore-musl
+# Objects are reproducible but their path is not.
+
 all:  \
 	smoke \
 	debug \
diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk
index 4b9ab0b7c23..3b4df73cdfd 100644
--- a/src/test/run-make-fulldeps/tools.mk
+++ b/src/test/run-make-fulldeps/tools.mk
@@ -88,10 +88,6 @@ else
 ifeq ($(UNAME),FreeBSD)
 	EXTRACFLAGS := -lm -lpthread -lgcc_s
 else
-ifeq ($(UNAME),Bitrig)
-	EXTRACFLAGS := -lm -lpthread
-	EXTRACXXFLAGS := -lc++ -lc++abi
-else
 ifeq ($(UNAME),SunOS)
 	EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
 else
@@ -106,7 +102,6 @@ endif
 endif
 endif
 endif
-endif
 
 REMOVE_DYLIBS     = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1))
 REMOVE_RLIBS      = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))
diff --git a/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile b/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile
index 3976da31131..838b1a2719b 100644
--- a/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile
+++ b/src/test/run-make-fulldeps/use-extern-for-plugins/Makefile
@@ -2,7 +2,6 @@
 
 # ignore-freebsd
 # ignore-openbsd
-# ignore-bitrig
 # ignore-sunos
 
 HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //')
diff --git a/src/test/run-make/rustc-macro-dep-files/Makefile b/src/test/run-make/rustc-macro-dep-files/Makefile
index 0420a389168..a08a63fb44b 100644
--- a/src/test/run-make/rustc-macro-dep-files/Makefile
+++ b/src/test/run-make/rustc-macro-dep-files/Makefile
@@ -2,7 +2,10 @@
 
 # FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
 # instead of hardcoding them everywhere they're needed.
+ifeq ($(IS_MUSL_HOST),1)
+ADDITIONAL_ARGS := $(RUSTFLAGS)
+endif
 all:
-	$(BARE_RUSTC) foo.rs --out-dir $(TMPDIR)
+	$(BARE_RUSTC) $(ADDITIONAL_ARGS) foo.rs --out-dir $(TMPDIR)
 	$(RUSTC) bar.rs --target $(TARGET) --emit dep-info
 	$(CGREP) -v "proc-macro source" < $(TMPDIR)/bar.d
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs
index 699972c9a85..c6b33fbc75e 100644
--- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs
@@ -14,7 +14,7 @@ use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable};
 use syntax::ext::build::AstBuilder;
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
 use syntax::ptr::P;
 use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure};
 use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching};
@@ -71,7 +71,7 @@ fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span,
     };
 
     fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| {
-        if attr::contains_name(&item.attrs, "ignore") {
+        if attr::contains_name(&item.attrs, sym::ignore) {
             acc
         } else {
             cx.expr_binary(item.span, ast::BinOpKind::Add, acc,
diff --git a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs
index 76d0906f97c..40e0115c623 100644
--- a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs
@@ -23,7 +23,7 @@ use syntax::{ast, source_map};
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
     reg.register_late_lint_pass(box MissingWhitelistedAttrPass);
-    reg.register_attribute("whitelisted_attr".to_string(), Whitelisted);
+    reg.register_attribute(Symbol::intern("whitelisted_attr"), Whitelisted);
 }
 
 declare_lint! {
@@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass {
             _ => cx.tcx.hir().expect_item_by_hir_id(cx.tcx.hir().get_parent_item(id)),
         };
 
-        if !attr::contains_name(&item.attrs, "whitelisted_attr") {
+        if !attr::contains_name(&item.attrs, Symbol::intern("whitelisted_attr")) {
             cx.span_lint(MISSING_WHITELISTED_ATTR, span,
                          "Missing 'whitelisted_attr' attribute");
         }
diff --git a/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs
index f34e10218d4..8c7bd7222e7 100644
--- a/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs
@@ -11,6 +11,7 @@ use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPass
 use rustc_plugin::Registry;
 use rustc::hir;
 use syntax::attr;
+use syntax::symbol::Symbol;
 
 macro_rules! fake_lint_pass {
     ($struct:ident, $lints:expr, $($attr:expr),*) => {
@@ -49,19 +50,19 @@ declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]");
 fake_lint_pass! {
     PassOkay,
     lint_array!(CRATE_NOT_OKAY), // Single lint
-    "rustc_crate_okay"
+    Symbol::intern("rustc_crate_okay")
 }
 
 fake_lint_pass! {
     PassRedBlue,
     lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints
-    "rustc_crate_red", "rustc_crate_blue"
+    Symbol::intern("rustc_crate_red"), Symbol::intern("rustc_crate_blue")
 }
 
 fake_lint_pass! {
     PassGreyGreen,
     lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma
-    "rustc_crate_grey", "rustc_crate_green"
+    Symbol::intern("rustc_crate_grey"), Symbol::intern("rustc_crate_green")
 }
 
 #[plugin_registrar]
diff --git a/src/test/run-pass-valgrind/exit-flushes.rs b/src/test/run-pass-valgrind/exit-flushes.rs
index c4d23c2938d..cd5edb84bdf 100644
--- a/src/test/run-pass-valgrind/exit-flushes.rs
+++ b/src/test/run-pass-valgrind/exit-flushes.rs
@@ -1,6 +1,7 @@
 // no-prefer-dynamic
 // ignore-cloudabi
 // ignore-emscripten
+// ignore-sgx no processes
 // ignore-macos this needs valgrind 3.11 or higher; see
 // https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679
 
diff --git a/src/test/run-pass/abort-on-c-abi.rs b/src/test/run-pass/abort-on-c-abi.rs
index df94cd57186..110f3eee1ef 100644
--- a/src/test/run-pass/abort-on-c-abi.rs
+++ b/src/test/run-pass/abort-on-c-abi.rs
@@ -4,6 +4,7 @@
 
 // ignore-cloudabi no env and process
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::{env, panic};
 use std::io::prelude::*;
diff --git a/src/test/run-pass/atomic-print.rs b/src/test/run-pass/atomic-print.rs
index 566aeeb2c39..ee76ef9b25f 100644
--- a/src/test/run-pass/atomic-print.rs
+++ b/src/test/run-pass/atomic-print.rs
@@ -2,6 +2,7 @@
 #![allow(deprecated)]
 // ignore-cloudabi no process support
 // ignore-emscripten no threads support
+// ignore-sgx no processes
 
 use std::{env, fmt, process, sync, thread};
 
diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs
index 7f038ddecc1..69ce1f70322 100644
--- a/src/test/run-pass/backtrace-debuginfo.rs
+++ b/src/test/run-pass/backtrace-debuginfo.rs
@@ -11,6 +11,7 @@
 // ignore-cloudabi spawning processes is not supported
 // ignore-emscripten spawning processes is not supported
 // normalize-stderr-test ".*\n" -> ""
+// ignore-sgx no processes
 
 // Note that above `-opt-bisect-limit=0` is used to basically disable
 // optimizations. It creates tons of output on stderr, hence we normalize
@@ -32,7 +33,6 @@ macro_rules! dump_and_die {
                     all(target_os = "linux", target_arch = "arm"),
                     target_os = "freebsd",
                     target_os = "dragonfly",
-                    target_os = "bitrig",
                     target_os = "openbsd")) {
             // skip these platforms as this support isn't implemented yet.
         } else {
diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs
index da3871aba09..5f6198aff50 100644
--- a/src/test/run-pass/backtrace.rs
+++ b/src/test/run-pass/backtrace.rs
@@ -2,6 +2,7 @@
 // ignore-cloudabi spawning processes is not supported
 // ignore-emscripten spawning processes is not supported
 // ignore-openbsd no support for libbacktrace without filename
+// ignore-sgx no processes
 // compile-flags:-g
 
 use std::env;
diff --git a/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs b/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs
index c953bed26f4..96d2663500e 100644
--- a/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs
+++ b/src/test/run-pass/borrowck/borrowck-multiple-borrows-interior-boxes.rs
@@ -3,8 +3,6 @@
 #![allow(unused_variables)]
 // Test case from #39963.
 
-#![feature(nll)]
-
 #[derive(Clone)]
 struct Foo(Option<Box<Foo>>, Option<Box<Foo>>);
 
diff --git a/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs
index 8f0434c0e2b..fd0e346e2b4 100644
--- a/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs
+++ b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(nll)]
 #![deny(unused_mut)]
 
 #[derive(Debug)]
diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs
index 5e1d436e31b..1242ae307d3 100644
--- a/src/test/run-pass/borrowck/two-phase-bin-ops.rs
+++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs
@@ -1,8 +1,4 @@
 // run-pass
-// revisions: lxl nll
-
-#![cfg_attr(nll, feature(nll))]
-
 use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
 use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
 
diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs
index f376bb7fde2..ec162b40bf8 100644
--- a/src/test/run-pass/c-stack-returning-int64.rs
+++ b/src/test/run-pass/c-stack-returning-int64.rs
@@ -1,4 +1,5 @@
 // ignore-wasm32-bare no libc to test with
+// ignore-sgx no libc
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/cfg/cfg-family.rs b/src/test/run-pass/cfg/cfg-family.rs
index 282ac4abcee..9fb7c766921 100644
--- a/src/test/run-pass/cfg/cfg-family.rs
+++ b/src/test/run-pass/cfg/cfg-family.rs
@@ -2,6 +2,7 @@
 // pretty-expanded FIXME #23616
 // ignore-cloudabi no target_family
 // ignore-wasm32-bare no target_family
+// ignore-sgx
 
 #[cfg(windows)]
 pub fn main() {
diff --git a/src/test/run-pass/cfg/cfg-target-family.rs b/src/test/run-pass/cfg/cfg-target-family.rs
index 2cd0ba5bf88..ecf802f7281 100644
--- a/src/test/run-pass/cfg/cfg-target-family.rs
+++ b/src/test/run-pass/cfg/cfg-target-family.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no target_family
 // ignore-wasm32-bare no target_family
+// ignore-sgx
 
 // pretty-expanded FIXME #23616
 
diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs
index ab3d3ebbaad..aa5a3a37705 100644
--- a/src/test/run-pass/command-exec.rs
+++ b/src/test/run-pass/command-exec.rs
@@ -3,6 +3,7 @@
 // ignore-pretty issue #37199
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 #![feature(process_exec)]
 
diff --git a/src/test/run-pass/command-pre-exec.rs b/src/test/run-pass/command-pre-exec.rs
index 21783fedd39..5c3cc31de58 100644
--- a/src/test/run-pass/command-pre-exec.rs
+++ b/src/test/run-pass/command-pre-exec.rs
@@ -2,6 +2,7 @@
 // ignore-windows - this is a unix-specific test
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 #![feature(process_exec, rustc_private)]
 
 extern crate libc;
diff --git a/src/test/run-pass/consts/const-ptr-nonnull.rs b/src/test/run-pass/consts/const-ptr-nonnull.rs
index 91624e92fbe..c5b9d837b47 100644
--- a/src/test/run-pass/consts/const-ptr-nonnull.rs
+++ b/src/test/run-pass/consts/const-ptr-nonnull.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(const_ptr_nonnull)]
-
 use std::ptr::NonNull;
 
 const DANGLING: NonNull<u32> = NonNull::dangling();
diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs
index 55d389952cc..625e5179381 100644
--- a/src/test/run-pass/core-run-destroy.rs
+++ b/src/test/run-pass/core-run-destroy.rs
@@ -5,6 +5,7 @@
 // compile-flags:--test
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 // N.B., these tests kill child processes. Valgrind sees these children as leaking
 // memory, which makes for some *confusing* logs. That's why these are here
diff --git a/src/test/run-pass/default-alloc-error-hook.rs b/src/test/run-pass/default-alloc-error-hook.rs
index 8dcc8ad5433..7d1624320e6 100644
--- a/src/test/run-pass/default-alloc-error-hook.rs
+++ b/src/test/run-pass/default-alloc-error-hook.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::alloc::{Layout, handle_alloc_error};
 use std::env;
diff --git a/src/test/run-pass/dupe-first-attr.rc b/src/test/run-pass/dupe-first-attr.rc
index cb6a82a15da..8b7025b7be7 100644
--- a/src/test/run-pass/dupe-first-attr.rc
+++ b/src/test/run-pass/dupe-first-attr.rc
@@ -18,9 +18,6 @@ mod hello;
 #[cfg(target_os = "dragonfly")]
 mod hello;
 
-#[cfg(target_os = "bitrig")]
-mod hello;
-
 #[cfg(target_os = "android")]
 mod hello;
 
diff --git a/src/test/run-pass/env-args-reverse-iterator.rs b/src/test/run-pass/env-args-reverse-iterator.rs
index 78548fd9bc5..d677aa85001 100644
--- a/src/test/run-pass/env-args-reverse-iterator.rs
+++ b/src/test/run-pass/env-args-reverse-iterator.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env::args;
 use std::process::Command;
diff --git a/src/test/run-pass/env-funky-keys.rs b/src/test/run-pass/env-funky-keys.rs
index 79f32bd6c29..3b236e2b3af 100644
--- a/src/test/run-pass/env-funky-keys.rs
+++ b/src/test/run-pass/env-funky-keys.rs
@@ -4,6 +4,7 @@
 // ignore-windows
 // ignore-cloudabi no execve
 // ignore-emscripten no execve
+// ignore-sgx no execve
 // no-prefer-dynamic
 
 #![feature(rustc_private)]
diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs
index 90b75344730..62f45d0a2eb 100644
--- a/src/test/run-pass/env-home-dir.rs
+++ b/src/test/run-pass/env-home-dir.rs
@@ -2,6 +2,7 @@
 #![allow(deprecated)]
 // ignore-cloudabi no environment variables present
 // ignore-emscripten env vars don't work?
+// ignore-sgx env vars cannot be modified
 
 use std::env::*;
 use std::path::PathBuf;
diff --git a/src/test/run-pass/exec-env.rs b/src/test/run-pass/exec-env.rs
index 1327b558fc9..c1b8e082514 100644
--- a/src/test/run-pass/exec-env.rs
+++ b/src/test/run-pass/exec-env.rs
@@ -1,6 +1,7 @@
 // exec-env:TEST_EXEC_ENV=22
 // ignore-cloudabi no env vars
 // ignore-emscripten FIXME: issue #31622
+// ignore-sgx unsupported
 
 use std::env;
 
diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs
index 3bc0ceb5cf2..c4091f84af9 100644
--- a/src/test/run-pass/fds-are-cloexec.rs
+++ b/src/test/run-pass/fds-are-cloexec.rs
@@ -3,6 +3,7 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
 // ignore-haiku
+// ignore-sgx no processes
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/foreign/foreign-fn-linkname.rs b/src/test/run-pass/foreign/foreign-fn-linkname.rs
index 5ed8d19bc5a..1f048159064 100644
--- a/src/test/run-pass/foreign/foreign-fn-linkname.rs
+++ b/src/test/run-pass/foreign/foreign-fn-linkname.rs
@@ -1,5 +1,6 @@
 // run-pass
 // ignore-wasm32-bare no libc to test ffi with
+// ignore-sgx no libc
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/functions-closures/parallel-codegen-closures.rs b/src/test/run-pass/functions-closures/parallel-codegen-closures.rs
index 921fbaf4942..79759daba50 100644
--- a/src/test/run-pass/functions-closures/parallel-codegen-closures.rs
+++ b/src/test/run-pass/functions-closures/parallel-codegen-closures.rs
@@ -6,7 +6,6 @@
 // Tests parallel codegen - this can fail if the symbol for the anonymous
 // closure in `sum` pollutes the second codegen unit from the first.
 
-// ignore-bitrig
 // compile-flags: -C codegen_units=2
 
 #![feature(iter_arith)]
diff --git a/src/test/run-pass/if-ret.stderr b/src/test/run-pass/if-ret.stderr
new file mode 100644
index 00000000000..a64281833e5
--- /dev/null
+++ b/src/test/run-pass/if-ret.stderr
@@ -0,0 +1,8 @@
+warning: unreachable block in `if` expression
+  --> $DIR/if-ret.rs:4:24
+   |
+LL | fn foo() { if (return) { } }
+   |                        ^^^
+   |
+   = note: #[warn(unreachable_code)] on by default
+
diff --git a/src/test/run-pass/impl-trait-in-bindings.rs b/src/test/run-pass/impl-trait-in-bindings.rs
index 9a1f53b4893..1e3a641b7cf 100644
--- a/src/test/run-pass/impl-trait-in-bindings.rs
+++ b/src/test/run-pass/impl-trait-in-bindings.rs
@@ -1,4 +1,5 @@
 #![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
 
 use std::fmt::Debug;
 
diff --git a/src/test/run-pass/impl-trait-in-bindings.stderr b/src/test/run-pass/impl-trait-in-bindings.stderr
new file mode 100644
index 00000000000..4896deb9d5c
--- /dev/null
+++ b/src/test/run-pass/impl-trait-in-bindings.stderr
@@ -0,0 +1,6 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/impl-trait-in-bindings.rs:1:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs
index 5a21e1dd817..9a9843375e4 100644
--- a/src/test/run-pass/impl-trait/lifetimes.rs
+++ b/src/test/run-pass/impl-trait/lifetimes.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![allow(warnings)]
+#![feature(generators)]
 
 use std::fmt::Debug;
 
@@ -112,6 +113,11 @@ impl<'unnecessary_lifetime> MyVec {
     fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator<Item = &'s u8> {
         self.0.iter().flat_map(|inner_vec| inner_vec.iter())
     }
+
+    fn generator_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized {
+        || yield
+    }
 }
 
+
 fn main() {}
diff --git a/src/test/run-pass/inherit-env.rs b/src/test/run-pass/inherit-env.rs
index 8e2401d0c03..229953f1b18 100644
--- a/src/test/run-pass/inherit-env.rs
+++ b/src/test/run-pass/inherit-env.rs
@@ -1,5 +1,6 @@
 // ignore-emscripten
 // ignore-wasm32
+// ignore-sgx no processes
 
 use std::env;
 use std::process::Command;
diff --git a/src/test/run-pass/intrinsics/intrinsic-alignment.rs b/src/test/run-pass/intrinsics/intrinsic-alignment.rs
index 19e56710620..6a67d04a54c 100644
--- a/src/test/run-pass/intrinsics/intrinsic-alignment.rs
+++ b/src/test/run-pass/intrinsics/intrinsic-alignment.rs
@@ -40,7 +40,7 @@ mod m {
     }
 }
 
-#[cfg(target_os = "bitrig")]
+#[cfg(target_env = "sgx")]
 mod m {
     #[main]
     #[cfg(target_arch = "x86_64")]
diff --git a/src/test/run-pass/invalid_const_promotion.rs b/src/test/run-pass/invalid_const_promotion.rs
index 2775aac0156..ddf4dc42424 100644
--- a/src/test/run-pass/invalid_const_promotion.rs
+++ b/src/test/run-pass/invalid_const_promotion.rs
@@ -1,6 +1,7 @@
 #![allow(unused_mut)]
 // ignore-wasm32
 // ignore-emscripten
+// ignore-sgx no processes
 
 // compile-flags: -C debug_assertions=yes
 
diff --git a/src/test/run-pass/issue-59020.rs b/src/test/run-pass/issue-59020.rs
index a2b11764a2f..e7544934da0 100644
--- a/src/test/run-pass/issue-59020.rs
+++ b/src/test/run-pass/issue-59020.rs
@@ -1,6 +1,7 @@
 // edition:2018
 // run-pass
 // ignore-emscripten no threads support
+// ignore-sgx no thread sleep support
 
 use std::thread;
 use std::time::Duration;
diff --git a/src/test/run-pass/issues/issue-10626.rs b/src/test/run-pass/issues/issue-10626.rs
index 9c10fd2cea6..78fa8b7c6fb 100644
--- a/src/test/run-pass/issues/issue-10626.rs
+++ b/src/test/run-pass/issues/issue-10626.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 // Make sure that if a process doesn't have its stdio/stderr descriptors set up
 // that we don't die in a large ball of fire
diff --git a/src/test/run-pass/issues/issue-12133-3.rs b/src/test/run-pass/issues/issue-12133-3.rs
index c87a37ab6b7..c8aa9bf4649 100644
--- a/src/test/run-pass/issues/issue-12133-3.rs
+++ b/src/test/run-pass/issues/issue-12133-3.rs
@@ -5,6 +5,7 @@
 // ignore-cloudabi no dylib support
 // ignore-emscripten no dylib support
 // ignore-musl
+// ignore-sgx no dylib support
 
 // pretty-expanded FIXME #23616
 
diff --git a/src/test/run-pass/issues/issue-12699.rs b/src/test/run-pass/issues/issue-12699.rs
index b23853074fa..e26c2d7cde2 100644
--- a/src/test/run-pass/issues/issue-12699.rs
+++ b/src/test/run-pass/issues/issue-12699.rs
@@ -1,5 +1,6 @@
 // run-pass
 // ignore-wasm32-bare can't block the thread
+// ignore-sgx not supported
 #![allow(deprecated)]
 
 use std::thread;
diff --git a/src/test/run-pass/issues/issue-13304.rs b/src/test/run-pass/issues/issue-13304.rs
index cd74ce38dea..5698536ab5d 100644
--- a/src/test/run-pass/issues/issue-13304.rs
+++ b/src/test/run-pass/issues/issue-13304.rs
@@ -2,6 +2,7 @@
 #![allow(unused_mut)]
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::io::prelude::*;
diff --git a/src/test/run-pass/issues/issue-13494.rs b/src/test/run-pass/issues/issue-13494.rs
deleted file mode 100644
index 12be97702a9..00000000000
--- a/src/test/run-pass/issues/issue-13494.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// run-pass
-#![allow(unused_must_use)]
-// ignore-emscripten no threads support
-
-// This test may not always fail, but it can be flaky if the race it used to
-// expose is still present.
-
-#![feature(mpsc_select)]
-#![allow(deprecated)]
-
-use std::sync::mpsc::{channel, Sender, Receiver};
-use std::thread;
-
-fn helper(rx: Receiver<Sender<()>>) {
-    for tx in rx.iter() {
-        let _ = tx.send(());
-    }
-}
-
-fn main() {
-    let (tx, rx) = channel();
-    let t = thread::spawn(move|| { helper(rx) });
-    let (snd, rcv) = channel::<isize>();
-    for _ in 1..100000 {
-        snd.send(1).unwrap();
-        let (tx2, rx2) = channel();
-        tx.send(tx2).unwrap();
-        select! {
-            _ = rx2.recv() => (),
-            _ = rcv.recv() => ()
-        }
-    }
-    drop(tx);
-    t.join();
-}
diff --git a/src/test/run-pass/issues/issue-14456.rs b/src/test/run-pass/issues/issue-14456.rs
index 23347d35178..164d7ef8af2 100644
--- a/src/test/run-pass/issues/issue-14456.rs
+++ b/src/test/run-pass/issues/issue-14456.rs
@@ -2,6 +2,7 @@
 #![allow(unused_mut)]
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::io::prelude::*;
diff --git a/src/test/run-pass/issues/issue-14940.rs b/src/test/run-pass/issues/issue-14940.rs
index ce47a623f00..785ad6a2c49 100644
--- a/src/test/run-pass/issues/issue-14940.rs
+++ b/src/test/run-pass/issues/issue-14940.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::process::Command;
diff --git a/src/test/run-pass/issues/issue-16272.rs b/src/test/run-pass/issues/issue-16272.rs
index a2570e763f6..3ba2483f430 100644
--- a/src/test/run-pass/issues/issue-16272.rs
+++ b/src/test/run-pass/issues/issue-16272.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/issues/issue-2214.rs b/src/test/run-pass/issues/issue-2214.rs
index 6e538f711de..22f33545cb9 100644
--- a/src/test/run-pass/issues/issue-2214.rs
+++ b/src/test/run-pass/issues/issue-2214.rs
@@ -1,6 +1,6 @@
 // run-pass
 // ignore-wasm32-bare no libc to test ffi with
-
+// ignore-sgx no libc
 #![feature(rustc_private)]
 
 extern crate libc;
diff --git a/src/test/run-pass/issues/issue-24313.rs b/src/test/run-pass/issues/issue-24313.rs
index ddcf1d04511..2c420dc056f 100644
--- a/src/test/run-pass/issues/issue-24313.rs
+++ b/src/test/run-pass/issues/issue-24313.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no threads
+// ignore-sgx no processes
 
 use std::thread;
 use std::env;
diff --git a/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs b/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs
index 68f7dfd38f4..48362d0bb62 100644
--- a/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs
+++ b/src/test/run-pass/issues/issue-24535-allow-mutable-borrow-in-match-guard.rs
@@ -5,7 +5,6 @@
 // See further discussion on rust-lang/rust#24535,
 // rust-lang/rfcs#1006, and rust-lang/rfcs#107
 
-#![feature(nll)]
 #![feature(bind_by_move_pattern_guards)]
 
 fn main() {
diff --git a/src/test/run-pass/issues/issue-30490.rs b/src/test/run-pass/issues/issue-30490.rs
index 231d41cd86a..76e72246887 100644
--- a/src/test/run-pass/issues/issue-30490.rs
+++ b/src/test/run-pass/issues/issue-30490.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 // Previously libstd would set stdio descriptors of a child process
 // by `dup`ing the requested descriptors to inherit directly into the
diff --git a/src/test/run-pass/issues/issue-33770.rs b/src/test/run-pass/issues/issue-33770.rs
index 7962509003f..39ae009c996 100644
--- a/src/test/run-pass/issues/issue-33770.rs
+++ b/src/test/run-pass/issues/issue-33770.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::process::{Command, Stdio};
 use std::env;
diff --git a/src/test/run-pass/issues/issue-48962.rs b/src/test/run-pass/issues/issue-48962.rs
index 7c644789834..80d815379be 100644
--- a/src/test/run-pass/issues/issue-48962.rs
+++ b/src/test/run-pass/issues/issue-48962.rs
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(unused_must_use)]
 // Test that we are able to reinitialize box with moved referent
-#![feature(nll)]
 static mut ORDER: [usize; 3] = [0, 0, 0];
 static mut INDEX: usize = 0;
 
diff --git a/src/test/run-pass/issues/issue-51345.rs b/src/test/run-pass/issues/issue-51345.rs
index 29a0a328503..15571e8bf5b 100644
--- a/src/test/run-pass/issues/issue-51345.rs
+++ b/src/test/run-pass/issues/issue-51345.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unreachable_code)]
-#![feature(nll)]
 
 fn main() {
     let mut v = Vec::new();
diff --git a/src/test/run-pass/issues/issue-9396.rs b/src/test/run-pass/issues/issue-9396.rs
index 3e7e9a51cdd..27b5185377d 100644
--- a/src/test/run-pass/issues/issue-9396.rs
+++ b/src/test/run-pass/issues/issue-9396.rs
@@ -2,6 +2,7 @@
 #![allow(unused_must_use)]
 #![allow(deprecated)]
 // ignore-emscripten no threads support
+// ignore-sgx no thread sleep support
 
 use std::sync::mpsc::{TryRecvError, channel};
 use std::thread;
diff --git a/src/test/run-pass/linkage1.rs b/src/test/run-pass/linkage1.rs
index 4e404f26eec..da07385ead7 100644
--- a/src/test/run-pass/linkage1.rs
+++ b/src/test/run-pass/linkage1.rs
@@ -1,6 +1,7 @@
 // ignore-windows
 // ignore-macos
 // ignore-emscripten doesn't support this linkage
+// ignore-sgx weak linkage not permitted
 // aux-build:linkage1.rs
 
 #![feature(linkage)]
diff --git a/src/test/run-pass/macros/macro-comma-support.rs b/src/test/run-pass/macros/macro-comma-support.rs
index 904f2e2c7fd..12a612c153a 100644
--- a/src/test/run-pass/macros/macro-comma-support.rs
+++ b/src/test/run-pass/macros/macro-comma-support.rs
@@ -233,8 +233,6 @@ fn println() {
     println!("hello {}", "world",);
 }
 
-// select! is too troublesome and unlikely to be stabilized
-
 // stringify! is N/A
 
 #[cfg(std)]
diff --git a/src/test/run-pass/mpsc_stress.rs b/src/test/run-pass/mpsc_stress.rs
index cd30dd62bc4..cf8d92b2278 100644
--- a/src/test/run-pass/mpsc_stress.rs
+++ b/src/test/run-pass/mpsc_stress.rs
@@ -1,5 +1,6 @@
 // compile-flags:--test
 // ignore-emscripten
+// ignore-sgx no thread sleep support
 
 use std::sync::mpsc::channel;
 use std::sync::mpsc::TryRecvError;
diff --git a/src/test/run-pass/multi-panic.rs b/src/test/run-pass/multi-panic.rs
index 3f24d989c8c..900b2b2206f 100644
--- a/src/test/run-pass/multi-panic.rs
+++ b/src/test/run-pass/multi-panic.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 fn check_for_no_backtrace(test: std::process::Output) {
     assert!(!test.status.success());
diff --git a/src/test/run-pass/nll/issue-47153-generic-const.rs b/src/test/run-pass/nll/issue-47153-generic-const.rs
index 4f021fda4e3..9f4d57111bb 100644
--- a/src/test/run-pass/nll/issue-47153-generic-const.rs
+++ b/src/test/run-pass/nll/issue-47153-generic-const.rs
@@ -3,7 +3,6 @@
 // Regression test for #47153: constants in a generic context (such as
 // a trait) used to ICE.
 
-#![feature(nll)]
 #![allow(warnings)]
 
 trait Foo {
diff --git a/src/test/run-pass/nll/issue-47589.rs b/src/test/run-pass/nll/issue-47589.rs
index 5bbed3a8590..280bf081138 100644
--- a/src/test/run-pass/nll/issue-47589.rs
+++ b/src/test/run-pass/nll/issue-47589.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(nll)]
-
 pub struct DescriptorSet<'a> {
     pub slots: Vec<AttachInfo<'a, Resources>>
 }
diff --git a/src/test/run-pass/nll/issue-48623-closure.rs b/src/test/run-pass/nll/issue-48623-closure.rs
index 5a41fff11a1..3f8587eed41 100644
--- a/src/test/run-pass/nll/issue-48623-closure.rs
+++ b/src/test/run-pass/nll/issue-48623-closure.rs
@@ -2,8 +2,6 @@
 #![allow(path_statements)]
 #![allow(dead_code)]
 
-#![feature(nll)]
-
 struct WithDrop;
 
 impl Drop for WithDrop {
diff --git a/src/test/run-pass/nll/issue-48623-generator.rs b/src/test/run-pass/nll/issue-48623-generator.rs
index b404daca725..ba3eccff495 100644
--- a/src/test/run-pass/nll/issue-48623-generator.rs
+++ b/src/test/run-pass/nll/issue-48623-generator.rs
@@ -2,7 +2,6 @@
 #![allow(path_statements)]
 #![allow(dead_code)]
 
-#![feature(nll)]
 #![feature(generators, generator_trait)]
 
 struct WithDrop;
diff --git a/src/test/run-pass/nll/issue-50343.rs b/src/test/run-pass/nll/issue-50343.rs
index 8d2992b3b4f..55a2d231e19 100644
--- a/src/test/run-pass/nll/issue-50343.rs
+++ b/src/test/run-pass/nll/issue-50343.rs
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(nll)]
 #![deny(unused_mut)]
 
 fn main() {
diff --git a/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs
index dc5257cfb92..69d7cdd83a6 100644
--- a/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs
+++ b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(nll)]
 #![deny(unused_mut)]
 
 struct Foo {
diff --git a/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs b/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs
index c3f818812aa..941c9eeb411 100644
--- a/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs
+++ b/src/test/run-pass/nll/issue-53123-raw-pointer-cast.rs
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(nll)]
 #![allow(unused_variables)]
 
 pub trait TryTransform {
diff --git a/src/test/run-pass/nll/mutating_references.rs b/src/test/run-pass/nll/mutating_references.rs
index 0af8751494e..eb46b30b6b9 100644
--- a/src/test/run-pass/nll/mutating_references.rs
+++ b/src/test/run-pass/nll/mutating_references.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(nll)]
-
 struct List<T> {
     value: T,
     next: Option<Box<List<T>>>,
diff --git a/src/test/run-pass/nll/process_or_insert_default.rs b/src/test/run-pass/nll/process_or_insert_default.rs
index e9cd4014bc3..84ac9bbd0dd 100644
--- a/src/test/run-pass/nll/process_or_insert_default.rs
+++ b/src/test/run-pass/nll/process_or_insert_default.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(nll)]
-
 use std::collections::HashMap;
 
 fn process_or_insert_default(map: &mut HashMap<usize, String>, key: usize) {
diff --git a/src/test/run-pass/nll/rc-loop.rs b/src/test/run-pass/nll/rc-loop.rs
index a4ef546c25f..e59303d1f78 100644
--- a/src/test/run-pass/nll/rc-loop.rs
+++ b/src/test/run-pass/nll/rc-loop.rs
@@ -6,8 +6,6 @@
 // `x`.  The lexical checker makes this very painful. The NLL checker
 // does not.
 
-#![feature(nll)]
-
 use std::rc::Rc;
 
 #[derive(Debug, PartialEq, Eq)]
diff --git a/src/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs
index 005781e1d2f..aae1d0b7f81 100644
--- a/src/test/run-pass/no-stdio.rs
+++ b/src/test/run-pass/no-stdio.rs
@@ -1,6 +1,7 @@
 // ignore-android
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs
index 9f868d6e5c3..f03935e3d27 100644
--- a/src/test/run-pass/out-of-stack.rs
+++ b/src/test/run-pass/out-of-stack.rs
@@ -4,6 +4,7 @@
 // ignore-musl
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 #![feature(asm)]
 #![feature(rustc_private)]
diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
index e2dbb0d175d..9c099911eab 100644
--- a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
+++ b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs
@@ -5,6 +5,7 @@
 // no-prefer-dynamic
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 // ignore-macos
 
 extern crate exit_success_if_unwind;
diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs
index 719034bd11e..f625fe35d72 100644
--- a/src/test/run-pass/panic-runtime/abort.rs
+++ b/src/test/run-pass/panic-runtime/abort.rs
@@ -4,6 +4,7 @@
 // no-prefer-dynamic
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 // ignore-macos
 
 use std::process::Command;
diff --git a/src/test/run-pass/panic-runtime/lto-abort.rs b/src/test/run-pass/panic-runtime/lto-abort.rs
index 9015a8f25a9..8fff71a629a 100644
--- a/src/test/run-pass/panic-runtime/lto-abort.rs
+++ b/src/test/run-pass/panic-runtime/lto-abort.rs
@@ -4,6 +4,7 @@
 // no-prefer-dynamic
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/panic-runtime/lto-unwind.rs b/src/test/run-pass/panic-runtime/lto-unwind.rs
index b14cdfc193f..94a0b596e4a 100644
--- a/src/test/run-pass/panic-runtime/lto-unwind.rs
+++ b/src/test/run-pass/panic-runtime/lto-unwind.rs
@@ -5,6 +5,7 @@
 // no-prefer-dynamic
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs
index 3f6e489bb83..4ca4b407bd4 100644
--- a/src/test/run-pass/panic-uninitialized-zeroed.rs
+++ b/src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -2,7 +2,7 @@
 // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
 // in a runtime panic.
 
-#![feature(never_type, maybe_uninit)]
+#![feature(never_type)]
 
 use std::{mem, panic};
 
diff --git a/src/test/run-pass/paths-containing-nul.rs b/src/test/run-pass/paths-containing-nul.rs
index dfcef59aa57..64ee7319fdd 100644
--- a/src/test/run-pass/paths-containing-nul.rs
+++ b/src/test/run-pass/paths-containing-nul.rs
@@ -2,6 +2,7 @@
 // ignore-cloudabi no files or I/O
 // ignore-wasm32-bare no files or I/O
 // ignore-emscripten no files
+// ignore-sgx no files
 
 use std::fs;
 use std::io;
diff --git a/src/test/run-pass/print-stdout-eprint-stderr.rs b/src/test/run-pass/print-stdout-eprint-stderr.rs
index 9c47a734d7b..65130a1a9f2 100644
--- a/src/test/run-pass/print-stdout-eprint-stderr.rs
+++ b/src/test/run-pass/print-stdout-eprint-stderr.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi spawning processes is not supported
 // ignore-emscripten spawning processes is not supported
+// ignore-sgx no processes
 
 use std::{env, process};
 
diff --git a/src/test/run-pass/process/process-envs.rs b/src/test/run-pass/process/process-envs.rs
index 1ff0fbbdd08..a7779c55f1f 100644
--- a/src/test/run-pass/process/process-envs.rs
+++ b/src/test/run-pass/process/process-envs.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/process/process-exit.rs b/src/test/run-pass/process/process-exit.rs
index ecc7b72c0f3..da3b4ca85c2 100644
--- a/src/test/run-pass/process/process-exit.rs
+++ b/src/test/run-pass/process/process-exit.rs
@@ -2,6 +2,7 @@
 #![allow(unused_imports)]
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::process::{self, Command, Stdio};
diff --git a/src/test/run-pass/process/process-remove-from-env.rs b/src/test/run-pass/process/process-remove-from-env.rs
index 9c2aa871e0d..32cbb6ac85a 100644
--- a/src/test/run-pass/process/process-remove-from-env.rs
+++ b/src/test/run-pass/process/process-remove-from-env.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::process::Command;
 use std::env;
diff --git a/src/test/run-pass/process/process-spawn-nonexistent.rs b/src/test/run-pass/process/process-spawn-nonexistent.rs
index 2fe9f33de38..182cf1748fe 100644
--- a/src/test/run-pass/process/process-spawn-nonexistent.rs
+++ b/src/test/run-pass/process/process-spawn-nonexistent.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::io::ErrorKind;
 use std::process::Command;
diff --git a/src/test/run-pass/process/process-spawn-with-unicode-params.rs b/src/test/run-pass/process/process-spawn-with-unicode-params.rs
index e3508cb4e8f..edd3cb26ec3 100644
--- a/src/test/run-pass/process/process-spawn-with-unicode-params.rs
+++ b/src/test/run-pass/process/process-spawn-with-unicode-params.rs
@@ -9,6 +9,7 @@
 
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::io::prelude::*;
 use std::io;
diff --git a/src/test/run-pass/process/process-status-inherits-stdin.rs b/src/test/run-pass/process/process-status-inherits-stdin.rs
index e2e17b7fb66..f9b2da7e401 100644
--- a/src/test/run-pass/process/process-status-inherits-stdin.rs
+++ b/src/test/run-pass/process/process-status-inherits-stdin.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::io;
diff --git a/src/test/run-pass/rfcs/rfc-1014.rs b/src/test/run-pass/rfcs/rfc-1014.rs
index 3b7b96d0d02..41a036958bf 100644
--- a/src/test/run-pass/rfcs/rfc-1014.rs
+++ b/src/test/run-pass/rfcs/rfc-1014.rs
@@ -2,6 +2,7 @@
 #![allow(dead_code)]
 // ignore-cloudabi stdout does not map to file descriptor 1 by default
 // ignore-wasm32-bare no libc
+// ignore-sgx no libc
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs
index 7f8a0f01dde..ab1bf3a5b91 100644
--- a/src/test/run-pass/running-with-no-runtime.rs
+++ b/src/test/run-pass/running-with-no-runtime.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi spawning processes is not supported
 // ignore-emscripten spawning processes is not supported
+// ignore-sgx no processes
 
 #![feature(start)]
 
diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs
index ce485d771f0..e90efface68 100644
--- a/src/test/run-pass/segfault-no-out-of-stack.rs
+++ b/src/test/run-pass/segfault-no-out-of-stack.rs
@@ -1,6 +1,7 @@
 #![allow(unused_imports)]
 // ignore-cloudabi can't run commands
 // ignore-emscripten can't run commands
+// ignore-sgx no processes
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/sepcomp/sepcomp-cci.rs b/src/test/run-pass/sepcomp/sepcomp-cci.rs
index f5c633d250b..02bbab30e9c 100644
--- a/src/test/run-pass/sepcomp/sepcomp-cci.rs
+++ b/src/test/run-pass/sepcomp/sepcomp-cci.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-bitrig
 // compile-flags: -C codegen-units=3
 // aux-build:sepcomp_cci_lib.rs
 
diff --git a/src/test/run-pass/sepcomp/sepcomp-extern.rs b/src/test/run-pass/sepcomp/sepcomp-extern.rs
index 18af785c1be..c4ccf23c47a 100644
--- a/src/test/run-pass/sepcomp/sepcomp-extern.rs
+++ b/src/test/run-pass/sepcomp/sepcomp-extern.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-bitrig
 // compile-flags: -C codegen-units=3
 // aux-build:sepcomp-extern-lib.rs
 
diff --git a/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs b/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs
index 96bcc260bdf..f56769e2b8c 100644
--- a/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs
+++ b/src/test/run-pass/sepcomp/sepcomp-fns-backwards.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-// ignore-bitrig
 // compile-flags: -C codegen-units=3
 
 // Test references to items that haven't been codegened yet.
diff --git a/src/test/run-pass/sepcomp/sepcomp-fns.rs b/src/test/run-pass/sepcomp/sepcomp-fns.rs
index c4ea17225b4..a432c89606e 100644
--- a/src/test/run-pass/sepcomp/sepcomp-fns.rs
+++ b/src/test/run-pass/sepcomp/sepcomp-fns.rs
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-bitrig
 // compile-flags: -C codegen-units=3
 
 // Test basic separate compilation functionality.  The functions should be able
diff --git a/src/test/run-pass/sepcomp/sepcomp-statics.rs b/src/test/run-pass/sepcomp/sepcomp-statics.rs
index e0c6b268b17..5457c8a0ae9 100644
--- a/src/test/run-pass/sepcomp/sepcomp-statics.rs
+++ b/src/test/run-pass/sepcomp/sepcomp-statics.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-// ignore-bitrig
 // compile-flags: -C codegen-units=3
 
 // Test references to static items across compilation units.
diff --git a/src/test/run-pass/sepcomp/sepcomp-unwind.rs b/src/test/run-pass/sepcomp/sepcomp-unwind.rs
index 01dbea08098..50a4e043943 100644
--- a/src/test/run-pass/sepcomp/sepcomp-unwind.rs
+++ b/src/test/run-pass/sepcomp/sepcomp-unwind.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-// ignore-bitrig
 // compile-flags: -C codegen-units=3
 // ignore-emscripten no threads support
 
diff --git a/src/test/run-pass/signal-alternate-stack-cleanup.rs b/src/test/run-pass/signal-alternate-stack-cleanup.rs
index d11f3f5b5e6..6f2fa2a370d 100644
--- a/src/test/run-pass/signal-alternate-stack-cleanup.rs
+++ b/src/test/run-pass/signal-alternate-stack-cleanup.rs
@@ -5,6 +5,7 @@
 // ignore-cloudabi no signal handling support
 // ignore-wasm32-bare no libc
 // ignore-windows
+// ignore-sgx no libc
 
 #![feature(rustc_private)]
 extern crate libc;
diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs
index 9e1e55ad54d..c22c0352286 100644
--- a/src/test/run-pass/signal-exit-status.rs
+++ b/src/test/run-pass/signal-exit-status.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 // ignore-windows
 
 use std::env;
diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs
index 2ded71670d2..6c5bbd45a3c 100644
--- a/src/test/run-pass/sigpipe-should-be-ignored.rs
+++ b/src/test/run-pass/sigpipe-should-be-ignored.rs
@@ -4,6 +4,7 @@
 
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::io::prelude::*;
diff --git a/src/test/run-pass/simd/simd-target-feature-mixup.rs b/src/test/run-pass/simd/simd-target-feature-mixup.rs
index 5842a7fcdf7..6d7688191b7 100644
--- a/src/test/run-pass/simd/simd-target-feature-mixup.rs
+++ b/src/test/run-pass/simd/simd-target-feature-mixup.rs
@@ -4,6 +4,7 @@
 #![allow(overflowing_literals)]
 
 // ignore-emscripten
+// ignore-sgx no processes
 
 #![feature(repr_simd, target_feature, cfg_target_feature)]
 #![feature(avx512_target_feature)]
diff --git a/src/test/run-pass/sleep.rs b/src/test/run-pass/sleep.rs
index f0411876c8a..7128b3cc7c3 100644
--- a/src/test/run-pass/sleep.rs
+++ b/src/test/run-pass/sleep.rs
@@ -1,4 +1,5 @@
 // ignore-emscripten no threads support
+// ignore-sgx no thread sleep support
 
 use std::thread::{self, sleep};
 use std::time::Duration;
diff --git a/src/test/run-pass/stack-probes-lto.rs b/src/test/run-pass/stack-probes-lto.rs
index 2705950b014..1274f032a3e 100644
--- a/src/test/run-pass/stack-probes-lto.rs
+++ b/src/test/run-pass/stack-probes-lto.rs
@@ -9,6 +9,7 @@
 // ignore-wasm
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 // ignore-musl FIXME #31506
 // ignore-pretty
 // compile-flags: -C lto
diff --git a/src/test/run-pass/stack-probes.rs b/src/test/run-pass/stack-probes.rs
index ff264421cfb..92a0cc3a07b 100644
--- a/src/test/run-pass/stack-probes.rs
+++ b/src/test/run-pass/stack-probes.rs
@@ -9,6 +9,7 @@
 // ignore-wasm
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 // ignore-musl FIXME #31506
 
 use std::mem;
diff --git a/src/test/run-pass/stdio-is-blocking.rs b/src/test/run-pass/stdio-is-blocking.rs
index 281c6a17aa9..1824162b8ba 100644
--- a/src/test/run-pass/stdio-is-blocking.rs
+++ b/src/test/run-pass/stdio-is-blocking.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 use std::env;
 use std::io::prelude::*;
diff --git a/src/test/run-pass/structs-enums/rec-align-u64.rs b/src/test/run-pass/structs-enums/rec-align-u64.rs
index d211eed131e..c4e9e9ea5ee 100644
--- a/src/test/run-pass/structs-enums/rec-align-u64.rs
+++ b/src/test/run-pass/structs-enums/rec-align-u64.rs
@@ -55,7 +55,7 @@ mod m {
     }
 }
 
-#[cfg(target_os = "bitrig")]
+#[cfg(target_env = "sgx")]
 mod m {
     #[cfg(target_arch = "x86_64")]
     pub mod m {
diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs
index c90f9024af1..391cbbdd42d 100644
--- a/src/test/run-pass/tcp-stress.rs
+++ b/src/test/run-pass/tcp-stress.rs
@@ -1,9 +1,9 @@
 // ignore-android needs extra network permissions
-// ignore-bitrig system ulimit (Too many open files)
 // ignore-cloudabi no global network namespace access
 // ignore-emscripten no threads or sockets support
 // ignore-netbsd system ulimit (Too many open files)
 // ignore-openbsd system ulimit (Too many open files)
+// ignore-sgx no thread sleep support
 
 use std::io::prelude::*;
 use std::net::{TcpListener, TcpStream};
diff --git a/src/test/run-pass/threads-sendsync/sync-send-in-std.rs b/src/test/run-pass/threads-sendsync/sync-send-in-std.rs
index 981ac166356..15e10dc250f 100644
--- a/src/test/run-pass/threads-sendsync/sync-send-in-std.rs
+++ b/src/test/run-pass/threads-sendsync/sync-send-in-std.rs
@@ -2,6 +2,7 @@
 
 // ignore-cloudabi networking not available
 // ignore-wasm32-bare networking not available
+// ignore-sgx ToSocketAddrs cannot be used for DNS Resolution
 
 use std::net::ToSocketAddrs;
 
diff --git a/src/test/run-pass/try-wait.rs b/src/test/run-pass/try-wait.rs
index 05871ba7d4c..97caddde412 100644
--- a/src/test/run-pass/try-wait.rs
+++ b/src/test/run-pass/try-wait.rs
@@ -1,6 +1,7 @@
 #![allow(stable_features)]
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 #![feature(process_try_wait)]
 
diff --git a/src/test/run-pass/union/union-nonzero.rs b/src/test/run-pass/union/union-nonzero.rs
new file mode 100644
index 00000000000..bd84b46bf3d
--- /dev/null
+++ b/src/test/run-pass/union/union-nonzero.rs
@@ -0,0 +1,51 @@
+// run-pass
+#![allow(dead_code)]
+
+// Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations.
+//
+// For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no
+// bit-value that an `Option<U>` could reuse as `None`; this test makes sure that isn't done.
+//
+// Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such
+// optimizations to types containing unions even if they're theoretically possible. (discussion:
+// https://github.com/rust-lang/rust/issues/36394)
+//
+// Notably this nails down part of the behavior that `MaybeUninit` assumes: that a
+// `Option<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe
+// construct.
+
+use std::mem::{size_of, transmute};
+
+union U1<A: Copy> {
+    a: A,
+}
+
+union U2<A: Copy, B: Copy> {
+    a: A,
+    b: B,
+}
+
+// Option<E> uses a value other than 0 and 1 as None
+#[derive(Clone,Copy)]
+enum E {
+    A = 0,
+    B = 1,
+}
+
+fn main() {
+    // Unions do not participate in niche-filling/non-zero optimization...
+    assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
+    assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
+    assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>());
+
+    // ...even when theoretically possible:
+    assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
+    assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
+
+    // The unused bits of the () variant can have any value.
+    let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
+
+    if let None = Some(zeroed) {
+        panic!()
+    }
+}
diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs
index e9869866a9b..1f32bd00a03 100644
--- a/src/test/run-pass/wait-forked-but-failed-child.rs
+++ b/src/test/run-pass/wait-forked-but-failed-child.rs
@@ -1,5 +1,6 @@
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 #![feature(rustc_private)]
 
diff --git a/src/test/run-pass/x86stdcall.rs b/src/test/run-pass/x86stdcall.rs
index 11a45a58895..cd9450a5697 100644
--- a/src/test/run-pass/x86stdcall.rs
+++ b/src/test/run-pass/x86stdcall.rs
@@ -1,5 +1,5 @@
 // ignore-wasm32-bare no libc to test ffi with
-
+// ignore-sgx no libc
 // GetLastError doesn't seem to work with stack switching
 
 #[cfg(windows)]
@@ -23,7 +23,6 @@ pub fn main() {
 }
 
 #[cfg(any(target_os = "android",
-          target_os = "bitrig",
           target_os = "cloudabi",
           target_os = "dragonfly",
           target_os = "emscripten",
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs
index aa3f539ba32..4b2a91e9c81 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.rs
+++ b/src/test/rustdoc-ui/doc-without-codeblock.rs
@@ -1,6 +1,4 @@
-//~ ERROR Missing code example in this documentation
-
-#![deny(missing_doc_code_examples)]
+#![deny(missing_doc_code_examples)] //~ ERROR Missing code example in this documentation
 
 /// Some docs.
 //~^ ERROR Missing code example in this documentation
diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr
index 208bdedf24d..23c07c4d32d 100644
--- a/src/test/rustdoc-ui/doc-without-codeblock.stderr
+++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr
@@ -1,25 +1,35 @@
 error: Missing code example in this documentation
+  --> $DIR/doc-without-codeblock.rs:1:1
+   |
+LL | / #![deny(missing_doc_code_examples)]
+LL | |
+LL | | /// Some docs.
+LL | |
+...  |
+LL | |     pub fn bar() {}
+LL | | }
+   | |_^
    |
 note: lint level defined here
-  --> $DIR/doc-without-codeblock.rs:3:9
+  --> $DIR/doc-without-codeblock.rs:1:9
    |
 LL | #![deny(missing_doc_code_examples)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:5:1
+  --> $DIR/doc-without-codeblock.rs:3:1
    |
 LL | /// Some docs.
    | ^^^^^^^^^^^^^^
 
 error: Missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:9:1
+  --> $DIR/doc-without-codeblock.rs:7:1
    |
 LL | /// And then, the princess died.
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Missing code example in this documentation
-  --> $DIR/doc-without-codeblock.rs:12:5
+  --> $DIR/doc-without-codeblock.rs:10:5
    |
 LL |     /// Or maybe not because she saved herself!
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
new file mode 100644
index 00000000000..ffe0ddcd8c9
--- /dev/null
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs
@@ -0,0 +1,40 @@
+#![deny(missing_docs)]
+#![deny(missing_doc_code_examples)]
+
+//! crate level doc
+//! ```
+//! println!("hello"):
+//! ```
+
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+fn test() {
+}
+
+#[allow(missing_docs)]
+mod module1 { //~ ERROR
+}
+
+#[allow(missing_doc_code_examples)]
+/// doc
+mod module2 {
+
+  /// doc
+  pub fn test() {}
+}
+
+/// doc
+///
+/// ```
+/// println!("hello");
+/// ```
+pub mod module3 {
+
+  /// doc
+  //~^ ERROR
+  pub fn test() {}
+}
diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
new file mode 100644
index 00000000000..97a52a13e3f
--- /dev/null
+++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
@@ -0,0 +1,21 @@
+error: Missing code example in this documentation
+  --> $DIR/lint-missing-doc-code-example.rs:19:1
+   |
+LL | / mod module1 {
+LL | | }
+   | |_^
+   |
+note: lint level defined here
+  --> $DIR/lint-missing-doc-code-example.rs:2:9
+   |
+LL | #![deny(missing_doc_code_examples)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Missing code example in this documentation
+  --> $DIR/lint-missing-doc-code-example.rs:37:3
+   |
+LL |   /// doc
+   |   ^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc/async-move-doctest.rs b/src/test/rustdoc/async-move-doctest.rs
new file mode 100644
index 00000000000..42723132782
--- /dev/null
+++ b/src/test/rustdoc/async-move-doctest.rs
@@ -0,0 +1,14 @@
+// compile-flags:--test
+// edition:2018
+
+// prior to setting the default edition for the doctest pre-parser, this doctest would fail due to
+// a fatal parsing error
+// see https://github.com/rust-lang/rust/issues/59313
+
+//! ```
+//! #![feature(async_await)]
+//!
+//! fn foo() {
+//!     drop(async move {});
+//! }
+//! ```
diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs
index eb0e3f065c7..6ecdad3ec00 100644
--- a/src/test/rustdoc/attributes.rs
+++ b/src/test/rustdoc/attributes.rs
@@ -8,8 +8,8 @@ pub extern "C" fn f() {}
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @has foo/enum.Foo.html '//*[@class="docblock attributes"]' '#[repr(i64)]'
-// @has foo/enum.Foo.html '//*[@class="docblock attributes"]' '#[must_use]'
+// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[repr(i64)]'
+// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[must_use]'
 #[repr(i64)]
 #[must_use]
 pub enum Foo {
diff --git a/src/test/rustdoc/generic-const.rs b/src/test/rustdoc/generic-const.rs
new file mode 100644
index 00000000000..d6794ac8f1d
--- /dev/null
+++ b/src/test/rustdoc/generic-const.rs
@@ -0,0 +1,30 @@
+#![feature(const_generics)]
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+pub enum Order {
+    Sorted,
+    Unsorted,
+}
+
+// @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
+// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<const ORDER: Order, T> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<const ORDER: Order, T> Sync for VSet<T, ORDER>'
+pub struct VSet<T, const ORDER: Order> {
+    inner: Vec<T>,
+}
+
+// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, { Order::Sorted }>'
+impl <T> VSet<T, {Order::Sorted}> {
+    pub fn new() -> Self {
+        Self { inner: Vec::new() }
+    }
+}
+
+// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, { Order::Unsorted }>'
+impl <T> VSet<T, {Order::Unsorted}> {
+    pub fn new() -> Self {
+        Self { inner: Vec::new() }
+    }
+}
diff --git a/src/test/rustdoc/intra-link-libstd-re-export.rs b/src/test/rustdoc/intra-link-libstd-re-export.rs
new file mode 100644
index 00000000000..6f239292ec2
--- /dev/null
+++ b/src/test/rustdoc/intra-link-libstd-re-export.rs
@@ -0,0 +1,3 @@
+#![deny(intra_doc_link_resolution_failure)]
+
+pub use std::*;
diff --git a/src/test/rustdoc/playground-arg.rs b/src/test/rustdoc/playground-arg.rs
index fb1be7397e6..018716ad45a 100644
--- a/src/test/rustdoc/playground-arg.rs
+++ b/src/test/rustdoc/playground-arg.rs
@@ -11,4 +11,4 @@
 pub fn dummy() {}
 
 // ensure that `extern crate foo;` was inserted into code snips automatically:
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs
index 1b76e6c8853..9971c7b4297 100644
--- a/src/test/rustdoc/playground.rs
+++ b/src/test/rustdoc/playground.rs
@@ -24,6 +24,6 @@
 //! }
 //! ```
 
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run"
diff --git a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs
index c83e7bdb998..039124f31ff 100644
--- a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs
@@ -8,14 +8,14 @@ extern crate syntax;
 extern crate rustc;
 extern crate rustc_plugin;
 
+use syntax::symbol::Symbol;
 use syntax::feature_gate::AttributeType;
 use rustc_plugin::Registry;
 
 
-
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_attribute("foo".to_owned(), AttributeType::Normal);
-    reg.register_attribute("bar".to_owned(), AttributeType::CrateLevel);
-    reg.register_attribute("baz".to_owned(), AttributeType::Whitelisted);
+    reg.register_attribute(Symbol::intern("foo"), AttributeType::Normal);
+    reg.register_attribute(Symbol::intern("bar"), AttributeType::CrateLevel);
+    reg.register_attribute(Symbol::intern("baz"), AttributeType::Whitelisted);
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
index e8f1d2eedf5..7656b15721a 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
@@ -11,6 +11,7 @@ use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPass
 use rustc_plugin::Registry;
 use rustc::hir;
 use syntax::attr;
+use syntax::symbol::Symbol;
 
 declare_lint! {
     CRATE_NOT_OKAY,
@@ -22,7 +23,7 @@ declare_lint_pass!(Pass => [CRATE_NOT_OKAY]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
     fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) {
-        if !attr::contains_name(&krate.attrs, "crate_okay") {
+        if !attr::contains_name(&krate.attrs, Symbol::intern("crate_okay")) {
             cx.span_lint(CRATE_NOT_OKAY, krate.span,
                          "crate is not marked with #![crate_okay]");
         }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
index 1d204e7bfcf..0deb1bf0915 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
@@ -20,7 +20,7 @@ declare_lint_pass!(Pass => [TEST_LINT]);
 
 impl EarlyLintPass for Pass {
     fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
-        if it.ident.name == "lintme" {
+        if it.ident.name.as_str() == "lintme" {
             cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
         }
     }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
index 182d2899da1..64664377cd9 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
@@ -23,10 +23,10 @@ declare_lint_pass!(Pass => [TEST_LINT, TEST_GROUP]);
 
 impl EarlyLintPass for Pass {
     fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
-        if it.ident.name == "lintme" {
+        if it.ident.name.as_str() == "lintme" {
             cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
         }
-        if it.ident.name == "lintmetoo" {
+        if it.ident.name.as_str() == "lintmetoo" {
             cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'");
         }
     }
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr
new file mode 100644
index 00000000000..ca99304f9b4
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-fn-body.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:29
+   |
+LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>(
+   |        --  -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+...
+LL |     let z: I::A = if cond { x } else { y };
+   |                             ^ assignment requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/associated-types-project-from-hrtb-in-fn-body.rs:22:40
+   |
+LL | fn bar<'a, 'b, I : for<'x> Foo<&'x isize>>(
+   |        --  -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+...
+LL |     let z: I::A = if cond { x } else { y };
+   |                                        ^ assignment requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr b/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr
new file mode 100644
index 00000000000..d8506b9c8c8
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-subtyping-1.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/associated-types-subtyping-1.rs:24:12
+   |
+LL | fn method2<'a,'b,T>(x: &'a T, y: &'b T)
+   |            -- -- lifetime `'b` defined here
+   |            |
+   |            lifetime `'a` defined here
+...
+LL |     let a: <T as Trait<'a>>::Type = make_any();
+   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/associated-types-subtyping-1.rs:35:13
+   |
+LL | fn method3<'a,'b,T>(x: &'a T, y: &'b T)
+   |            -- -- lifetime `'b` defined here
+   |            |
+   |            lifetime `'a` defined here
+...
+LL |     let _c: <T as Trait<'a>>::Type = b;
+   |             ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr
new file mode 100644
index 00000000000..779e6dac92e
--- /dev/null
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.krisskross.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-contravariant.rs:45:4
+   |
+LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+   |              -- -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+...
+LL |    (a, b)
+   |    ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-contravariant.rs:45:4
+   |
+LL | fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
+   |              -- -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+...
+LL |    (a, b)
+   |    ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr
new file mode 100644
index 00000000000..f532c96ed2c
--- /dev/null
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-contravariant.rs:38:4
+   |
+LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |    bar(foo, x)
+   |    ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
new file mode 100644
index 00000000000..c45082fb053
--- /dev/null
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-invariant.rs:55:4
+   |
+LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              -- -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+...
+LL |    (a, b)
+   |    ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-invariant.rs:55:4
+   |
+LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              -- -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+...
+LL |    (a, b)
+   |    ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
new file mode 100644
index 00000000000..2c11e7ffe93
--- /dev/null
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-invariant.rs:38:12
+   |
+LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        -- -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+LL |    let f = foo; // <-- No consistent type can be inferred for `f` here.
+LL |    let a = bar(f, x);
+   |            ^^^^^^^^^ argument requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-invariant.rs:39:12
+   |
+LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        -- -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+...
+LL |    let b = bar(f, y);
+   |            ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
new file mode 100644
index 00000000000..8be0ad6e88f
--- /dev/null
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/project-fn-ret-invariant.rs:48:4
+   |
+LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+   |        -- lifetime `'a` defined here
+...
+LL |    bar(foo, x)
+   |    ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issue-60674.rs b/src/test/ui/async-await/issue-60674.rs
index 37e356e5baf..ecb80803383 100644
--- a/src/test/ui/async-await/issue-60674.rs
+++ b/src/test/ui/async-await/issue-60674.rs
@@ -11,4 +11,10 @@ extern crate issue_60674;
 #[issue_60674::attr]
 async fn f(mut x: u8) {}
 
+#[issue_60674::attr]
+async fn g((mut x, y, mut z): (u8, u8, u8)) {}
+
+#[issue_60674::attr]
+async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {}
+
 fn main() {}
diff --git a/src/test/ui/async-await/issue-60674.stdout b/src/test/ui/async-await/issue-60674.stdout
index a93944db1c5..86c3591b3af 100644
--- a/src/test/ui/async-await/issue-60674.stdout
+++ b/src/test/ui/async-await/issue-60674.stdout
@@ -1 +1,3 @@
 async fn f(mut x: u8) { }
+async fn g((mut x, y, mut z): (u8, u8, u8)) { }
+async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { }
diff --git a/src/test/ui/attr-eq-token-tree.stderr b/src/test/ui/attr-eq-token-tree.stderr
index aae25b2721e..571779dfa1a 100644
--- a/src/test/ui/attr-eq-token-tree.stderr
+++ b/src/test/ui/attr-eq-token-tree.stderr
@@ -1,8 +1,8 @@
 error: unexpected token: `!`
-  --> $DIR/attr-eq-token-tree.rs:3:11
+  --> $DIR/attr-eq-token-tree.rs:3:13
    |
 LL | #[my_attr = !]
-   |           ^
+   |             ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
index b2e8e4be172..f59f1160e70 100644
--- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
+++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs
@@ -22,6 +22,4 @@ macro_rules! await {
     () => {}
 }
 
-fn main() {
-    match await { await => () } //~ ERROR expected `!`, found `{`
-}
+fn main() {}
diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
index 076a31bd9ce..c4b82b29f02 100644
--- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
+++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr
@@ -68,13 +68,5 @@ help: you can escape reserved keywords to use them as identifiers
 LL | macro_rules! r#await {
    |              ^^^^^^^
 
-error: expected `!`, found `{`
-  --> $DIR/2018-edition-error-in-non-macro-position.rs:26:17
-   |
-LL |     match await { await => () }
-   |     -----       ^ expected `!`
-   |     |
-   |     while parsing this match expression
-
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs
index e0b2962ce97..d8568696842 100644
--- a/src/test/ui/await-keyword/2018-edition-error.rs
+++ b/src/test/ui/await-keyword/2018-edition-error.rs
@@ -9,6 +9,4 @@ mod outer_mod {
 use self::outer_mod::await::await; //~ ERROR expected identifier
     //~^ ERROR expected identifier, found reserved keyword `await`
 
-fn main() {
-    match await { await => () } //~ ERROR expected `!`, found `{`
-}
+fn main() {}
diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr
index c8bf9b42ca5..8afe5c1a36b 100644
--- a/src/test/ui/await-keyword/2018-edition-error.stderr
+++ b/src/test/ui/await-keyword/2018-edition-error.stderr
@@ -38,13 +38,5 @@ help: you can escape reserved keywords to use them as identifiers
 LL | use self::outer_mod::await::r#await;
    |                             ^^^^^^^
 
-error: expected `!`, found `{`
-  --> $DIR/2018-edition-error.rs:13:17
-   |
-LL |     match await { await => () }
-   |     -----       ^ expected `!`
-   |     |
-   |     while parsing this match expression
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs
new file mode 100644
index 00000000000..e1e5bdd3d1b
--- /dev/null
+++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs
@@ -0,0 +1,111 @@
+// edition:2018
+
+#![feature(async_await)]
+
+async fn bar() -> Result<(), ()> {
+    Ok(())
+}
+
+async fn foo1() -> Result<(), ()> {
+    let _ = await bar(); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo2() -> Result<(), ()> {
+    let _ = await? bar(); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo3() -> Result<(), ()> {
+    let _ = await bar()?; //~ ERROR incorrect use of `await`
+    //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
+    Ok(())
+}
+async fn foo21() -> Result<(), ()> {
+    let _ = await { bar() }; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo22() -> Result<(), ()> {
+    let _ = await(bar()); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo23() -> Result<(), ()> {
+    let _ = await { bar() }?; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo4() -> Result<(), ()> {
+    let _ = (await bar())?; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo5() -> Result<(), ()> {
+    let _ = bar().await(); //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo6() -> Result<(), ()> {
+    let _ = bar().await()?; //~ ERROR incorrect use of `await`
+    Ok(())
+}
+async fn foo7() -> Result<(), ()> {
+    let _ = bar().await; // OK
+    Ok(())
+}
+async fn foo8() -> Result<(), ()> {
+    let _ = bar().await?; // OK
+    Ok(())
+}
+fn foo9() -> Result<(), ()> {
+    let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo10() -> Result<(), ()> {
+    let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo11() -> Result<(), ()> {
+    let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo12() -> Result<(), ()> {
+    let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo13() -> Result<(), ()> {
+    let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo14() -> Result<(), ()> {
+    let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    //~^ ERROR incorrect use of `await`
+    Ok(())
+}
+fn foo15() -> Result<(), ()> {
+    let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    Ok(())
+}
+fn foo16() -> Result<(), ()> {
+    let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+    Ok(())
+}
+fn foo24() -> Result<(), ()> {
+    fn foo() -> Result<(), ()> {
+        let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+        Ok(())
+    }
+    foo()
+}
+fn foo25() -> Result<(), ()> {
+    let foo = || {
+        let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
+        Ok(())
+    };
+    foo()
+}
+
+fn main() {
+    match await { await => () }
+    //~^ ERROR expected expression, found `=>`
+    //~| ERROR incorrect use of `await`
+} //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `}`
diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr
new file mode 100644
index 00000000000..380da4448ad
--- /dev/null
+++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr
@@ -0,0 +1,207 @@
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:10:13
+   |
+LL |     let _ = await bar();
+   |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:14:13
+   |
+LL |     let _ = await? bar();
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:18:13
+   |
+LL |     let _ = await bar()?;
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:23:13
+   |
+LL |     let _ = await { bar() };
+   |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:27:13
+   |
+LL |     let _ = await(bar());
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `(bar()).await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:31:13
+   |
+LL |     let _ = await { bar() }?;
+   |             ^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ bar() }.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:35:14
+   |
+LL |     let _ = (await bar())?;
+   |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:39:24
+   |
+LL |     let _ = bar().await();
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:43:24
+   |
+LL |     let _ = bar().await()?;
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:55:13
+   |
+LL |     let _ = await bar();
+   |             ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:60:13
+   |
+LL |     let _ = await? bar();
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await?`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:65:13
+   |
+LL |     let _ = await bar()?;
+   |             ^^^^^^^^^^^^ help: `await` is a postfix operation: `bar()?.await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:70:14
+   |
+LL |     let _ = (await bar())?;
+   |              ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:75:24
+   |
+LL |     let _ = bar().await();
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:80:24
+   |
+LL |     let _ = bar().await()?;
+   |                        ^^ help: `await` is not a method call, remove the parentheses
+
+error: expected expression, found `=>`
+  --> $DIR/incorrect-syntax-suggestions.rs:108:25
+   |
+LL |     match await { await => () }
+   |                   ----- ^^ expected expression
+   |                   |
+   |                   while parsing this incorrect await expression
+
+error: incorrect use of `await`
+  --> $DIR/incorrect-syntax-suggestions.rs:108:11
+   |
+LL |     match await { await => () }
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: `await` is a postfix operation: `{ await => () }.await`
+
+error: expected one of `.`, `?`, `{`, or an operator, found `}`
+  --> $DIR/incorrect-syntax-suggestions.rs:111:1
+   |
+LL |     match await { await => () }
+   |     -----                      - expected one of `.`, `?`, `{`, or an operator here
+   |     |
+   |     while parsing this match expression
+...
+LL | }
+   | ^ unexpected token
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:55:13
+   |
+LL | fn foo9() -> Result<(), ()> {
+   |    ---- this is not `async`
+LL |     let _ = await bar();
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:60:13
+   |
+LL | fn foo10() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = await? bar();
+   |             ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:65:13
+   |
+LL | fn foo11() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = await bar()?;
+   |             ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:70:14
+   |
+LL | fn foo12() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = (await bar())?;
+   |              ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:75:13
+   |
+LL | fn foo13() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await();
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:80:13
+   |
+LL | fn foo14() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await()?;
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:85:13
+   |
+LL | fn foo15() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await;
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:89:13
+   |
+LL | fn foo16() -> Result<(), ()> {
+   |    ----- this is not `async`
+LL |     let _ = bar().await?;
+   |             ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:94:17
+   |
+LL |     fn foo() -> Result<(), ()> {
+   |        --- this is not `async`
+LL |         let _ = bar().await?;
+   |                 ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0728]: `await` is only allowed inside `async` functions and blocks
+  --> $DIR/incorrect-syntax-suggestions.rs:101:17
+   |
+LL |     let foo = || {
+   |               -- this is not `async`
+LL |         let _ = bar().await?;
+   |                 ^^^^^^^^^^^ only allowed inside `async` functions and blocks
+
+error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
+  --> $DIR/incorrect-syntax-suggestions.rs:18:19
+   |
+LL |     let _ = await bar()?;
+   |                   ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future`
+   |
+   = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future`
+   = note: required by `std::ops::Try::into_result`
+
+error: aborting due to 29 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr
index 0996c38b3b6..4e525974c2c 100644
--- a/src/test/ui/await-keyword/post_expansion_error.stderr
+++ b/src/test/ui/await-keyword/post_expansion_error.stderr
@@ -2,7 +2,9 @@ error: expected expression, found `)`
   --> $DIR/post_expansion_error.rs:8:12
    |
 LL |     await!()
-   |            ^ expected expression
+   |     -----  ^ expected expression
+   |     |
+   |     while parsing this await macro call
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr
new file mode 100644
index 00000000000..f66994b3f10
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr
@@ -0,0 +1,40 @@
+error[E0503]: cannot use `y` because it was mutably borrowed
+  --> $DIR/borrowck-anon-fields-variant.rs:17:7
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- borrow of `y.0` occurs here
+...
+LL |       Foo::Y(_, ref mut b) => b,
+   |       ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0`
+...
+LL |     *a += 1;
+   |     ------- borrow later used here
+
+error[E0503]: cannot use `y` because it was mutably borrowed
+  --> $DIR/borrowck-anon-fields-variant.rs:37:7
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- borrow of `y.0` occurs here
+...
+LL |       Foo::Y(ref mut b, _) => b,
+   |       ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0`
+...
+LL |     *a += 1;
+   |     ------- borrow later used here
+
+error[E0499]: cannot borrow `y.0` as mutable more than once at a time
+  --> $DIR/borrowck-anon-fields-variant.rs:37:14
+   |
+LL |       Foo::Y(ref mut a, _) => a,
+   |              --------- first mutable borrow occurs here
+...
+LL |       Foo::Y(ref mut b, _) => b,
+   |              ^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     *a += 1;
+   |     ------- first borrow later used here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0499, E0503.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr
new file mode 100644
index 00000000000..f1e1ae18839
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.nll.stderr
@@ -0,0 +1,366 @@
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-describe-lvalue.rs:262:13
+   |
+LL |             let y = &mut x;
+   |                     ------ first mutable borrow occurs here
+LL |             &mut x;
+   |             ^^^^^^ second mutable borrow occurs here
+LL |             *y = 1;
+   |             ------ first borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+  --> $DIR/borrowck-describe-lvalue.rs:272:20
+   |
+LL |                    let y = &mut x;
+   |                            ------ first mutable borrow occurs here
+LL |                    &mut x;
+   |                    ^^^^^^ second mutable borrow occurs here
+LL |                    *y = 1;
+   |                    ------ first borrow later used here
+
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/borrowck-describe-lvalue.rs:270:16
+   |
+LL |              || {
+   |               - inferred to be a `FnMut` closure
+LL | /                || {
+LL | |                    let y = &mut x;
+LL | |                    &mut x;
+LL | |                    *y = 1;
+LL | |                    drop(y);
+LL | |                 }
+   | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error[E0503]: cannot use `f.x` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:41:9
+   |
+LL |         let x = f.x();
+   |                 - borrow of `f` occurs here
+LL |         f.x;
+   |         ^^^ use of borrowed `f`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `g.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:48:9
+   |
+LL |         let x = g.x();
+   |                 - borrow of `g` occurs here
+LL |         g.0;
+   |         ^^^ use of borrowed `g`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `h.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:55:9
+   |
+LL |         let x = &mut h.0;
+   |                 -------- borrow of `h.0` occurs here
+LL |         h.0;
+   |         ^^^ use of borrowed `h.0`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `e.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:63:20
+   |
+LL |         let x = e.x();
+   |                 - borrow of `e` occurs here
+LL |         match e {
+LL |             Baz::X(value) => value
+   |                    ^^^^^ use of borrowed `e`
+LL |         };
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `u.a` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:71:9
+   |
+LL |         let x = &mut u.a;
+   |                 -------- borrow of `u.a` occurs here
+LL |         u.a;
+   |         ^^^ use of borrowed `u.a`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `f.x` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:78:9
+   |
+LL |         let x = f.x();
+   |                 - borrow of `*f` occurs here
+LL |         f.x;
+   |         ^^^ use of borrowed `*f`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `g.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:85:9
+   |
+LL |         let x = g.x();
+   |                 - borrow of `*g` occurs here
+LL |         g.0;
+   |         ^^^ use of borrowed `*g`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `h.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:92:9
+   |
+LL |         let x = &mut h.0;
+   |                 -------- borrow of `h.0` occurs here
+LL |         h.0;
+   |         ^^^ use of borrowed `h.0`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `e.0` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:100:20
+   |
+LL |         let x = e.x();
+   |                 - borrow of `*e` occurs here
+LL |         match *e {
+LL |             Baz::X(value) => value
+   |                    ^^^^^ use of borrowed `*e`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `u.a` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:109:9
+   |
+LL |         let x = &mut u.a;
+   |                 -------- borrow of `u.a` occurs here
+LL |         u.a;
+   |         ^^^ use of borrowed `u.a`
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:117:15
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         match v {
+LL |             &[x, _, .., _, _] => println!("{}", x),
+   |               ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:122:18
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, x, .., _, _] => println!("{}", x),
+   |                  ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:127:25
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, _, .., x, _] => println!("{}", x),
+   |                         ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:132:28
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, _, .., _, x] => println!("{}", x),
+   |                            ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:143:15
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         match v {
+LL |             &[x..] => println!("{:?}", x),
+   |               ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:148:18
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, x..] => println!("{:?}", x),
+   |                  ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:153:15
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[x.., _] => println!("{:?}", x),
+   |               ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[..]` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:158:18
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+...
+LL |             &[_, x.., _] => println!("{:?}", x),
+   |                  ^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `e` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:171:13
+   |
+LL |         let x = &mut e;
+   |                 ------ borrow of `e` occurs here
+LL |         match e {
+LL |             E::A(ref ax) =>
+   |             ^^^^^^^^^^^^ use of borrowed `e`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:171:18
+   |
+LL |         let x = &mut e;
+   |                 ------ mutable borrow occurs here
+LL |         match e {
+LL |             E::A(ref ax) =>
+   |                  ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:175:23
+   |
+LL |         let x = &mut e;
+   |                 ------ mutable borrow occurs here
+...
+LL |             E::B { x: ref bx } =>
+   |                       ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:188:22
+   |
+LL |         let x = &mut s;
+   |                 ------ mutable borrow occurs here
+LL |         match s {
+LL |             S  { y: (ref y0, _), .. } =>
+   |                      ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:194:28
+   |
+LL |         let x = &mut s;
+   |                 ------ mutable borrow occurs here
+...
+LL |             S  { x: F { y: ref x0, .. }, .. } =>
+   |                            ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0503]: cannot use `*v` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:240:9
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         v[0].y;
+   |         ^^^^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0503]: cannot use `v[_].y` because it was mutably borrowed
+  --> $DIR/borrowck-describe-lvalue.rs:240:9
+   |
+LL |         let x = &mut v;
+   |                 ------ borrow of `v` occurs here
+LL |         v[0].y;
+   |         ^^^^^^ use of borrowed `v`
+...
+LL |         drop(x);
+   |              - borrow later used here
+
+error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:251:24
+   |
+LL |         let x = &mut v;
+   |                 ------ mutable borrow occurs here
+LL |         match v {
+LL |             &[_, F {x: ref xf, ..}] => println!("{}", xf),
+   |                        ^^^^^^ immutable borrow occurs here
+...
+LL |         drop(x);
+   |              - mutable borrow later used here
+
+error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:210:29
+   |
+LL |             let x = &mut block;
+   |                     ---------- mutable borrow occurs here
+LL |             let p: &'a u8 = &*block.current;
+   |                             ^^^^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |             drop(x);
+   |                  - mutable borrow later used here
+
+error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-describe-lvalue.rs:227:33
+   |
+LL |             let x = &mut block;
+   |                     ---------- mutable borrow occurs here
+LL |             let p : *const u8 = &*(*block).current;
+   |                                 ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |             drop(x);
+   |                  - mutable borrow later used here
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrowck-describe-lvalue.rs:282:22
+   |
+LL |                 drop(x);
+   |                      - value moved here
+LL |                 drop(x);
+   |                      ^ value used here after move
+   |
+   = note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to 32 previous errors
+
+Some errors have detailed explanations: E0382, E0499, E0502, E0503.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr
new file mode 100644
index 00000000000..3468f29fb1a
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr
@@ -0,0 +1,27 @@
+error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-for-loop-head-linkage.rs:7:9
+   |
+LL |     for &x in &vector {
+   |               -------
+   |               |
+   |               immutable borrow occurs here
+   |               immutable borrow later used here
+LL |         let cap = vector.capacity();
+LL |         vector.extend(repeat(0));
+   |         ^^^^^^ mutable borrow occurs here
+
+error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-for-loop-head-linkage.rs:8:9
+   |
+LL |     for &x in &vector {
+   |               -------
+   |               |
+   |               immutable borrow occurs here
+   |               immutable borrow later used here
+...
+LL |         vector[1] = 5;
+   |         ^^^^^^ mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/borrowck-issue-48962.rs b/src/test/ui/borrowck/borrowck-issue-48962.rs
index e7df319a0bb..86061c8cd6e 100644
--- a/src/test/ui/borrowck/borrowck-issue-48962.rs
+++ b/src/test/ui/borrowck/borrowck-issue-48962.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Node {
     elem: i32,
     next: Option<Box<Node>>,
diff --git a/src/test/ui/borrowck/borrowck-issue-48962.stderr b/src/test/ui/borrowck/borrowck-issue-48962.stderr
index a5462b41396..ee174f6736e 100644
--- a/src/test/ui/borrowck/borrowck-issue-48962.stderr
+++ b/src/test/ui/borrowck/borrowck-issue-48962.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `src`
-  --> $DIR/borrowck-issue-48962.rs:16:5
+  --> $DIR/borrowck-issue-48962.rs:14:5
    |
 LL |     let mut src = &mut node;
    |         ------- move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
@@ -9,7 +9,7 @@ LL |     src.next = None;
    |     ^^^^^^^^ value used here after move
 
 error[E0382]: use of moved value: `src`
-  --> $DIR/borrowck-issue-48962.rs:22:5
+  --> $DIR/borrowck-issue-48962.rs:20:5
    |
 LL |     let mut src = &mut (22, 44);
    |         ------- move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
diff --git a/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr b/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr
new file mode 100644
index 00000000000..7e4a6322d5f
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-mutate-in-guard.nll.stderr
@@ -0,0 +1,41 @@
+error[E0302]: cannot assign in a pattern guard
+  --> $DIR/borrowck-mutate-in-guard.rs:10:25
+   |
+LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
+   |                         ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
+
+error[E0301]: cannot mutably borrow in a pattern guard
+  --> $DIR/borrowck-mutate-in-guard.rs:15:38
+   |
+LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+   |                                      ^ borrowed mutably in pattern guard
+   |
+   = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
+
+error[E0302]: cannot assign in a pattern guard
+  --> $DIR/borrowck-mutate-in-guard.rs:15:41
+   |
+LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+   |                                         ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
+
+error[E0510]: cannot assign `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:10:25
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+LL |         Enum::A(_) if { x = Enum::B(false); false } => 1,
+   |                         ^^^^^^^^^^^^^^^^^^ cannot assign
+
+error[E0510]: cannot mutably borrow `x` in match guard
+  --> $DIR/borrowck-mutate-in-guard.rs:15:33
+   |
+LL |     match x {
+   |           - value is immutable in match guard
+...
+LL |         Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+   |                                 ^^^^^^ cannot mutably borrow
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0301, E0302, E0510.
+For more information about an error, try `rustc --explain E0301`.
diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr
new file mode 100644
index 00000000000..49c3f861ea9
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr
@@ -0,0 +1,23 @@
+error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-object-lifetime.rs:20:13
+   |
+LL |     let y = x.borrowed();
+   |             - immutable borrow occurs here
+LL |     let z = x.mut_borrowed();
+   |             ^ mutable borrow occurs here
+LL |     y.use_ref();
+   |     - immutable borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-object-lifetime.rs:26:13
+   |
+LL |     let y = x.borrowed();
+   |             - immutable borrow occurs here
+LL |     let z = &mut x;
+   |             ^^^^^^ mutable borrow occurs here
+LL |     y.use_ref();
+   |     - immutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr b/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr
new file mode 100644
index 00000000000..e6d0f88e3ea
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:9:5
+   |
+LL | fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> {
+   |                      -- -- lifetime `'b` defined here
+   |                      |
+   |                      lifetime `'a` defined here
+LL |     S { pointer: &mut *p.pointer }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/borrowck/issue-10876.rs b/src/test/ui/borrowck/issue-10876.rs
index d8fff5f1776..20ab905fec4 100644
--- a/src/test/ui/borrowck/issue-10876.rs
+++ b/src/test/ui/borrowck/issue-10876.rs
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(nll)]
-
 enum Nat {
     S(Box<Nat>),
     Z
diff --git a/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs b/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs
index a8bfdbad38b..7d5acb95751 100644
--- a/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs
+++ b/src/test/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs
@@ -8,8 +8,6 @@
 
 // run-pass
 
-#![feature(nll)]
-
 fn foo(x: &mut Result<(u32, u32), (u32, u32)>) -> u32 {
     match *x {
         Ok((ref mut v, _)) | Err((_, ref mut v)) if *v > 0 => { *v }
diff --git a/src/test/ui/borrowck/issue-52713-bug.rs b/src/test/ui/borrowck/issue-52713-bug.rs
index 460e6b4bbae..671e83dfadc 100644
--- a/src/test/ui/borrowck/issue-52713-bug.rs
+++ b/src/test/ui/borrowck/issue-52713-bug.rs
@@ -2,8 +2,6 @@
 // computing liveness that wound up accidentally causing the program
 // below to be accepted.
 
-#![feature(nll)]
-
 fn foo<'a>(x: &'a mut u32) -> u32 {
     let mut x = 22;
     let y = &x;
diff --git a/src/test/ui/borrowck/issue-52713-bug.stderr b/src/test/ui/borrowck/issue-52713-bug.stderr
index e3216f5d33f..4abb6fb2c71 100644
--- a/src/test/ui/borrowck/issue-52713-bug.stderr
+++ b/src/test/ui/borrowck/issue-52713-bug.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/issue-52713-bug.rs:14:5
+  --> $DIR/issue-52713-bug.rs:12:5
    |
 LL |     let y = &x;
    |             -- borrow of `x` occurs here
diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs
index ad4accbbeee..51df40016d8 100644
--- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs
+++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 #![allow(dead_code)]
 
 #[derive(Debug)]
diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
index 6a12016b2a5..519f1d6fb27 100644
--- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
+++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:16:13
+  --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:14:13
    |
 LL |             *array
    |             ^^^^^^
diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs
index 0f3f1a639f7..efa313a9d23 100644
--- a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs
+++ b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.rs
@@ -1,19 +1,11 @@
-// ignore-compare-mode-nll
-
-// revisions: migrate nll
-
-#![cfg_attr(nll, feature(nll))]
-
 fn main() {
     let mut greeting = "Hello world!".to_string();
     let res = (|| (|| &greeting)())();
 
     greeting = "DEALLOCATED".to_string();
-    //[migrate]~^ ERROR cannot assign
-    //[nll]~^^ ERROR cannot assign
+    //~^ ERROR cannot assign
     drop(greeting);
-    //[migrate]~^ ERROR cannot move
-    //[nll]~^^ ERROR cannot move
+    //~^ ERROR cannot move
 
     println!("thread result: {:?}", res);
 }
diff --git a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.nll.stderr b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr
index efd4e1a1716..9b1d6fa7d35 100644
--- a/src/test/ui/borrowck/issue-58776-borrowck-scans-children.nll.stderr
+++ b/src/test/ui/borrowck/issue-58776-borrowck-scans-children.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `greeting` because it is borrowed
-  --> $DIR/issue-58776-borrowck-scans-children.rs:11:5
+  --> $DIR/issue-58776-borrowck-scans-children.rs:5:5
    |
 LL |     let res = (|| (|| &greeting)())();
    |                --      -------- borrow occurs due to use in closure
@@ -13,7 +13,7 @@ LL |     println!("thread result: {:?}", res);
    |                                     --- borrow later used here
 
 error[E0505]: cannot move out of `greeting` because it is borrowed
-  --> $DIR/issue-58776-borrowck-scans-children.rs:14:10
+  --> $DIR/issue-58776-borrowck-scans-children.rs:7:10
    |
 LL |     let res = (|| (|| &greeting)())();
    |                --      -------- borrow occurs due to use in closure
diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr
new file mode 100644
index 00000000000..0da715bbdb7
--- /dev/null
+++ b/src/test/ui/borrowck/issue-7573.nll.stderr
@@ -0,0 +1,14 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/issue-7573.rs:21:9
+   |
+LL |     let mut lines_to_use: Vec<&CrateId> = Vec::new();
+   |         ---------------- `lines_to_use` is declared here, outside of the closure body
+LL |
+LL |     let push_id = |installed_id: &CrateId| {
+   |                    ------------ `installed_id` is a reference that is only valid in the closure body
+...
+LL |         lines_to_use.push(installed_id);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
new file mode 100644
index 00000000000..4797a9d456c
--- /dev/null
+++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr
@@ -0,0 +1,12 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-bound-fn-2.rs:8:18
+   |
+LL |     let mut x = None;
+   |         ----- `x` is declared here, outside of the closure body
+LL |     with_int(|y| x = Some(y));
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr
new file mode 100644
index 00000000000..2b3a9816e45
--- /dev/null
+++ b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr
@@ -0,0 +1,12 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-bound-fn.rs:8:18
+   |
+LL |     let mut x: Option<&isize> = None;
+   |         ----- `x` is declared here, outside of the closure body
+LL |     with_int(|y| x = Some(y));
+   |               -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |               |
+   |               `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr
new file mode 100644
index 00000000000..8ceefd25344
--- /dev/null
+++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr
@@ -0,0 +1,12 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-escape-unboxed-closure.rs:6:23
+   |
+LL |     let mut x: Option<&isize> = None;
+   |         ----- `x` is declared here, outside of the closure body
+LL |     with_int(&mut |y| x = Some(y));
+   |                    -  ^^^^^^^^^^^ `y` escapes the closure body here
+   |                    |
+   |                    `y` is a reference that is only valid in the closure body
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/borrowck/two-phase-across-loop.rs b/src/test/ui/borrowck/two-phase-across-loop.rs
index b1a4c54f49b..12222342c95 100644
--- a/src/test/ui/borrowck/two-phase-across-loop.rs
+++ b/src/test/ui/borrowck/two-phase-across-loop.rs
@@ -1,8 +1,6 @@
 // Test that a borrow which starts as a 2-phase borrow and gets
 // carried around a loop winds up conflicting with itself.
 
-#![feature(nll)]
-
 struct Foo { x: String }
 
 impl Foo {
diff --git a/src/test/ui/borrowck/two-phase-across-loop.stderr b/src/test/ui/borrowck/two-phase-across-loop.stderr
index 933d3eb7111..38993a50bf6 100644
--- a/src/test/ui/borrowck/two-phase-across-loop.stderr
+++ b/src/test/ui/borrowck/two-phase-across-loop.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `foo` as mutable more than once at a time
-  --> $DIR/two-phase-across-loop.rs:19:22
+  --> $DIR/two-phase-across-loop.rs:17:22
    |
 LL |         strings.push(foo.get_string());
    |                      ^^^ mutable borrow starts here in previous iteration of loop
diff --git a/src/test/ui/borrowck/two-phase-multi-mut.rs b/src/test/ui/borrowck/two-phase-multi-mut.rs
index ed3d257da9f..bb646d7caf1 100644
--- a/src/test/ui/borrowck/two-phase-multi-mut.rs
+++ b/src/test/ui/borrowck/two-phase-multi-mut.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Foo {
 }
 
diff --git a/src/test/ui/borrowck/two-phase-multi-mut.stderr b/src/test/ui/borrowck/two-phase-multi-mut.stderr
index c4168503e4c..33fa4a3a150 100644
--- a/src/test/ui/borrowck/two-phase-multi-mut.stderr
+++ b/src/test/ui/borrowck/two-phase-multi-mut.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `foo` as mutable more than once at a time
-  --> $DIR/two-phase-multi-mut.rs:13:5
+  --> $DIR/two-phase-multi-mut.rs:11:5
    |
 LL |     foo.method(&mut foo);
    |     ^^^^------^--------^
@@ -9,7 +9,7 @@ LL |     foo.method(&mut foo);
    |     second mutable borrow occurs here
 
 error[E0499]: cannot borrow `foo` as mutable more than once at a time
-  --> $DIR/two-phase-multi-mut.rs:13:16
+  --> $DIR/two-phase-multi-mut.rs:11:16
    |
 LL |     foo.method(&mut foo);
    |     --- ------ ^^^^^^^^ second mutable borrow occurs here
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr
new file mode 100644
index 00000000000..d2ea5ab2077
--- /dev/null
+++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr
@@ -0,0 +1,36 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:13:9
+   |
+LL |         let shared = &v;
+   |                      -- immutable borrow occurs here
+LL | 
+LL |         v.push(shared.len());
+   |         ^      ------ immutable borrow later used here
+   |         |
+   |         mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:24:9
+   |
+LL |         let shared = &v;
+   |                      -- immutable borrow occurs here
+LL | 
+LL |         v.push(shared.len());
+   |         ^      ------ immutable borrow later used here
+   |         |
+   |         mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:37:9
+   |
+LL |         let shared = &v;
+   |                      -- immutable borrow occurs here
+LL | 
+LL |         v.push(shared.len());
+   |         ^      ------ immutable borrow later used here
+   |         |
+   |         mutable borrow occurs here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/c-variadic/variadic-ffi-5.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
index 27421010a97..a1afbb06390 100644
--- a/src/test/ui/c-variadic/variadic-ffi-5.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr
@@ -1,5 +1,5 @@
 error[E0621]: explicit lifetime required in the type of `ap`
-  --> $DIR/variadic-ffi-5.rs:11:5
+  --> $DIR/variadic-ffi-4.rs:8:5
    |
 LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> {
    |                                                       --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>`
@@ -7,7 +7,7 @@ LL |     ap
    |     ^^ lifetime `'a` required
 
 error[E0621]: explicit lifetime required in the type of `ap`
-  --> $DIR/variadic-ffi-5.rs:15:5
+  --> $DIR/variadic-ffi-4.rs:12:5
    |
 LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> {
    |                                                   --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>`
@@ -15,7 +15,7 @@ LL |     ap
    |     ^^ lifetime `'static` required
 
 error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-5.rs:19:33
+  --> $DIR/variadic-ffi-4.rs:16:33
    |
 LL |     let _ = ap.with_copy(|ap| { ap });
    |                           ---   ^^ returning this value requires that `'1` must outlive `'2`
@@ -24,40 +24,48 @@ LL |     let _ = ap.with_copy(|ap| { ap });
    |                           has type `core::ffi::VaList<'1>`
 
 error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-5.rs:23:5
+  --> $DIR/variadic-ffi-4.rs:20:5
    |
-LL | pub unsafe extern "C" fn no_escape3(_: usize, ap0: &mut VaList, mut ap1: ...) {
-   |                                               ---               ------- has type `core::ffi::VaList<'1>`
+LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
+   |                                               -------               ------- has type `core::ffi::VaList<'1>`
    |                                               |
    |                                               has type `&mut core::ffi::VaList<'2>`
 LL |     *ap0 = ap1;
    |     ^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-5.rs:27:5
+  --> $DIR/variadic-ffi-4.rs:24:5
    |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
-   |                                               -------               ------- has type `core::ffi::VaList<'2>`
+LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) {
+   |                                               ---               ------- has type `core::ffi::VaList<'2>`
    |                                               |
    |                                               has type `&mut core::ffi::VaList<'1>`
 LL |     ap0 = &mut ap1;
    |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/variadic-ffi-5.rs:27:5
+  --> $DIR/variadic-ffi-4.rs:24:5
    |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
-   |                                               -------               ------- has type `core::ffi::VaList<'1>`
+LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) {
+   |                                               ---               ------- has type `core::ffi::VaList<'1>`
    |                                               |
    |                                               has type `&mut core::ffi::VaList<'2>`
 LL |     ap0 = &mut ap1;
    |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
 
+error[E0384]: cannot assign to immutable argument `ap0`
+  --> $DIR/variadic-ffi-4.rs:24:5
+   |
+LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) {
+   |                                               --- help: make this binding mutable: `mut ap0`
+LL |     ap0 = &mut ap1;
+   |     ^^^^^^^^^^^^^^ cannot assign to immutable argument
+
 error[E0597]: `ap1` does not live long enough
-  --> $DIR/variadic-ffi-5.rs:27:11
+  --> $DIR/variadic-ffi-4.rs:24:11
    |
-LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
-   |                                                        - let's call the lifetime of this reference `'1`
+LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) {
+   |                                                    - let's call the lifetime of this reference `'1`
 LL |     ap0 = &mut ap1;
    |     ------^^^^^^^^
    |     |     |
@@ -67,7 +75,7 @@ LL |     ap0 = &mut ap1;
 LL | }
    |  - `ap1` dropped here while still borrowed
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0597, E0621.
-For more information about an error, try `rustc --explain E0597`.
+Some errors have detailed explanations: E0384, E0597, E0621.
+For more information about an error, try `rustc --explain E0384`.
diff --git a/src/test/ui/c-variadic/variadic-ffi-5.rs b/src/test/ui/c-variadic/variadic-ffi-5.rs
deleted file mode 100644
index fcc80d9b0cc..00000000000
--- a/src/test/ui/c-variadic/variadic-ffi-5.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-#![crate_type="lib"]
-#![no_std]
-#![feature(c_variadic)]
-// The tests in this file are similar to that of variadic-ffi-4, but this
-// one enables nll.
-#![feature(nll)]
-
-use core::ffi::VaList;
-
-pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> {
-    ap //~ ERROR: explicit lifetime required
-}
-
-pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> {
-    ap //~ ERROR: explicit lifetime required
-}
-
-pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) {
-    let _ = ap.with_copy(|ap| { ap }); //~ ERROR: lifetime may not live long enough
-}
-
-pub unsafe extern "C" fn no_escape3(_: usize, ap0: &mut VaList, mut ap1: ...) {
-    *ap0 = ap1; //~ ERROR: lifetime may not live long enough
-}
-
-pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
-    ap0 = &mut ap1;
-    //~^ ERROR: lifetime may not live long enough
-    //~^^ ERROR: lifetime may not live long enough
-    //~^^^ ERROR: `ap1` does not live long enough
-}
diff --git a/src/test/ui/cdylib-deps-must-be-static.rs b/src/test/ui/cdylib-deps-must-be-static.rs
index 241cc96fec0..8530c9e24b2 100644
--- a/src/test/ui/cdylib-deps-must-be-static.rs
+++ b/src/test/ui/cdylib-deps-must-be-static.rs
@@ -3,7 +3,7 @@
 // ignore-musl
 // ignore-cloudabi
 // ignore-emscripten
-
+// ignore-sgx no dynamic libraries
 #![crate_type = "cdylib"]
 
 extern crate cdylib_dep;
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
new file mode 100644
index 00000000000..7e4ac4e8ce6
--- /dev/null
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
@@ -0,0 +1,53 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:30:5
+   |
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
+   |     |
+   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+   |
+note: required by `with_closure_expecting_fn_with_free_region`
+  --> $DIR/expect-fn-supply-fn.rs:1:1
+   |
+LL | / fn with_closure_expecting_fn_with_free_region<F>(_: F)
+LL | |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
+LL | | {
+LL | | }
+   | |_^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:37:5
+   |
+LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
+   |     |
+   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |
+note: required by `with_closure_expecting_fn_with_bound_region`
+  --> $DIR/expect-fn-supply-fn.rs:6:1
+   |
+LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+LL | |     where F: FnOnce(fn(&u32), &i32)
+LL | | {
+LL | | }
+   | |_^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:46:5
+   |
+LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
+   |     |
+   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |
+note: required by `with_closure_expecting_fn_with_bound_region`
+  --> $DIR/expect-fn-supply-fn.rs:6:1
+   |
+LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+LL | |     where F: FnOnce(fn(&u32), &i32)
+LL | | {
+LL | | }
+   | |_^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr
new file mode 100644
index 00000000000..1d12e2f585e
--- /dev/null
+++ b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.nll.stderr
@@ -0,0 +1,37 @@
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5
+   |
+LL |   fn foo(x: &()) {
+   |             --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()`
+LL | /     bar(|| {
+LL | |
+LL | |         let _ = x;
+LL | |     })
+   | |______^ lifetime `'static` required
+
+error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
+  --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:9
+   |
+LL |     bar(|| {
+   |         ^^ may outlive borrowed value `x`
+LL |
+LL |         let _ = x;
+   |                 - `x` is borrowed here
+   |
+note: function requires argument type to outlive `'static`
+  --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5
+   |
+LL | /     bar(|| {
+LL | |
+LL | |         let _ = x;
+LL | |     })
+   | |______^
+help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
+   |
+LL |     bar(move || {
+   |         ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0373, E0621.
+For more information about an error, try `rustc --explain E0373`.
diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr
new file mode 100644
index 00000000000..bbf75302d56
--- /dev/null
+++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr
@@ -0,0 +1,42 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/expect-region-supply-region.rs:18:9
+   |
+LL |     let mut f: Option<&u32> = None;
+   |         ----- `f` is declared here, outside of the closure body
+LL |     closure_expecting_bound(|x| {
+   |                              - `x` is a reference that is only valid in the closure body
+LL |         f = Some(x);
+   |         ^^^^^^^^^^^ `x` escapes the closure body here
+
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/expect-region-supply-region.rs:28:9
+   |
+LL |     let mut f: Option<&u32> = None;
+   |         ----- `f` is declared here, outside of the closure body
+LL |     closure_expecting_bound(|x: &u32| {
+   |                              - `x` is a reference that is only valid in the closure body
+LL |         f = Some(x);
+   |         ^^^^^^^^^^^ `x` escapes the closure body here
+
+error: lifetime may not live long enough
+  --> $DIR/expect-region-supply-region.rs:37:30
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(|x: &'x u32| {
+   |                              ^  - let's call the lifetime of this reference `'1`
+   |                              |
+   |                              requires that `'1` must outlive `'x`
+
+error: lifetime may not live long enough
+  --> $DIR/expect-region-supply-region.rs:37:30
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(|x: &'x u32| {
+   |                              ^ requires that `'x` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs
new file mode 100644
index 00000000000..c3f5e360fe2
--- /dev/null
+++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs
@@ -0,0 +1,11 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+// We should probably be able to infer the types here. However, this test is checking that we don't
+// get an ICE in this case. It may be modified later to not be an error.
+
+struct Foo<const NUM_BYTES: usize>(pub [u8; NUM_BYTES]);
+
+fn main() {
+    let _ = Foo::<3>([1, 2, 3]); //~ ERROR type annotations needed
+}
diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr
new file mode 100644
index 00000000000..a0641bd2fdc
--- /dev/null
+++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr
@@ -0,0 +1,15 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/cannot-infer-type-for-const-param.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+
+error[E0282]: type annotations needed
+  --> $DIR/cannot-infer-type-for-const-param.rs:10:19
+   |
+LL |     let _ = Foo::<3>([1, 2, 3]);
+   |                   ^ cannot infer type for `{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/const-generics/impl-const-generic-struct.rs b/src/test/ui/const-generics/impl-const-generic-struct.rs
new file mode 100644
index 00000000000..7a0c0f2be5d
--- /dev/null
+++ b/src/test/ui/const-generics/impl-const-generic-struct.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct S<const X: u32>;
+
+impl<const X: u32> S<{X}> {
+    fn x() -> u32 {
+        X
+    }
+}
+
+fn main() {
+    assert_eq!(S::<19>::x(), 19);
+}
diff --git a/src/test/ui/const-generics/impl-const-generic-struct.stderr b/src/test/ui/const-generics/impl-const-generic-struct.stderr
new file mode 100644
index 00000000000..d443e060a97
--- /dev/null
+++ b/src/test/ui/const-generics/impl-const-generic-struct.stderr
@@ -0,0 +1,6 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/impl-const-generic-struct.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs b/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs
new file mode 100644
index 00000000000..b069cd89680
--- /dev/null
+++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs
@@ -0,0 +1,9 @@
+use std::convert::TryInto;
+
+struct S;
+
+fn main() {
+    let _: u32 = 5i32.try_into::<32>().unwrap(); //~ ERROR wrong number of const arguments
+    S.f::<0>(); //~ ERROR no method named `f`
+    S::<0>; //~ ERROR  wrong number of const arguments
+}
diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
new file mode 100644
index 00000000000..8f3f91651ed
--- /dev/null
+++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
@@ -0,0 +1,25 @@
+error[E0107]: wrong number of const arguments: expected 0, found 1
+  --> $DIR/invalid-const-arg-for-type-param.rs:6:34
+   |
+LL |     let _: u32 = 5i32.try_into::<32>().unwrap();
+   |                                  ^^ unexpected const argument
+
+error[E0599]: no method named `f` found for type `S` in the current scope
+  --> $DIR/invalid-const-arg-for-type-param.rs:7:7
+   |
+LL | struct S;
+   | --------- method `f` not found for this
+...
+LL |     S.f::<0>();
+   |       ^
+
+error[E0107]: wrong number of const arguments: expected 0, found 1
+  --> $DIR/invalid-const-arg-for-type-param.rs:8:9
+   |
+LL |     S::<0>;
+   |         ^ unexpected const argument
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0599.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs b/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs
index 06b1727258d..34f61ed5a34 100644
--- a/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs
+++ b/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs
@@ -1,7 +1,5 @@
 // compile-pass
 
-#![feature(nll)]
-
 pub fn main() {
     let y: &'static mut [u8; 0] = &mut [];
 }
diff --git a/src/test/ui/consts/const_let_refutable.nll.stderr b/src/test/ui/consts/const_let_refutable.nll.stderr
new file mode 100644
index 00000000000..30ab1f4d5ec
--- /dev/null
+++ b/src/test/ui/consts/const_let_refutable.nll.stderr
@@ -0,0 +1,31 @@
+error[E0005]: refutable pattern in function argument: `&[]` not covered
+  --> $DIR/const_let_refutable.rs:3:16
+   |
+LL | const fn slice([a, b]: &[i32]) -> i32 {
+   |                ^^^^^^ pattern `&[]` not covered
+
+error[E0723]: can only call other `const fn` within a `const fn`, but `const std::ops::Add::add` is not stable as `const fn`
+  --> $DIR/const_let_refutable.rs:4:5
+   |
+LL |     a + b
+   |     ^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0381]: use of possibly uninitialized variable: `a`
+  --> $DIR/const_let_refutable.rs:4:5
+   |
+LL |     a + b
+   |     ^ use of possibly uninitialized `a`
+
+error[E0381]: use of possibly uninitialized variable: `b`
+  --> $DIR/const_let_refutable.rs:4:9
+   |
+LL |     a + b
+   |         ^ use of possibly uninitialized `b`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0005, E0381, E0723.
+For more information about an error, try `rustc --explain E0005`.
diff --git a/src/test/ui/consts/issue-54224.rs b/src/test/ui/consts/issue-54224.rs
index b5a8fe8819c..f1947933d67 100644
--- a/src/test/ui/consts/issue-54224.rs
+++ b/src/test/ui/consts/issue-54224.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]); //~ ERROR temporary value dropped while borrowed
 
 use std::borrow::Cow;
diff --git a/src/test/ui/consts/issue-54224.stderr b/src/test/ui/consts/issue-54224.stderr
index 9b6638b228e..8dcb4daca3b 100644
--- a/src/test/ui/consts/issue-54224.stderr
+++ b/src/test/ui/consts/issue-54224.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-54224.rs:3:39
+  --> $DIR/issue-54224.rs:1:39
    |
 LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]);
    |                                 ------^^^^^^^^^-
@@ -9,7 +9,7 @@ LL | const FOO: Option<&[[u8; 3]]> = Some(&[*b"foo"]);
    |                                 using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-54224.rs:11:57
+  --> $DIR/issue-54224.rs:9:57
    |
 LL | pub const Z: Cow<'static, [ [u8; 3] ]> = Cow::Borrowed(&[*b"ABC"]);
    |                                          ---------------^^^^^^^^^-
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
new file mode 100644
index 00000000000..8d962384a12
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
@@ -0,0 +1,328 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:37:25
+   |
+LL |     const fn into_inner(self) -> T { self.0 }
+   |                         ^^^^ constant functions cannot evaluate destructors
+
+error[E0723]: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:39:36
+   |
+LL |     const fn get_mut(&mut self) -> &mut T { &mut self.0 }
+   |                                    ^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:44:28
+   |
+LL |     const fn into_inner_lt(self) -> T { self.0 }
+   |                            ^^^^ constant functions cannot evaluate destructors
+
+error[E0723]: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:46:42
+   |
+LL |     const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
+   |                                          ^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/min_const_fn.rs:51:27
+   |
+LL |     const fn into_inner_s(self) -> T { self.0 }
+   |                           ^^^^ constant functions cannot evaluate destructors
+
+error[E0723]: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:53:38
+   |
+LL |     const fn get_mut_s(&mut self) -> &mut T { &mut self.0 }
+   |                                      ^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:58:39
+   |
+LL |     const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 }
+   |                                       ^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:76:16
+   |
+LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
+   |                ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:78:18
+   |
+LL | const fn foo11_2<T: Send>(t: T) -> T { t }
+   |                  ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = 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.rs:80:33
+   |
+LL | const fn foo19(f: f32) -> f32 { f * 2.0 }
+   |                                 ^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = 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.rs:82:35
+   |
+LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f }
+   |                                   ^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: only int and `bool` operations are stable in const fn
+  --> $DIR/min_const_fn.rs:84:35
+   |
+LL | const fn foo19_3(f: f32) -> f32 { -f }
+   |                                   ^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = 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.rs:86:43
+   |
+LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g }
+   |                                           ^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: cannot access `static` items in const fn
+  --> $DIR/min_const_fn.rs:90:27
+   |
+LL | const fn foo25() -> u32 { BAR }
+   |                           ^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: cannot access `static` items in const fn
+  --> $DIR/min_const_fn.rs:91:36
+   |
+LL | const fn foo26() -> &'static u32 { &BAR }
+   |                                    ^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:92:42
+   |
+LL | const fn foo30(x: *const u32) -> usize { x as usize }
+   |                                          ^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:94:63
+   |
+LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
+   |                                                               ^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:96:42
+   |
+LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
+   |                                          ^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: casting pointers to ints is unstable in const fn
+  --> $DIR/min_const_fn.rs:98:63
+   |
+LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
+   |                                                               ^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:100:38
+   |
+LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:102:29
+   |
+LL | const fn foo30_5(b: bool) { while b { } }
+   |                             ^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:104:44
+   |
+LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
+   |                                            ^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: `if`, `match`, `&&` and `||` are not stable in const fn
+  --> $DIR/min_const_fn.rs:106:44
+   |
+LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
+   |                                            ^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: mutable references in const fn are unstable
+  --> $DIR/min_const_fn.rs:108:14
+   |
+LL | const fn inc(x: &mut i32) { *x += 1 }
+   |              ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:113:6
+   |
+LL | impl<T: std::fmt::Debug> Foo<T> {
+   |      ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:118:6
+   |
+LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
+   |      ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:123:6
+   |
+LL | impl<T: Sync + Sized> Foo<T> {
+   |      ^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: `impl Trait` in const fn is unstable
+  --> $DIR/min_const_fn.rs:129:24
+   |
+LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:131:34
+   |
+LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
+   |                                  ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:133:22
+   |
+LL | const fn no_apit(_x: impl std::fmt::Debug) {}
+   |                      ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: `impl Trait` in const fn is unstable
+  --> $DIR/min_const_fn.rs:134:23
+   |
+LL | const fn no_rpit() -> impl std::fmt::Debug {}
+   |                       ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:135:23
+   |
+LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
+   |                       ^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:136:32
+   |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0515]: cannot return reference to temporary value
+  --> $DIR/min_const_fn.rs:136:63
+   |
+LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
+   |                                                               ^--
+   |                                                               ||
+   |                                                               |temporary value created here
+   |                                                               returns a reference to data owned by the current function
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:144:41
+   |
+LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: function pointers in const fn are unstable
+  --> $DIR/min_const_fn.rs:147:21
+   |
+LL | const fn no_fn_ptrs(_x: fn()) {}
+   |                     ^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: function pointers in const fn are unstable
+  --> $DIR/min_const_fn.rs:149:27
+   |
+LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
+   |                           ^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error: aborting due to 37 previous errors
+
+Some errors have detailed explanations: E0515, E0723.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr
new file mode 100644
index 00000000000..9ffb549057b
--- /dev/null
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr
@@ -0,0 +1,31 @@
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn_dyn.rs:9:5
+   |
+LL |     x.0.field;
+   |     ^^^^^^^^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn_dyn.rs:12:66
+   |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+   |                                                                  ^^
+   |
+   = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563
+   = help: add #![feature(const_fn)] to the crate attributes to enable
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/min_const_fn_dyn.rs:12:67
+   |
+LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
+   |                                                                  -^    - temporary value is freed at the end of this statement
+   |                                                                  ||
+   |                                                                  |creates a temporary which is freed while still in use
+   |                                                                  cast requires that borrow lasts for `'static`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0716, E0723.
+For more information about an error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/promote_evaluation_unused_result.rs b/src/test/ui/consts/promote_evaluation_unused_result.rs
index d199e34775e..dc21b9fe8cd 100644
--- a/src/test/ui/consts/promote_evaluation_unused_result.rs
+++ b/src/test/ui/consts/promote_evaluation_unused_result.rs
@@ -1,7 +1,5 @@
 //compile-pass
 
-#![feature(nll)]
-
 fn main() {
 
     let _: &'static usize = &(loop {}, 1).1;
diff --git a/src/test/ui/consts/promote_fn_calls.rs b/src/test/ui/consts/promote_fn_calls.rs
index 045322de347..6b6eea36361 100644
--- a/src/test/ui/consts/promote_fn_calls.rs
+++ b/src/test/ui/consts/promote_fn_calls.rs
@@ -1,8 +1,6 @@
 // compile-pass
 // aux-build:promotable_const_fn_lib.rs
 
-#![feature(nll)]
-
 extern crate promotable_const_fn_lib;
 
 use promotable_const_fn_lib::{foo, Foo};
diff --git a/src/test/ui/consts/promote_fn_calls_std.rs b/src/test/ui/consts/promote_fn_calls_std.rs
index 0350708d673..d982f350208 100644
--- a/src/test/ui/consts/promote_fn_calls_std.rs
+++ b/src/test/ui/consts/promote_fn_calls_std.rs
@@ -1,7 +1,5 @@
 // compile-pass
 
-#![feature(nll)]
-
 fn main() {
     let x: &'static u8 = &u8::max_value();
     let x: &'static u16 = &u16::max_value();
diff --git a/src/test/ui/consts/std/alloc.rs b/src/test/ui/consts/std/alloc.rs
new file mode 100644
index 00000000000..65ac7e44926
--- /dev/null
+++ b/src/test/ui/consts/std/alloc.rs
@@ -0,0 +1,10 @@
+use std::alloc::Layout;
+
+// ok
+const LAYOUT_VALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x08) };
+
+// not ok, since alignment needs to be non-zero.
+const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+//~^ ERROR it is undefined behavior to use this value
+
+fn main() {}
diff --git a/src/test/ui/consts/std/alloc.stderr b/src/test/ui/consts/std/alloc.stderr
new file mode 100644
index 00000000000..74a8f3daf6a
--- /dev/null
+++ b/src/test/ui/consts/std/alloc.stderr
@@ -0,0 +1,11 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/alloc.rs:7:1
+   |
+LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/continue-after-missing-main.nll.stderr b/src/test/ui/continue-after-missing-main.nll.stderr
new file mode 100644
index 00000000000..aceabf33164
--- /dev/null
+++ b/src/test/ui/continue-after-missing-main.nll.stderr
@@ -0,0 +1,7 @@
+error[E0601]: `main` function not found in crate `continue_after_missing_main`
+   |
+   = note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/empty/empty-never-array.nll.stderr b/src/test/ui/empty/empty-never-array.nll.stderr
new file mode 100644
index 00000000000..01ee1c3a4d7
--- /dev/null
+++ b/src/test/ui/empty/empty-never-array.nll.stderr
@@ -0,0 +1,23 @@
+error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
+  --> $DIR/empty-never-array.rs:10:9
+   |
+LL | / enum Helper<T, U> {
+LL | |     T(T, [!; 0]),
+LL | |     #[allow(dead_code)]
+LL | |     U(U),
+LL | | }
+   | |_- `Helper<T, U>` defined here
+...
+LL |       let Helper::U(u) = Helper::T(t, []);
+   |           ^^^^^^^^^^^^ pattern `T(_, _)` not covered
+
+error[E0381]: use of possibly uninitialized variable: `u`
+  --> $DIR/empty-never-array.rs:12:5
+   |
+LL |     u
+   |     ^ use of possibly uninitialized `u`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0005, E0381.
+For more information about an error, try `rustc --explain E0005`.
diff --git a/src/test/ui/error-codes/E0502.nll.stderr b/src/test/ui/error-codes/E0502.nll.stderr
new file mode 100644
index 00000000000..e5671ee49e6
--- /dev/null
+++ b/src/test/ui/error-codes/E0502.nll.stderr
@@ -0,0 +1,13 @@
+error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable
+  --> $DIR/E0502.rs:4:9
+   |
+LL |     let ref y = a;
+   |         ----- immutable borrow occurs here
+LL |     bar(a);
+   |         ^ mutable borrow occurs here
+LL |     y.use_ref();
+   |     - immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
new file mode 100644
index 00000000000..5140d1a9a7a
--- /dev/null
+++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45
+   |
+LL |     invoke(&x, |a, b| if a > b { a } else { b });
+   |                    --                       ^ returning this value requires that `'1` must outlive `'2`
+   |                    ||
+   |                    |return type of closure is &'2 i32
+   |                    has type `&'1 i32`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr
index 03867a8e43b..359725a41c1 100644
--- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr
+++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr
@@ -1,8 +1,8 @@
 error: unexpected token: `,`
-  --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:15
+  --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:17
    |
 LL |         [_, 99.., _] => {},
-   |               ^^
+   |                 ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr
index 5ac435bf011..8f849d7b3f8 100644
--- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr
+++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr
@@ -1,8 +1,8 @@
 error: unexpected token: `]`
-  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:15
+  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:17
    |
 LL |         [_, 99..] => {},
-   |               ^^
+   |                 ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/existential-type/issue-60371.rs b/src/test/ui/existential-type/issue-60371.rs
new file mode 100644
index 00000000000..f9def11d193
--- /dev/null
+++ b/src/test/ui/existential-type/issue-60371.rs
@@ -0,0 +1,15 @@
+trait Bug {
+    type Item: Bug;
+
+    const FUN: fn() -> Self::Item;
+}
+
+impl Bug for &() {
+    existential type Item: Bug; //~ ERROR existential types are unstable
+    //~^ ERROR the trait bound `(): Bug` is not satisfied
+    //~^^ ERROR could not find defining uses
+
+    const FUN: fn() -> Self::Item = || ();
+}
+
+fn main() {}
diff --git a/src/test/ui/existential-type/issue-60371.stderr b/src/test/ui/existential-type/issue-60371.stderr
new file mode 100644
index 00000000000..2560e01047a
--- /dev/null
+++ b/src/test/ui/existential-type/issue-60371.stderr
@@ -0,0 +1,29 @@
+error[E0658]: existential types are unstable
+  --> $DIR/issue-60371.rs:8:5
+   |
+LL |     existential type Item: Bug;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/34511
+   = help: add #![feature(existential_type)] to the crate attributes to enable
+
+error[E0277]: the trait bound `(): Bug` is not satisfied
+  --> $DIR/issue-60371.rs:8:5
+   |
+LL |     existential type Item: Bug;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bug` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <&() as Bug>
+   = note: the return type of a function must have a statically known size
+
+error: could not find defining uses
+  --> $DIR/issue-60371.rs:8:5
+   |
+LL |     existential type Item: Bug;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr
new file mode 100644
index 00000000000..f316644156d
--- /dev/null
+++ b/src/test/ui/existential_types/generic_type_does_not_live_long_enough.nll.stderr
@@ -0,0 +1,18 @@
+error: at least one trait must be specified
+  --> $DIR/generic_type_does_not_live_long_enough.rs:9:35
+   |
+LL | existential type WrongGeneric<T>: 'static;
+   |                                   ^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/generic_type_does_not_live_long_enough.rs:6:18
+   |
+LL |     let z: i32 = x;
+   |                  ^ expected i32, found opaque type
+   |
+   = note: expected type `i32`
+              found type `WrongGeneric::<&{integer}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/existential_types/issue-60655-latebound-regions.rs b/src/test/ui/existential_types/issue-60655-latebound-regions.rs
new file mode 100644
index 00000000000..a4fe8650129
--- /dev/null
+++ b/src/test/ui/existential_types/issue-60655-latebound-regions.rs
@@ -0,0 +1,30 @@
+// Test that existential types are allowed to contain late-bound regions.
+
+// compile-pass
+// edition:2018
+
+#![feature(async_await, existential_type)]
+
+use std::future::Future;
+
+pub existential type Func: Sized;
+
+// Late bound region should be allowed to escape the function, since it's bound
+// in the type.
+fn null_function_ptr() -> Func {
+    None::<for<'a> fn(&'a ())>
+}
+
+async fn async_nop(_: &u8) {}
+
+pub existential type ServeFut: Future<Output=()>;
+
+// Late bound regions occur in the generator witness type here.
+fn serve() -> ServeFut {
+    async move {
+        let x = 5;
+        async_nop(&x).await
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gate/await-macro.stderr b/src/test/ui/feature-gate/await-macro.stderr
index b6833655f6d..699a7a8886e 100644
--- a/src/test/ui/feature-gate/await-macro.stderr
+++ b/src/test/ui/feature-gate/await-macro.stderr
@@ -2,7 +2,7 @@ error[E0658]: `await!(<expr>)` macro syntax is unstable, and will soon be remove
   --> $DIR/await-macro.rs:9:5
    |
 LL |     await!(bar());
-   |     ^^^^^
+   |     ^^^^^^^^^^^^^
    |
    = note: for more information, see https://github.com/rust-lang/rust/issues/50547
    = help: add #![feature(await_macro)] to the crate attributes to enable
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index 0129a3f72b2..ca0a432d339 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -52,7 +52,7 @@
 //~^ WARN unused attribute
 #![path = "3800"] //~ WARN unused attribute
 #![automatically_derived] //~ WARN unused attribute
-#![no_mangle] //~ WARN unused attribute
+#![no_mangle]
 #![no_link] //~ WARN unused attribute
 // see issue-43106-gating-of-derive.rs
 #![should_panic] //~ WARN unused attribute
diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
index dcbe13a749f..c7081205e14 100644
--- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr
@@ -1153,12 +1153,6 @@ LL | #![automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: unused attribute
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1
-   |
-LL | #![no_mangle]
-   | ^^^^^^^^^^^^^
-
-warning: unused attribute
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1
    |
 LL | #![no_link]
diff --git a/src/test/ui/generator/auto-trait-regions.nll.stderr b/src/test/ui/generator/auto-trait-regions.nll.stderr
new file mode 100644
index 00000000000..4c157a05a5e
--- /dev/null
+++ b/src/test/ui/generator/auto-trait-regions.nll.stderr
@@ -0,0 +1,41 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:44:24
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                        ^^^^                - temporary value is freed at the end of this statement
+   |                        |
+   |                        creates a temporary which is freed while still in use
+LL |         yield;
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/auto-trait-regions.rs:44:35
+   |
+LL |         let a = A(&mut true, &mut true, No);
+   |                                   ^^^^     - temporary value is freed at the end of this statement
+   |                                   |
+   |                                   creates a temporary which is freed while still in use
+LL |         yield;
+LL |         assert_foo(a);
+   |                    - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error: higher-ranked subtype error
+  --> $DIR/auto-trait-regions.rs:30:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/auto-trait-regions.rs:48:5
+   |
+LL |     assert_foo(gen);
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/generator/generator-region-requirements.rs b/src/test/ui/generator/generator-region-requirements.rs
index cd9abaae056..41cb339f459 100644
--- a/src/test/ui/generator/generator-region-requirements.rs
+++ b/src/test/ui/generator/generator-region-requirements.rs
@@ -1,8 +1,4 @@
-// revisions: migrate nll
-// ignore-compare-mode-nll
-
 #![feature(generators, generator_trait)]
-#![cfg_attr(nll, feature(nll))]
 use std::ops::{Generator, GeneratorState};
 use std::pin::Pin;
 
@@ -14,8 +10,7 @@ fn dangle(x: &mut i32) -> &'static mut i32 {
     loop {
         match Pin::new(&mut g).resume() {
             GeneratorState::Complete(c) => return c,
-//[nll]~^ ERROR explicit lifetime required
-//[migrate]~^^ ERROR explicit lifetime required
+            //~^ ERROR explicit lifetime required
             GeneratorState::Yielded(_) => (),
         }
     }
diff --git a/src/test/ui/generator/generator-region-requirements.nll.stderr b/src/test/ui/generator/generator-region-requirements.stderr
index 8a96d187f6b..53d48bc4f56 100644
--- a/src/test/ui/generator/generator-region-requirements.nll.stderr
+++ b/src/test/ui/generator/generator-region-requirements.stderr
@@ -1,5 +1,5 @@
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/generator-region-requirements.rs:16:51
+  --> $DIR/generator-region-requirements.rs:12:51
    |
 LL | fn dangle(x: &mut i32) -> &'static mut i32 {
    |              -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`
diff --git a/src/test/ui/generator/generator-with-nll.rs b/src/test/ui/generator/generator-with-nll.rs
index 87afa57ab51..cee3e6d226c 100644
--- a/src/test/ui/generator/generator-with-nll.rs
+++ b/src/test/ui/generator/generator-with-nll.rs
@@ -1,5 +1,4 @@
 #![feature(generators)]
-#![feature(nll)]
 
 fn main() {
     || {
diff --git a/src/test/ui/generator/generator-with-nll.stderr b/src/test/ui/generator/generator-with-nll.stderr
index bd5abb20206..14199aeb930 100644
--- a/src/test/ui/generator/generator-with-nll.stderr
+++ b/src/test/ui/generator/generator-with-nll.stderr
@@ -1,5 +1,5 @@
 error[E0626]: borrow may still be in use when generator yields
-  --> $DIR/generator-with-nll.rs:8:17
+  --> $DIR/generator-with-nll.rs:7:17
    |
 LL |         let b = &mut true;
    |                 ^^^^^^^^^
diff --git a/src/test/ui/hashmap-iter-value-lifetime.nll.stderr b/src/test/ui/hashmap-iter-value-lifetime.nll.stderr
new file mode 100644
index 00000000000..312a91adca6
--- /dev/null
+++ b/src/test/ui/hashmap-iter-value-lifetime.nll.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as immutable
+  --> $DIR/hashmap-iter-value-lifetime.rs:7:5
+   |
+LL |     let (_, thing) = my_stuff.iter().next().unwrap();
+   |                      -------- immutable borrow occurs here
+LL | 
+LL |     my_stuff.clear();
+   |     ^^^^^^^^ mutable borrow occurs here
+LL | 
+LL |     println!("{}", *thing);
+   |                    ------ immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/hashmap-lifetimes.nll.stderr b/src/test/ui/hashmap-lifetimes.nll.stderr
new file mode 100644
index 00000000000..aa8e890c168
--- /dev/null
+++ b/src/test/ui/hashmap-lifetimes.nll.stderr
@@ -0,0 +1,13 @@
+error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as immutable
+  --> $DIR/hashmap-lifetimes.rs:6:5
+   |
+LL |     let mut it = my_stuff.iter();
+   |                  -------- immutable borrow occurs here
+LL |     my_stuff.insert(1, 43);
+   |     ^^^^^^^^ mutable borrow occurs here
+LL |     it;
+   |     -- immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
new file mode 100644
index 00000000000..070fe12a284
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
@@ -0,0 +1,30 @@
+error: lifetime may not live long enough
+  --> $DIR/hr-subtype.rs:33:13
+   |
+LL |           fn subtype<'x,'y:'x,'z:'y>() {
+   |                      -- -- lifetime `'y` defined here
+   |                      |
+   |                      lifetime `'x` defined here
+LL |               gimme::<$t2>(None::<$t1>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+LL | |                                     fn(Inv<'y>)) }
+   | |__________________________________________________- in this macro invocation
+
+error: lifetime may not live long enough
+  --> $DIR/hr-subtype.rs:39:13
+   |
+LL |           fn supertype<'x,'y:'x,'z:'y>() {
+   |                        -- -- lifetime `'y` defined here
+   |                        |
+   |                        lifetime `'x` defined here
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+LL | |                                     fn(Inv<'y>)) }
+   | |__________________________________________________- in this macro invocation
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
new file mode 100644
index 00000000000..e140eaadd48
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
@@ -0,0 +1,16 @@
+error: lifetime may not live long enough
+  --> $DIR/hr-subtype.rs:39:13
+   |
+LL |           fn supertype<'x,'y:'x,'z:'y>() {
+   |                        -- -- lifetime `'y` defined here
+   |                        |
+   |                        lifetime `'x` defined here
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_x_vs_free_y: (fn(&'x u32),
+LL | |                             fn(&'y u32)) }
+   | |__________________________________________- in this macro invocation
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr b/src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr
new file mode 100644
index 00000000000..4de35d70c30
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-cache-issue-54302.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-cache-issue-54302.rs:19:5
+   |
+LL |     assert_deserialize_owned::<&'static str>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
new file mode 100644
index 00000000000..0522fc45d68
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr
@@ -0,0 +1,77 @@
+warning: function cannot return without recursing
+  --> $DIR/hrtb-perfect-forwarding.rs:22:1
+   |
+LL | / fn no_hrtb<'b,T>(mut t: T)
+LL | |     where T : Bar<&'b isize>
+LL | | {
+LL | |     // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
+LL | |     // `&mut T : Bar<&'b isize>`.
+LL | |     no_hrtb(&mut t);
+   | |     --------------- recursive call site
+LL | | }
+   | |_^ cannot return without recursing
+   |
+   = note: #[warn(unconditional_recursion)] on by default
+   = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+  --> $DIR/hrtb-perfect-forwarding.rs:30:1
+   |
+LL | / fn bar_hrtb<T>(mut t: T)
+LL | |     where T : for<'b> Bar<&'b isize>
+LL | | {
+LL | |     // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
+...  |
+LL | |     bar_hrtb(&mut t);
+   | |     ---------------- recursive call site
+LL | | }
+   | |_^ cannot return without recursing
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+  --> $DIR/hrtb-perfect-forwarding.rs:39:1
+   |
+LL | / fn foo_hrtb_bar_not<'b,T>(mut t: T)
+LL | |     where T : for<'a> Foo<&'a isize> + Bar<&'b isize>
+LL | | {
+LL | |     // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
+...  |
+LL | |     foo_hrtb_bar_not(&mut t);
+   | |     ------------------------ recursive call site
+LL | | }
+   | |_^ cannot return without recursing
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+   |
+LL |     foo_hrtb_bar_not(&mut t);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/hrtb-perfect-forwarding.rs:46:5
+   |
+LL | fn foo_hrtb_bar_not<'b,T>(mut t: T)
+   |                     -- lifetime `'b` defined here
+...
+LL |     foo_hrtb_bar_not(&mut t);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+
+warning: function cannot return without recursing
+  --> $DIR/hrtb-perfect-forwarding.rs:49:1
+   |
+LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
+LL | |     where T : for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>
+LL | | {
+LL | |     // OK -- now we have `T : for<'b> Bar&'b isize>`.
+LL | |     foo_hrtb_bar_hrtb(&mut t);
+   | |     ------------------------- recursive call site
+LL | | }
+   | |_^ cannot return without recursing
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/if/if-let-arm-types.rs b/src/test/ui/if/if-let-arm-types.rs
index 819f5dd1cfc..0f8815f0479 100644
--- a/src/test/ui/if/if-let-arm-types.rs
+++ b/src/test/ui/if/if-let-arm-types.rs
@@ -1,11 +1,12 @@
 fn main() {
     if let Some(b) = None {
-        //~^ NOTE if let` arms have incompatible types
+        //~^ NOTE if and else have incompatible types
         ()
+        //~^ NOTE expected because of this
     } else {
         1
     };
-    //~^^ ERROR: `if let` arms have incompatible types
+    //~^^ ERROR: if and else have incompatible types
     //~| NOTE expected (), found integer
     //~| NOTE expected type `()`
 }
diff --git a/src/test/ui/if/if-let-arm-types.stderr b/src/test/ui/if/if-let-arm-types.stderr
index b986973fe91..ff88de20f76 100644
--- a/src/test/ui/if/if-let-arm-types.stderr
+++ b/src/test/ui/if/if-let-arm-types.stderr
@@ -1,14 +1,16 @@
-error[E0308]: `if let` arms have incompatible types
-  --> $DIR/if-let-arm-types.rs:6:9
+error[E0308]: if and else have incompatible types
+  --> $DIR/if-let-arm-types.rs:7:9
    |
 LL | /     if let Some(b) = None {
 LL | |
 LL | |         ()
+   | |         -- expected because of this
+LL | |
 LL | |     } else {
 LL | |         1
    | |         ^ expected (), found integer
 LL | |     };
-   | |_____- `if let` arms have incompatible types
+   | |_____- if and else have incompatible types
    |
    = note: expected type `()`
               found type `{integer}`
diff --git a/src/test/ui/if/if-no-match-bindings.rs b/src/test/ui/if/if-no-match-bindings.rs
new file mode 100644
index 00000000000..581ce18c1d6
--- /dev/null
+++ b/src/test/ui/if/if-no-match-bindings.rs
@@ -0,0 +1,22 @@
+// Checks for `if` expressions with respect to default match bindings.
+// Specifically, we do not accept `if cond { ... }` where `cond: &mut? bool`.
+// Meanwhile, `match cond { true => ..., _ => ... }` does accept that.
+
+// FIXME(@rust-lang/lang-team): consider relaxing this?
+
+fn b_ref<'a>() -> &'a bool { &true }
+fn b_mut_ref<'a>() -> &'a mut bool { &mut true }
+
+fn main() {
+    // This is OK:
+    match b_ref() { true => {}, _ => {} }
+    match b_mut_ref() { true => {}, _ => {} }
+    match &true { true => {}, _ => {} }
+    match &mut true { true => {}, _ => {} }
+
+    // This is NOT:
+    if b_ref() {} //~ ERROR mismatched types [E0308]
+    if b_mut_ref() {} //~ ERROR mismatched types [E0308]
+    if &true {} //~ ERROR mismatched types [E0308]
+    if &mut true {} //~ ERROR mismatched types [E0308]
+}
diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr
new file mode 100644
index 00000000000..7b0b472121f
--- /dev/null
+++ b/src/test/ui/if/if-no-match-bindings.stderr
@@ -0,0 +1,39 @@
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:18:8
+   |
+LL |     if b_ref() {}
+   |        ^^^^^^^ expected bool, found &bool
+   |
+   = note: expected type `bool`
+              found type `&bool`
+
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:19:8
+   |
+LL |     if b_mut_ref() {}
+   |        ^^^^^^^^^^^ expected bool, found &mut bool
+   |
+   = note: expected type `bool`
+              found type `&mut bool`
+
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:20:8
+   |
+LL |     if &true {}
+   |        ^^^^^ expected bool, found &bool
+   |
+   = note: expected type `bool`
+              found type `&bool`
+
+error[E0308]: mismatched types
+  --> $DIR/if-no-match-bindings.rs:21:8
+   |
+LL |     if &mut true {}
+   |        ^^^^^^^^^ expected bool, found &mut bool
+   |
+   = note: expected type `bool`
+              found type `&mut bool`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/if/if-without-else-as-fn-expr.rs b/src/test/ui/if/if-without-else-as-fn-expr.rs
index 67e4445629f..15892de8385 100644
--- a/src/test/ui/if/if-without-else-as-fn-expr.rs
+++ b/src/test/ui/if/if-without-else-as-fn-expr.rs
@@ -3,6 +3,7 @@ fn foo(bar: usize) -> usize {
         return 3;
     }
     //~^^^ ERROR if may be missing an else clause
+    //~| ERROR mismatched types [E0308]
 }
 
 fn foo2(bar: usize) -> usize {
@@ -10,6 +11,7 @@ fn foo2(bar: usize) -> usize {
         return 3;
     };
     //~^^^ ERROR if may be missing an else clause
+    //~| ERROR mismatched types [E0308]
     x
 }
 
@@ -18,8 +20,36 @@ fn foo3(bar: usize) -> usize {
         3
     }
     //~^^^ ERROR if may be missing an else clause
+    //~| ERROR mismatched types [E0308]
 }
 
+fn foo_let(bar: usize) -> usize {
+    if let 0 = 1 {
+        return 3;
+    }
+    //~^^^ ERROR if may be missing an else clause
+    //~| ERROR mismatched types [E0308]
+}
+
+fn foo2_let(bar: usize) -> usize {
+    let x: usize = if let 0 = 1 {
+        return 3;
+    };
+    //~^^^ ERROR if may be missing an else clause
+    //~| ERROR mismatched types [E0308]
+    x
+}
+
+fn foo3_let(bar: usize) -> usize {
+    if let 0 = 1 {
+        3
+    }
+    //~^^^ ERROR if may be missing an else clause
+    //~| ERROR mismatched types [E0308]
+}
+
+// FIXME(60254): deduplicate first error in favor of second.
+
 fn main() {
     let _ = foo(1);
 }
diff --git a/src/test/ui/if/if-without-else-as-fn-expr.stderr b/src/test/ui/if/if-without-else-as-fn-expr.stderr
index 0ba72726ca7..06600b1cb9a 100644
--- a/src/test/ui/if/if-without-else-as-fn-expr.stderr
+++ b/src/test/ui/if/if-without-else-as-fn-expr.stderr
@@ -1,3 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/if-without-else-as-fn-expr.rs:2:5
+   |
+LL | /     if bar % 5 == 0 {
+LL | |         return 3;
+LL | |     }
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
 error[E0317]: if may be missing an else clause
   --> $DIR/if-without-else-as-fn-expr.rs:2:5
    |
@@ -13,8 +24,20 @@ LL | |     }
    = note: `if` expressions without `else` evaluate to `()`
    = help: consider adding an `else` block that evaluates to the expected type
 
+error[E0308]: mismatched types
+  --> $DIR/if-without-else-as-fn-expr.rs:10:20
+   |
+LL |       let x: usize = if bar % 5 == 0 {
+   |  ____________________^
+LL | |         return 3;
+LL | |     };
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
 error[E0317]: if may be missing an else clause
-  --> $DIR/if-without-else-as-fn-expr.rs:9:20
+  --> $DIR/if-without-else-as-fn-expr.rs:10:20
    |
 LL |       let x: usize = if bar % 5 == 0 {
    |  _________-__________^
@@ -29,8 +52,19 @@ LL | |     };
    = note: `if` expressions without `else` evaluate to `()`
    = help: consider adding an `else` block that evaluates to the expected type
 
+error[E0308]: mismatched types
+  --> $DIR/if-without-else-as-fn-expr.rs:19:5
+   |
+LL | /     if bar % 5 == 0 {
+LL | |         3
+LL | |     }
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
 error[E0317]: if may be missing an else clause
-  --> $DIR/if-without-else-as-fn-expr.rs:17:5
+  --> $DIR/if-without-else-as-fn-expr.rs:19:5
    |
 LL |   fn foo3(bar: usize) -> usize {
    |                          ----- expected `usize` because of this return type
@@ -44,6 +78,87 @@ LL | |     }
    = note: `if` expressions without `else` evaluate to `()`
    = help: consider adding an `else` block that evaluates to the expected type
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/if-without-else-as-fn-expr.rs:27:5
+   |
+LL | /     if let 0 = 1 {
+LL | |         return 3;
+LL | |     }
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error[E0317]: if may be missing an else clause
+  --> $DIR/if-without-else-as-fn-expr.rs:27:5
+   |
+LL |   fn foo_let(bar: usize) -> usize {
+   |                             ----- expected `usize` because of this return type
+LL | /     if let 0 = 1 {
+LL | |         return 3;
+LL | |     }
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0308]: mismatched types
+  --> $DIR/if-without-else-as-fn-expr.rs:35:20
+   |
+LL |       let x: usize = if let 0 = 1 {
+   |  ____________________^
+LL | |         return 3;
+LL | |     };
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error[E0317]: if may be missing an else clause
+  --> $DIR/if-without-else-as-fn-expr.rs:35:20
+   |
+LL |       let x: usize = if let 0 = 1 {
+   |  _________-__________^
+   | |         |
+   | |         expected because of this assignment
+LL | |         return 3;
+LL | |     };
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+
+error[E0308]: mismatched types
+  --> $DIR/if-without-else-as-fn-expr.rs:44:5
+   |
+LL | /     if let 0 = 1 {
+LL | |         3
+LL | |     }
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+
+error[E0317]: if may be missing an else clause
+  --> $DIR/if-without-else-as-fn-expr.rs:44:5
+   |
+LL |   fn foo3_let(bar: usize) -> usize {
+   |                              ----- expected `usize` because of this return type
+LL | /     if let 0 = 1 {
+LL | |         3
+LL | |     }
+   | |_____^ expected usize, found ()
+   |
+   = note: expected type `usize`
+              found type `()`
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
+
+error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0317`.
+Some errors have detailed explanations: E0308, E0317.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr
new file mode 100644
index 00000000000..da30997a231
--- /dev/null
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr
@@ -0,0 +1,10 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/dyn-trait.rs:20:5
+   |
+LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
+   |                              - `x` is a reference that is only valid in the function body
+LL |     static_val(x);
+   |     ^^^^^^^^^^^^^ `x` escapes the function body here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/bindings-opaque.rs b/src/test/ui/impl-trait/bindings-opaque.rs
index 5f623321943..d4eef29ed32 100644
--- a/src/test/ui/impl-trait/bindings-opaque.rs
+++ b/src/test/ui/impl-trait/bindings-opaque.rs
@@ -1,4 +1,5 @@
 #![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
 
 const FOO: impl Copy = 42;
 
diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr
index 8b2514c0501..d0a6a4ee578 100644
--- a/src/test/ui/impl-trait/bindings-opaque.stderr
+++ b/src/test/ui/impl-trait/bindings-opaque.stderr
@@ -1,17 +1,23 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/bindings-opaque.rs:1:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
-  --> $DIR/bindings-opaque.rs:10:17
+  --> $DIR/bindings-opaque.rs:11:17
    |
 LL |     let _ = FOO.count_ones();
    |                 ^^^^^^^^^^
 
 error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
-  --> $DIR/bindings-opaque.rs:12:17
+  --> $DIR/bindings-opaque.rs:13:17
    |
 LL |     let _ = BAR.count_ones();
    |                 ^^^^^^^^^^
 
 error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope
-  --> $DIR/bindings-opaque.rs:14:17
+  --> $DIR/bindings-opaque.rs:15:17
    |
 LL |     let _ = foo.count_ones();
    |                 ^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/bindings.rs b/src/test/ui/impl-trait/bindings.rs
index 91d092634a9..104a44d6566 100644
--- a/src/test/ui/impl-trait/bindings.rs
+++ b/src/test/ui/impl-trait/bindings.rs
@@ -1,4 +1,5 @@
 #![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
 
 fn a<T: Clone>(x: T) {
     const foo: impl Clone = x;
diff --git a/src/test/ui/impl-trait/bindings.stderr b/src/test/ui/impl-trait/bindings.stderr
index a5bf583afea..c66836ab8e5 100644
--- a/src/test/ui/impl-trait/bindings.stderr
+++ b/src/test/ui/impl-trait/bindings.stderr
@@ -1,23 +1,29 @@
+warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
+  --> $DIR/bindings.rs:1:12
+   |
+LL | #![feature(impl_trait_in_bindings)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/bindings.rs:4:29
+  --> $DIR/bindings.rs:5:29
    |
 LL |     const foo: impl Clone = x;
    |                             ^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/bindings.rs:10:33
+  --> $DIR/bindings.rs:11:33
    |
 LL |         const foo: impl Clone = x;
    |                                 ^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/bindings.rs:17:33
+  --> $DIR/bindings.rs:18:33
    |
 LL |         const foo: impl Clone = x;
    |                                 ^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/bindings.rs:24:33
+  --> $DIR/bindings.rs:25:33
    |
 LL |         const foo: impl Clone = x;
    |                                 ^ non-constant value
diff --git a/src/test/ui/impl-trait/can-return-unconstrained-closure.rs b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs
index a982b176ecd..90a7519074b 100644
--- a/src/test/ui/impl-trait/can-return-unconstrained-closure.rs
+++ b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs
@@ -16,4 +16,8 @@ fn make_identity() -> impl Sized {
     |x: &'static i32| x
 }
 
+fn make_identity_static() -> impl Sized + 'static {
+    |x: &'static i32| x
+}
+
 fn main() {}
diff --git a/src/test/ui/impl-trait/closure-calling-parent-fn.rs b/src/test/ui/impl-trait/closure-calling-parent-fn.rs
index cb5f78bd6fc..58d7875ccd0 100644
--- a/src/test/ui/impl-trait/closure-calling-parent-fn.rs
+++ b/src/test/ui/impl-trait/closure-calling-parent-fn.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // Regression test for #54593: the MIR type checker was going wrong
 // when a closure returns the `impl Copy` from its parent fn. It was
 // (incorrectly) replacing the `impl Copy` in its return type with the
diff --git a/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs b/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs
index 29e271c68ec..11f1a392239 100644
--- a/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs
+++ b/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs
@@ -17,6 +17,13 @@ fn wrapped_closure() -> impl Sized {
     A(f)
 }
 
+fn wrapped_closure_with_bound() -> impl Sized + 'static {
+    let f = |x| x;
+    f(&0);
+    A(f)
+}
+
 fn main() {
     let x: Box<dyn Send> = Box::new(wrapped_closure());
+    let y: Box<dyn Send> = Box::new(wrapped_closure_with_bound());
 }
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
new file mode 100644
index 00000000000..4b7c04f1e43
--- /dev/null
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr
@@ -0,0 +1,51 @@
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:3:23
+   |
+LL | fn elided(x: &i32) -> impl Copy { x }
+   |              -        ^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |              |
+   |              let's call the lifetime of this reference `'1`
+help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+   |
+LL | fn elided(x: &i32) -> impl Copy + '_ { x }
+   |                       ^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+   |
+LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
+   |             --                 ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |             |
+   |             lifetime `'a` defined here
+help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
+   |
+LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
+   |                                ^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:12:69
+   |
+LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
+   |               -- lifetime `'a` defined here                         ^ returning this value requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:17:61
+   |
+LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
+   |                          --  -- lifetime `'b` defined here  ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
+   |                          |
+   |                          lifetime `'a` defined here
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/must_outlive_least_region_or_bound.rs:22:51
+   |
+LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
+   |                                                   ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs
index cb40d90ae55..adaa474474f 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs
+++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant-closure.rs
@@ -9,7 +9,6 @@
 
 #![allow(dead_code)]
 #![feature(in_band_lifetimes)]
-#![feature(nll)]
 
 fn foo(x: &'x u32) -> impl Fn() -> &'y u32
 where 'x: 'y
diff --git a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs
index e2310a3907f..204c2ff3041 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs
+++ b/src/test/ui/impl-trait/region-escape-via-bound-contravariant.rs
@@ -9,7 +9,6 @@
 
 #![allow(dead_code)]
 #![feature(in_band_lifetimes)]
-#![feature(nll)]
 
 trait Trait<'a> { }
 
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.rs b/src/test/ui/impl-trait/region-escape-via-bound.rs
index d62aec800e8..29243699e44 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.rs
+++ b/src/test/ui/impl-trait/region-escape-via-bound.rs
@@ -5,7 +5,6 @@
 
 #![allow(dead_code)]
 #![feature(in_band_lifetimes)]
-#![feature(nll)]
 
 use std::cell::Cell;
 
diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr
index 81b44b7eba7..5c8e322f712 100644
--- a/src/test/ui/impl-trait/region-escape-via-bound.stderr
+++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr
@@ -1,11 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/region-escape-via-bound.rs:16:29
+  --> $DIR/region-escape-via-bound.rs:15:29
    |
 LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
    |                             ^^^^^^^^^^^^^^
    |
-note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 18:7
-  --> $DIR/region-escape-via-bound.rs:18:7
+note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime 'x as defined on the function body at 17:7
+  --> $DIR/region-escape-via-bound.rs:17:7
    |
 LL | where 'x: 'y
    |       ^^
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
new file mode 100644
index 00000000000..0bf120cf7ec
--- /dev/null
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr
@@ -0,0 +1,26 @@
+error: lifetime may not live long enough
+  --> $DIR/static-return-lifetime-infered.rs:6:35
+   |
+LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
+   |                         -         ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+   |                         |
+   |                         let's call the lifetime of this reference `'1`
+help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+   |
+LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/static-return-lifetime-infered.rs:10:37
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+   |                    --               ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
+   |                    |
+   |                    lifetime `'a` defined here
+help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
+   |
+LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
new file mode 100644
index 00000000000..039cb62f866
--- /dev/null
+++ b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr
@@ -0,0 +1,11 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/type_parameters_captured.rs:7:20
+   |
+LL | fn foo<T>(x: T) -> impl Any + 'static {
+   |                    ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/imports/extern-crate-used.rs b/src/test/ui/imports/extern-crate-used.rs
index 2d91cbc00f2..26150c7d4a1 100644
--- a/src/test/ui/imports/extern-crate-used.rs
+++ b/src/test/ui/imports/extern-crate-used.rs
@@ -5,10 +5,14 @@
 
 #![deny(unused_extern_crates)]
 
-extern crate core as iso1; //~ ERROR `extern crate` is not idiomatic in the new edition
-extern crate core as iso2; //~ ERROR `extern crate` is not idiomatic in the new edition
-extern crate core as iso3; //~ ERROR `extern crate` is not idiomatic in the new edition
-extern crate core as iso4; //~ ERROR `extern crate` is not idiomatic in the new edition
+// Shouldn't suggest changing to `use`, as new name
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use the new name in
+// other modules. See #57672.
+extern crate core as iso1;
+extern crate core as iso2;
+extern crate core as iso3;
+extern crate core as iso4;
 
 // Doesn't introduce its extern prelude entry, so it's still considered unused.
 extern crate core; //~ ERROR unused extern crate
diff --git a/src/test/ui/imports/extern-crate-used.stderr b/src/test/ui/imports/extern-crate-used.stderr
index c0783feb794..397bfa02902 100644
--- a/src/test/ui/imports/extern-crate-used.stderr
+++ b/src/test/ui/imports/extern-crate-used.stderr
@@ -1,8 +1,8 @@
-error: `extern crate` is not idiomatic in the new edition
-  --> $DIR/extern-crate-used.rs:8:1
+error: unused extern crate
+  --> $DIR/extern-crate-used.rs:18:1
    |
-LL | extern crate core as iso1;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
+LL | extern crate core;
+   | ^^^^^^^^^^^^^^^^^^ help: remove it
    |
 note: lint level defined here
   --> $DIR/extern-crate-used.rs:6:9
@@ -10,29 +10,5 @@ note: lint level defined here
 LL | #![deny(unused_extern_crates)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: `extern crate` is not idiomatic in the new edition
-  --> $DIR/extern-crate-used.rs:9:1
-   |
-LL | extern crate core as iso2;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: `extern crate` is not idiomatic in the new edition
-  --> $DIR/extern-crate-used.rs:10:1
-   |
-LL | extern crate core as iso3;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: `extern crate` is not idiomatic in the new edition
-  --> $DIR/extern-crate-used.rs:11:1
-   |
-LL | extern crate core as iso4;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: unused extern crate
-  --> $DIR/extern-crate-used.rs:14:1
-   |
-LL | extern crate core;
-   | ^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: aborting due to 5 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr
new file mode 100644
index 00000000000..f5aee2d2d7e
--- /dev/null
+++ b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr
@@ -0,0 +1,20 @@
+error[E0621]: explicit lifetime required in the type of `y`
+  --> $DIR/mismatched.rs:4:42
+   |
+LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y }
+   |                       ----               ^ lifetime `'a` required
+   |                       |
+   |                       help: add explicit lifetime `'a` to the type of `y`: `&'a u32`
+
+error: lifetime may not live long enough
+  --> $DIR/mismatched.rs:6:46
+   |
+LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y }
+   |             --          --                   ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |             |           |
+   |             |           lifetime `'b` defined here
+   |             lifetime `'a` defined here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
new file mode 100644
index 00000000000..cd65bab2d46
--- /dev/null
+++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
@@ -0,0 +1,24 @@
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
+  --> $DIR/mismatched_trait_impl.rs:9:5
+   |
+LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5...
+  --> $DIR/mismatched_trait_impl.rs:9:5
+   |
+LL | /     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
+LL | |         x
+LL | |     }
+   | |_____^
+note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 9:32...
+  --> $DIR/mismatched_trait_impl.rs:9:32
+   |
+LL |     fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
+   |                                ^^
+   = note: ...so that the method type is compatible with trait:
+           expected fn(&i32, &'a u32, &u32) -> &'a u32
+              found fn(&i32, &u32, &u32) -> &u32
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issue-60622.rs b/src/test/ui/issue-60622.rs
new file mode 100644
index 00000000000..d6a0189c3e0
--- /dev/null
+++ b/src/test/ui/issue-60622.rs
@@ -0,0 +1,18 @@
+// ignore-tidy-linelength
+
+#![deny(warnings)]
+
+struct Borked {}
+
+impl Borked {
+    fn a(&self) {}
+}
+
+fn run_wild<T>(b: &Borked) {
+    b.a::<'_, T>();
+    //~^ ERROR cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+    //~^^ ERROR wrong number of type arguments: expected 0, found 1
+    //~^^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+}
+
+fn main() {}
diff --git a/src/test/ui/issue-60622.stderr b/src/test/ui/issue-60622.stderr
new file mode 100644
index 00000000000..0c337c315f1
--- /dev/null
+++ b/src/test/ui/issue-60622.stderr
@@ -0,0 +1,27 @@
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/issue-60622.rs:12:11
+   |
+LL |     fn a(&self) {}
+   |          - the late bound lifetime parameter is introduced here
+...
+LL |     b.a::<'_, T>();
+   |           ^^
+   |
+note: lint level defined here
+  --> $DIR/issue-60622.rs:3:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: #[deny(late_bound_lifetime_arguments)] implied by #[deny(warnings)]
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/issue-60622.rs:12:15
+   |
+LL |     b.a::<'_, T>();
+   |               ^ unexpected type argument
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/issues/issue-10291.nll.stderr b/src/test/ui/issues/issue-10291.nll.stderr
new file mode 100644
index 00000000000..45f29fd7956
--- /dev/null
+++ b/src/test/ui/issues/issue-10291.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-10291.rs:3:9
+   |
+LL | fn test<'x>(x: &'x isize) {
+   |         -- lifetime `'x` defined here
+LL |     drop::<Box<for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
+LL |         x
+   |         ^ returning this value requires that `'x` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-13058.nll.stderr b/src/test/ui/issues/issue-13058.nll.stderr
new file mode 100644
index 00000000000..8368978deab
--- /dev/null
+++ b/src/test/ui/issues/issue-13058.nll.stderr
@@ -0,0 +1,12 @@
+error[E0621]: explicit lifetime required in the type of `cont`
+  --> $DIR/issue-13058.rs:14:21
+   |
+LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
+   |                                                                     -- help: add explicit lifetime `'r` to the type of `cont`: `&'r T`
+LL | {
+LL |     let cont_iter = cont.iter();
+   |                     ^^^^^^^^^^^ lifetime `'r` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/issues/issue-15034.nll.stderr b/src/test/ui/issues/issue-15034.nll.stderr
new file mode 100644
index 00000000000..f142e260a23
--- /dev/null
+++ b/src/test/ui/issues/issue-15034.nll.stderr
@@ -0,0 +1,11 @@
+error[E0621]: explicit lifetime required in the type of `lexer`
+  --> $DIR/issue-15034.rs:17:9
+   |
+LL |     pub fn new(lexer: &'a mut Lexer) -> Parser<'a> {
+   |                       ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>`
+LL |         Parser { lexer: lexer }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/issues/issue-15381.nll.stderr b/src/test/ui/issues/issue-15381.nll.stderr
new file mode 100644
index 00000000000..a8495846b36
--- /dev/null
+++ b/src/test/ui/issues/issue-15381.nll.stderr
@@ -0,0 +1,16 @@
+error[E0005]: refutable pattern in `for` loop binding: `&[]` not covered
+  --> $DIR/issue-15381.rs:4:9
+   |
+LL |     for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
+   |         ^^^^^^^^ pattern `&[]` not covered
+
+error[E0381]: borrow of possibly uninitialized variable: `y`
+  --> $DIR/issue-15381.rs:6:26
+   |
+LL |         println!("y={}", y);
+   |                          ^ use of possibly uninitialized `y`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0005, E0381.
+For more information about an error, try `rustc --explain E0005`.
diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr
new file mode 100644
index 00000000000..ea6b69d1a76
--- /dev/null
+++ b/src/test/ui/issues/issue-16683.nll.stderr
@@ -0,0 +1,10 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/issue-16683.rs:4:9
+   |
+LL |     fn b(&self) {
+   |          ----- `self` is a reference that is only valid in the function body
+LL |         self.a();
+   |         ^^^^^^^^ `self` escapes the function body here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-17728.nll.stderr b/src/test/ui/issues/issue-17728.nll.stderr
new file mode 100644
index 00000000000..7436ebd920e
--- /dev/null
+++ b/src/test/ui/issues/issue-17728.nll.stderr
@@ -0,0 +1,21 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/issue-17728.rs:109:14
+   |
+LL | /     match to_parse {
+LL | |         "w" | "west" => RoomDirection::West,
+LL | |         "e" | "east" => RoomDirection::East,
+LL | |         "n" | "north" => RoomDirection::North,
+...  |
+LL | |         "down" => RoomDirection::Down,
+   | |                   ------------------- this and all prior arms are found to be of type `RoomDirection`
+LL | |         _ => None
+   | |              ^^^^ expected enum `RoomDirection`, found enum `std::option::Option`
+LL | |     }
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected type `RoomDirection`
+              found type `std::option::Option<_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr
new file mode 100644
index 00000000000..b9dc9da3683
--- /dev/null
+++ b/src/test/ui/issues/issue-17758.nll.stderr
@@ -0,0 +1,10 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/issue-17758.rs:7:9
+   |
+LL |     fn bar(&self) {
+   |            ----- `self` is a reference that is only valid in the function body
+LL |         self.foo();
+   |         ^^^^^^^^^^ `self` escapes the function body here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-19991.stderr b/src/test/ui/issues/issue-19991.stderr
index 4c6d150229a..d9ea910adef 100644
--- a/src/test/ui/issues/issue-19991.stderr
+++ b/src/test/ui/issues/issue-19991.stderr
@@ -6,11 +6,14 @@ LL | |
 LL | |
 LL | |
 LL | |         765
+   | |         --- found here
 LL | |     };
    | |_____^ expected (), found integer
    |
    = note: expected type `()`
               found type `{integer}`
+   = note: `if` expressions without `else` evaluate to `()`
+   = help: consider adding an `else` block that evaluates to the expected type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20091.rs b/src/test/ui/issues/issue-20091.rs
index 4d86a17b6f1..4ea567d25ca 100644
--- a/src/test/ui/issues/issue-20091.rs
+++ b/src/test/ui/issues/issue-20091.rs
@@ -3,6 +3,7 @@
 
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 #![feature(os)]
 
diff --git a/src/test/ui/issues/issue-26217.nll.stderr b/src/test/ui/issues/issue-26217.nll.stderr
new file mode 100644
index 00000000000..c7601caacdc
--- /dev/null
+++ b/src/test/ui/issues/issue-26217.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-26217.rs:4:5
+   |
+LL | fn bar<'a>() {
+   |        -- lifetime `'a` defined here
+LL |     foo::<&'a i32>();
+   |     ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-28848.nll.stderr b/src/test/ui/issues/issue-28848.nll.stderr
new file mode 100644
index 00000000000..5cf9856e4dc
--- /dev/null
+++ b/src/test/ui/issues/issue-28848.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-28848.rs:10:5
+   |
+LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
+   |            --  -- lifetime `'b` defined here
+   |            |
+   |            lifetime `'a` defined here
+LL |     Foo::<'a, 'b>::xmute(u)
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr
index 84cca5b20af..04b8c3aa353 100644
--- a/src/test/ui/issues/issue-32709.stderr
+++ b/src/test/ui/issues/issue-32709.stderr
@@ -4,6 +4,7 @@ error[E0277]: `?` couldn't convert the error to `()`
 LL |     Err(5)?;
    |           ^ the trait `std::convert::From<{integer}>` is not implemented for `()`
    |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = note: required by `std::convert::From::from`
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-34721.rs b/src/test/ui/issues/issue-34721.rs
index 226c21446b1..bdc9fe43a8b 100644
--- a/src/test/ui/issues/issue-34721.rs
+++ b/src/test/ui/issues/issue-34721.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 pub trait Foo {
     fn zero(self) -> Self;
 }
diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr
index 2ed7b543e71..d5cede990a3 100644
--- a/src/test/ui/issues/issue-34721.stderr
+++ b/src/test/ui/issues/issue-34721.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/issue-34721.rs:27:9
+  --> $DIR/issue-34721.rs:25:9
    |
 LL |     pub fn baz<T: Foo>(x: T) -> T {
    |                -       - move occurs because `x` has type `T`, which does not implement the `Copy` trait
diff --git a/src/test/ui/issues/issue-39175.rs b/src/test/ui/issues/issue-39175.rs
index 25225ca6e7c..3ba2a9d40be 100644
--- a/src/test/ui/issues/issue-39175.rs
+++ b/src/test/ui/issues/issue-39175.rs
@@ -6,6 +6,7 @@
 // ignore-windows
 // ignore-cloudabi
 // ignore-emscripten
+// ignore-sgx no processes
 
 use std::process::Command;
 // use std::os::unix::process::CommandExt;
diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr
index 6aee474fe74..108c969cdad 100644
--- a/src/test/ui/issues/issue-39175.stderr
+++ b/src/test/ui/issues/issue-39175.stderr
@@ -1,5 +1,5 @@
 error[E0599]: no method named `exec` found for type `&mut std::process::Command` in the current scope
-  --> $DIR/issue-39175.rs:14:39
+  --> $DIR/issue-39175.rs:15:39
    |
 LL |     Command::new("echo").arg("hello").exec();
    |                                       ^^^^
diff --git a/src/test/ui/issues/issue-40510-1.migrate.nll.stderr b/src/test/ui/issues/issue-40510-1.migrate.nll.stderr
new file mode 100644
index 00000000000..776a724d310
--- /dev/null
+++ b/src/test/ui/issues/issue-40510-1.migrate.nll.stderr
@@ -0,0 +1,13 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-40510-1.rs:11:9
+   |
+LL |     || {
+   |      - inferred to be a `FnMut` closure
+LL |         &mut x
+   |         ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40510-1.stderr b/src/test/ui/issues/issue-40510-1.migrate.stderr
index 44234cbc881..17d1c48d075 100644
--- a/src/test/ui/issues/issue-40510-1.stderr
+++ b/src/test/ui/issues/issue-40510-1.migrate.stderr
@@ -1,5 +1,5 @@
 warning: captured variable cannot escape `FnMut` closure body
-  --> $DIR/issue-40510-1.rs:8:9
+  --> $DIR/issue-40510-1.rs:11:9
    |
 LL |     || {
    |      - inferred to be a `FnMut` closure
@@ -11,3 +11,11 @@ LL |         &mut x
    = warning: this error has been downgraded to a warning for backwards compatibility with previous releases
    = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
 
+error: compilation successful
+  --> $DIR/issue-40510-1.rs:20:1
+   |
+LL | fn main() {}
+   | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40510-1.nll.stderr b/src/test/ui/issues/issue-40510-1.nll.stderr
new file mode 100644
index 00000000000..776a724d310
--- /dev/null
+++ b/src/test/ui/issues/issue-40510-1.nll.stderr
@@ -0,0 +1,13 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-40510-1.rs:11:9
+   |
+LL |     || {
+   |      - inferred to be a `FnMut` closure
+LL |         &mut x
+   |         ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40510-1.rs b/src/test/ui/issues/issue-40510-1.rs
index dd8a6bc5ab2..6ecbeefd881 100644
--- a/src/test/ui/issues/issue-40510-1.rs
+++ b/src/test/ui/issues/issue-40510-1.rs
@@ -1,13 +1,21 @@
-// compile-pass
+#![feature(rustc_attrs)]
 #![allow(unused)]
 
+// revisions: migrate nll
+#![cfg_attr(nll, feature(nll))]
+
 fn f() {
     let mut x: Box<()> = Box::new(());
 
     || {
         &mut x
     };
+    //[migrate]~^^ WARNING captured variable cannot escape `FnMut` closure body
+    //[migrate]~| WARNING this error has been downgraded to a warning
+    //[migrate]~| WARNING this warning will become a hard error in the future
+    //[nll]~^^^^^ ERROR captured variable cannot escape `FnMut` closure body
 }
 
-
+#[rustc_error]
 fn main() {}
+//[migrate]~^ ERROR
diff --git a/src/test/ui/issues/issue-40510-3.migrate.nll.stderr b/src/test/ui/issues/issue-40510-3.migrate.nll.stderr
new file mode 100644
index 00000000000..a49475a8570
--- /dev/null
+++ b/src/test/ui/issues/issue-40510-3.migrate.nll.stderr
@@ -0,0 +1,15 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-40510-3.rs:11:9
+   |
+LL |       || {
+   |        - inferred to be a `FnMut` closure
+LL | /         || {
+LL | |             x.push(())
+LL | |         }
+   | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40510-3.stderr b/src/test/ui/issues/issue-40510-3.migrate.stderr
index 1297e141898..692aa105377 100644
--- a/src/test/ui/issues/issue-40510-3.stderr
+++ b/src/test/ui/issues/issue-40510-3.migrate.stderr
@@ -1,5 +1,5 @@
 warning: captured variable cannot escape `FnMut` closure body
-  --> $DIR/issue-40510-3.rs:8:9
+  --> $DIR/issue-40510-3.rs:11:9
    |
 LL |       || {
    |        - inferred to be a `FnMut` closure
@@ -13,3 +13,11 @@ LL | |         }
    = warning: this error has been downgraded to a warning for backwards compatibility with previous releases
    = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
 
+error: compilation successful
+  --> $DIR/issue-40510-3.rs:22:1
+   |
+LL | fn main() {}
+   | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40510-3.nll.stderr b/src/test/ui/issues/issue-40510-3.nll.stderr
new file mode 100644
index 00000000000..a49475a8570
--- /dev/null
+++ b/src/test/ui/issues/issue-40510-3.nll.stderr
@@ -0,0 +1,15 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-40510-3.rs:11:9
+   |
+LL |       || {
+   |        - inferred to be a `FnMut` closure
+LL | /         || {
+LL | |             x.push(())
+LL | |         }
+   | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40510-3.rs b/src/test/ui/issues/issue-40510-3.rs
index bc95c461d1e..205d9823631 100644
--- a/src/test/ui/issues/issue-40510-3.rs
+++ b/src/test/ui/issues/issue-40510-3.rs
@@ -1,6 +1,9 @@
-// compile-pass
+#![feature(rustc_attrs)]
 #![allow(unused)]
 
+// revisions: migrate nll
+#![cfg_attr(nll, feature(nll))]
+
 fn f() {
     let mut x: Vec<()> = Vec::new();
 
@@ -8,8 +11,13 @@ fn f() {
         || {
             x.push(())
         }
+        //[migrate]~^^^ WARNING captured variable cannot escape `FnMut` closure body
+        //[migrate]~| WARNING this error has been downgraded to a warning
+        //[migrate]~| WARNING this warning will become a hard error in the future
+        //[nll]~^^^^^^ ERROR captured variable cannot escape `FnMut` closure body
     };
 }
 
-
+#[rustc_error]
 fn main() {}
+//[migrate]~^ ERROR
diff --git a/src/test/ui/issues/issue-43355.rs b/src/test/ui/issues/issue-43355.rs
index 809300d6d19..bf819af7962 100644
--- a/src/test/ui/issues/issue-43355.rs
+++ b/src/test/ui/issues/issue-43355.rs
@@ -12,7 +12,6 @@ impl<X, T> Trait1<X> for T where T: Trait2<X> {
 
 impl<X> Trait1<Box<X>> for A {
 //~^ ERROR conflicting implementations of trait
-//~| hard error
 //~| downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A`
     type Output = i32;
 }
diff --git a/src/test/ui/issues/issue-43355.stderr b/src/test/ui/issues/issue-43355.stderr
index 039f10447c0..75c69e5b3e3 100644
--- a/src/test/ui/issues/issue-43355.stderr
+++ b/src/test/ui/issues/issue-43355.stderr
@@ -1,4 +1,4 @@
-error: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`: (E0119)
+error[E0119]: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`:
   --> $DIR/issue-43355.rs:13:1
    |
 LL | impl<X, T> Trait1<X> for T where T: Trait2<X> {
@@ -7,10 +7,8 @@ LL | impl<X, T> Trait1<X> for T where T: Trait2<X> {
 LL | impl<X> Trait1<Box<X>> for A {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A`
    |
-   = note: #[deny(incoherent_fundamental_impls)] on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205>
    = note: downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/issues/issue-45696-no-variant-box-recur.rs b/src/test/ui/issues/issue-45696-no-variant-box-recur.rs
index b5d9036aba6..c688261fa1c 100644
--- a/src/test/ui/issues/issue-45696-no-variant-box-recur.rs
+++ b/src/test/ui/issues/issue-45696-no-variant-box-recur.rs
@@ -6,11 +6,6 @@
 // We will explicitly test NLL, and migration modes; thus we will also skip the
 // automated compare-mode=nll.
 
-// revisions: nll migrate
-// ignore-compare-mode-nll
-
-#![cfg_attr(nll, feature(nll))]
-
 // run-pass
 
 // This test has structs and functions that are by definition unusable
diff --git a/src/test/ui/issues/issue-46036.rs b/src/test/ui/issues/issue-46036.rs
index c517bbe57e8..18af33c1821 100644
--- a/src/test/ui/issues/issue-46036.rs
+++ b/src/test/ui/issues/issue-46036.rs
@@ -1,6 +1,5 @@
 // Issue 46036: [NLL] false edges on infinite loops
 // Infinite loops should create false edges to the cleanup block.
-#![feature(nll)]
 
 struct Foo { x: &'static u32 }
 
diff --git a/src/test/ui/issues/issue-46036.stderr b/src/test/ui/issues/issue-46036.stderr
index 9c1746e0fa1..49dd0e267b8 100644
--- a/src/test/ui/issues/issue-46036.stderr
+++ b/src/test/ui/issues/issue-46036.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `a` does not live long enough
-  --> $DIR/issue-46036.rs:9:24
+  --> $DIR/issue-46036.rs:8:24
    |
 LL |     let foo = Foo { x: &a };
    |                        ^^
diff --git a/src/test/ui/issues/issue-46983.rs b/src/test/ui/issues/issue-46983.rs
index a5c1e17a58c..c1fd7729bde 100644
--- a/src/test/ui/issues/issue-46983.rs
+++ b/src/test/ui/issues/issue-46983.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn foo(x: &u32) -> &'static u32 {
     &*x
     //~^ ERROR explicit lifetime required in the type of `x` [E0621]
diff --git a/src/test/ui/issues/issue-46983.stderr b/src/test/ui/issues/issue-46983.stderr
index 43d351ec905..8a4a6bdb39f 100644
--- a/src/test/ui/issues/issue-46983.stderr
+++ b/src/test/ui/issues/issue-46983.stderr
@@ -1,5 +1,5 @@
 error[E0621]: explicit lifetime required in the type of `x`
-  --> $DIR/issue-46983.rs:4:5
+  --> $DIR/issue-46983.rs:2:5
    |
 LL | fn foo(x: &u32) -> &'static u32 {
    |           ---- help: add explicit lifetime `'static` to the type of `x`: `&'static u32`
diff --git a/src/test/ui/issues/issue-47184.rs b/src/test/ui/issues/issue-47184.rs
index 04f1146a8f8..2f78ce0002b 100644
--- a/src/test/ui/issues/issue-47184.rs
+++ b/src/test/ui/issues/issue-47184.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn main() {
     let _vec: Vec<&'static String> = vec![&String::new()];
     //~^ ERROR temporary value dropped while borrowed [E0716]
diff --git a/src/test/ui/issues/issue-47184.stderr b/src/test/ui/issues/issue-47184.stderr
index 2b4d576e726..f97713b4ac4 100644
--- a/src/test/ui/issues/issue-47184.stderr
+++ b/src/test/ui/issues/issue-47184.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-47184.rs:4:44
+  --> $DIR/issue-47184.rs:2:44
    |
 LL |     let _vec: Vec<&'static String> = vec![&String::new()];
    |               --------------------         ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr
index 88466131e31..7d11a8c8021 100644
--- a/src/test/ui/issues/issue-47377.stderr
+++ b/src/test/ui/issues/issue-47377.stderr
@@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str`
 LL |      let _a = b + ", World!";
    |               - ^ ---------- &str
    |               | |
-   |               | `+` can't be used to concatenate two `&str` strings
+   |               | `+` cannot be used to concatenate two `&str` strings
    |               &str
 help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
    |
diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr
index d69101eab4c..89a154c5109 100644
--- a/src/test/ui/issues/issue-47380.stderr
+++ b/src/test/ui/issues/issue-47380.stderr
@@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str`
 LL |     println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!";
    |                                      - ^ ---------- &str
    |                                      | |
-   |                                      | `+` can't be used to concatenate two `&str` strings
+   |                                      | `+` cannot be used to concatenate two `&str` strings
    |                                      &str
 help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
    |
diff --git a/src/test/ui/issues/issue-47646.rs b/src/test/ui/issues/issue-47646.rs
index c3c07bf6411..ace6cdce841 100644
--- a/src/test/ui/issues/issue-47646.rs
+++ b/src/test/ui/issues/issue-47646.rs
@@ -1,6 +1,3 @@
-#![allow(warnings)]
-#![feature(nll)]
-
 use std::collections::BinaryHeap;
 
 fn main() {
diff --git a/src/test/ui/issues/issue-47646.stderr b/src/test/ui/issues/issue-47646.stderr
index db9f227d6b7..c0b87636848 100644
--- a/src/test/ui/issues/issue-47646.stderr
+++ b/src/test/ui/issues/issue-47646.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `heap` as immutable because it is also borrowed as mutable
-  --> $DIR/issue-47646.rs:12:30
+  --> $DIR/issue-47646.rs:9:30
    |
 LL |     let borrow = heap.peek_mut();
    |                  ---- mutable borrow occurs here
diff --git a/src/test/ui/issues/issue-47703-1.rs b/src/test/ui/issues/issue-47703-1.rs
index 9add314fdaf..74323317f19 100644
--- a/src/test/ui/issues/issue-47703-1.rs
+++ b/src/test/ui/issues/issue-47703-1.rs
@@ -1,6 +1,4 @@
 // compile-pass
-#![allow(dead_code)]
-#![feature(nll)]
 
 struct AtomicRefMut<'a> {
     value: &'a mut i32,
diff --git a/src/test/ui/issues/issue-47703-tuple.rs b/src/test/ui/issues/issue-47703-tuple.rs
index 850771cffd0..377eeb67ae1 100644
--- a/src/test/ui/issues/issue-47703-tuple.rs
+++ b/src/test/ui/issues/issue-47703-tuple.rs
@@ -1,6 +1,4 @@
 // compile-pass
-#![allow(dead_code)]
-#![feature(nll)]
 
 struct WithDrop;
 
diff --git a/src/test/ui/issues/issue-47703.rs b/src/test/ui/issues/issue-47703.rs
index 06b17e931a9..22f2a1f364d 100644
--- a/src/test/ui/issues/issue-47703.rs
+++ b/src/test/ui/issues/issue-47703.rs
@@ -1,6 +1,4 @@
 // compile-pass
-#![allow(dead_code)]
-#![feature(nll)]
 
 struct MyStruct<'a> {
     field: &'a mut (),
diff --git a/src/test/ui/issues/issue-47722.rs b/src/test/ui/issues/issue-47722.rs
index c9bc6147aa9..cefc872668c 100644
--- a/src/test/ui/issues/issue-47722.rs
+++ b/src/test/ui/issues/issue-47722.rs
@@ -1,10 +1,8 @@
 // compile-pass
-#![allow(dead_code)]
 
 // Tests that automatic coercions from &mut T to *mut T
 // allow borrows of T to expire immediately - essentially, that
 // they work identically to 'foo as *mut T'
-#![feature(nll)]
 
 struct SelfReference {
     self_reference: *mut SelfReference,
diff --git a/src/test/ui/issues/issue-47789.rs b/src/test/ui/issues/issue-47789.rs
index d15a27a2a2e..334bd608add 100644
--- a/src/test/ui/issues/issue-47789.rs
+++ b/src/test/ui/issues/issue-47789.rs
@@ -1,9 +1,6 @@
 // compile-pass
-#![allow(dead_code)]
 #![allow(non_upper_case_globals)]
 
-#![feature(nll)]
-
 static mut x: &'static u32 = &0;
 
 fn foo() {
diff --git a/src/test/ui/issues/issue-48132.rs b/src/test/ui/issues/issue-48132.rs
index b3cef78f3e6..ea325ea695f 100644
--- a/src/test/ui/issues/issue-48132.rs
+++ b/src/test/ui/issues/issue-48132.rs
@@ -3,9 +3,6 @@
 
 // run-pass
 
-#![feature(nll)]
-#![allow(warnings)]
-
 struct Inner<I, V> {
     iterator: I,
     item: V,
diff --git a/src/test/ui/issues/issue-48179.rs b/src/test/ui/issues/issue-48179.rs
index 245f13b2b60..90e9858d741 100644
--- a/src/test/ui/issues/issue-48179.rs
+++ b/src/test/ui/issues/issue-48179.rs
@@ -3,9 +3,6 @@
 
 // run-pass
 
-#![feature(nll)]
-#![allow(warnings)]
-
 pub struct Container<T: Iterator> {
     value: Option<T::Item>,
 }
diff --git a/src/test/ui/issues/issue-48803.rs b/src/test/ui/issues/issue-48803.rs
index bc1bc29c98f..f7fd04179f2 100644
--- a/src/test/ui/issues/issue-48803.rs
+++ b/src/test/ui/issues/issue-48803.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
     x
 }
diff --git a/src/test/ui/issues/issue-48803.stderr b/src/test/ui/issues/issue-48803.stderr
index 9a6da9e625d..2f94039c0c3 100644
--- a/src/test/ui/issues/issue-48803.stderr
+++ b/src/test/ui/issues/issue-48803.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/issue-48803.rs:12:5
+  --> $DIR/issue-48803.rs:10:5
    |
 LL |     let y = &x;
    |             -- borrow of `x` occurs here
diff --git a/src/test/ui/issues/issue-49579.rs b/src/test/ui/issues/issue-49579.rs
index 34f277af01e..dd7b9eeb8d5 100644
--- a/src/test/ui/issues/issue-49579.rs
+++ b/src/test/ui/issues/issue-49579.rs
@@ -1,8 +1,6 @@
 // compile-pass
 // ignore-emscripten no i128 support
 
-#![feature(nll)]
-
 fn fibs(n: u32) -> impl Iterator<Item=u128> {
     (0 .. n)
     .scan((0, 1), |st, _| {
diff --git a/src/test/ui/issues/issue-49824.nll.stderr b/src/test/ui/issues/issue-49824.nll.stderr
new file mode 100644
index 00000000000..9c6f8d4532a
--- /dev/null
+++ b/src/test/ui/issues/issue-49824.nll.stderr
@@ -0,0 +1,18 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/issue-49824.rs:10:9
+   |
+LL |       || {
+   |        - inferred to be a `FnMut` closure
+LL | /         || {
+LL | |
+LL | |
+LL | |
+LL | |             let _y = &mut x;
+LL | |         }
+   | |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs
index f0f1dc6c286..bf892a8daa2 100644
--- a/src/test/ui/issues/issue-50577.rs
+++ b/src/test/ui/issues/issue-50577.rs
@@ -2,5 +2,6 @@ fn main() {
     enum Foo {
         Drop = assert_eq!(1, 1)
         //~^ ERROR if may be missing an else clause
+        //~| ERROR mismatched types [E0308]
     }
 }
diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/issues/issue-50577.stderr
index 0c3ba2ea4f9..413c8c5c80b 100644
--- a/src/test/ui/issues/issue-50577.stderr
+++ b/src/test/ui/issues/issue-50577.stderr
@@ -1,3 +1,13 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-50577.rs:3:16
+   |
+LL |         Drop = assert_eq!(1, 1)
+   |                ^^^^^^^^^^^^^^^^ expected isize, found ()
+   |
+   = note: expected type `isize`
+              found type `()`
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
 error[E0317]: if may be missing an else clause
   --> $DIR/issue-50577.rs:3:16
    |
@@ -13,6 +23,7 @@ LL |         Drop = assert_eq!(1, 1)
    = help: consider adding an `else` block that evaluates to the expected type
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0317`.
+Some errors have detailed explanations: E0308, E0317.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-51515.rs b/src/test/ui/issues/issue-51515.rs
index 64d9822bab4..8eab7b2fa3a 100644
--- a/src/test/ui/issues/issue-51515.rs
+++ b/src/test/ui/issues/issue-51515.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn main() {
     let foo = &16;
     //~^ HELP consider changing this to be a mutable reference
diff --git a/src/test/ui/issues/issue-51515.stderr b/src/test/ui/issues/issue-51515.stderr
index 0e6c8fd48f1..827bb8fe2b8 100644
--- a/src/test/ui/issues/issue-51515.stderr
+++ b/src/test/ui/issues/issue-51515.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `*foo` which is behind a `&` reference
-  --> $DIR/issue-51515.rs:7:5
+  --> $DIR/issue-51515.rs:5:5
    |
 LL |     let foo = &16;
    |               --- help: consider changing this to be a mutable reference: `&mut 16`
@@ -8,7 +8,7 @@ LL |     *foo = 32;
    |     ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
 
 error[E0594]: cannot assign to `*bar` which is behind a `&` reference
-  --> $DIR/issue-51515.rs:12:5
+  --> $DIR/issue-51515.rs:10:5
    |
 LL |     let bar = foo;
    |         --- help: consider changing this to be a mutable reference: `&mut i32`
diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs
index 2c02ac01142..5966edd0bf0 100644
--- a/src/test/ui/issues/issue-51719.rs
+++ b/src/test/ui/issues/issue-51719.rs
@@ -9,3 +9,5 @@ async fn foo() {}
 fn make_generator() {
     let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
 }
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr
index 768909b66ec..c06165b2446 100644
--- a/src/test/ui/issues/issue-51719.stderr
+++ b/src/test/ui/issues/issue-51719.stderr
@@ -2,7 +2,9 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
   --> $DIR/issue-51719.rs:10:19
    |
 LL |     let _gen = || foo.await;
-   |                   ^^^^^^^^^
+   |                -- ^^^^^^^^^ only allowed inside `async` functions and blocks
+   |                |
+   |                this is not `async`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr
index 0c4cb034a93..97b63d1590e 100644
--- a/src/test/ui/issues/issue-51751.stderr
+++ b/src/test/ui/issues/issue-51751.stderr
@@ -1,8 +1,11 @@
 error[E0728]: `await` is only allowed inside `async` functions and blocks
   --> $DIR/issue-51751.rs:11:20
    |
+LL | fn main() {
+   |    ---- this is not `async`
+LL |     let result = inc(10000);
 LL |     let finished = result.await;
-   |                    ^^^^^^^^^^^^
+   |                    ^^^^^^^^^^^^ only allowed inside `async` functions and blocks
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-52057.rs b/src/test/ui/issues/issue-52057.rs
index 356efd5dfed..911983445e6 100644
--- a/src/test/ui/issues/issue-52057.rs
+++ b/src/test/ui/issues/issue-52057.rs
@@ -4,8 +4,6 @@
 //
 // run-pass
 
-#![feature(nll)]
-
 pub trait Parser {
     type Input;
 
diff --git a/src/test/ui/issues/issue-52213.nll.stderr b/src/test/ui/issues/issue-52213.nll.stderr
new file mode 100644
index 00000000000..eba875de215
--- /dev/null
+++ b/src/test/ui/issues/issue-52213.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52213.rs:3:20
+   |
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+   |                       --  -- lifetime `'b` defined here
+   |                       |
+   |                       lifetime `'a` defined here
+LL |     match (&t,) {
+LL |         ((u,),) => u,
+   |                    ^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-52533-1.nll.stderr b/src/test/ui/issues/issue-52533-1.nll.stderr
new file mode 100644
index 00000000000..20f19b25967
--- /dev/null
+++ b/src/test/ui/issues/issue-52533-1.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52533-1.rs:9:18
+   |
+LL |     gimme(|x, y| y)
+   |            -  -  ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |            |  |
+   |            |  has type `&Foo<'_, '1, u32>`
+   |            has type `&Foo<'_, '2, u32>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-52533.nll.stderr b/src/test/ui/issues/issue-52533.nll.stderr
new file mode 100644
index 00000000000..c764736d798
--- /dev/null
+++ b/src/test/ui/issues/issue-52533.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52533.rs:5:16
+   |
+LL |     foo(|a, b| b)
+   |          -  -  ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |          |  |
+   |          |  has type `&'1 u32`
+   |          has type `&'2 u32`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-52992.rs b/src/test/ui/issues/issue-52992.rs
index 0fdf077d2fc..c58656330e1 100644
--- a/src/test/ui/issues/issue-52992.rs
+++ b/src/test/ui/issues/issue-52992.rs
@@ -4,8 +4,6 @@
 //
 // compile-pass
 
-#![feature(nll)]
-
 fn main() {}
 
 fn fail<'a>() -> Struct<'a, Generic<()>> {
diff --git a/src/test/ui/issues/issue-53498.rs b/src/test/ui/issues/issue-53498.rs
new file mode 100644
index 00000000000..c87d4236492
--- /dev/null
+++ b/src/test/ui/issues/issue-53498.rs
@@ -0,0 +1,17 @@
+pub mod test {
+    pub struct A;
+    pub struct B;
+    pub struct Foo<T>(T);
+
+    impl Foo<A> {
+        fn foo() {}
+    }
+
+    impl Foo<B> {
+        fn foo() {}
+    }
+}
+
+fn main() {
+    test::Foo::<test::B>::foo(); //~ ERROR method `foo` is private
+}
diff --git a/src/test/ui/issues/issue-53498.stderr b/src/test/ui/issues/issue-53498.stderr
new file mode 100644
index 00000000000..3fd48233dae
--- /dev/null
+++ b/src/test/ui/issues/issue-53498.stderr
@@ -0,0 +1,9 @@
+error[E0624]: method `foo` is private
+  --> $DIR/issue-53498.rs:16:5
+   |
+LL |     test::Foo::<test::B>::foo();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0624`.
diff --git a/src/test/ui/issues/issue-53568.rs b/src/test/ui/issues/issue-53568.rs
index f04d861250b..4d3b3f80a97 100644
--- a/src/test/ui/issues/issue-53568.rs
+++ b/src/test/ui/issues/issue-53568.rs
@@ -3,9 +3,6 @@
 //
 // compile-pass
 
-#![feature(nll)]
-#![allow(dead_code)]
-
 trait Future {
     type Item;
 }
diff --git a/src/test/ui/issues/issue-54302-cases.nll.stderr b/src/test/ui/issues/issue-54302-cases.nll.stderr
new file mode 100644
index 00000000000..7463a3f286f
--- /dev/null
+++ b/src/test/ui/issues/issue-54302-cases.nll.stderr
@@ -0,0 +1,26 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-54302-cases.rs:63:5
+   |
+LL |     <u32 as RefFoo<u32>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-54302-cases.rs:69:5
+   |
+LL |     <i32 as RefFoo<i32>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-54302-cases.rs:75:5
+   |
+LL |     <u64 as RefFoo<u64>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-54302-cases.rs:81:5
+   |
+LL |     <i64 as RefFoo<i64>>::ref_foo(a)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/issues/issue-54302.nll.stderr b/src/test/ui/issues/issue-54302.nll.stderr
new file mode 100644
index 00000000000..e68de031282
--- /dev/null
+++ b/src/test/ui/issues/issue-54302.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-54302.rs:13:5
+   |
+LL |     assert_deserialize_owned::<&'static str>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-54943-1.rs b/src/test/ui/issues/issue-54943-1.rs
index 7750e340361..8d3a4e72de4 100644
--- a/src/test/ui/issues/issue-54943-1.rs
+++ b/src/test/ui/issues/issue-54943-1.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // This test is a minimal version of an ICE in the dropck-eyepatch tests
 // found in the fix for #54943.
 
diff --git a/src/test/ui/issues/issue-54943-2.rs b/src/test/ui/issues/issue-54943-2.rs
index f829c38c35d..41ca7c14982 100644
--- a/src/test/ui/issues/issue-54943-2.rs
+++ b/src/test/ui/issues/issue-54943-2.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // This test is a minimal version of an ICE in the dropck-eyepatch tests
 // found in the fix for #54943. In particular, this test is in unreachable
 // code as the initial fix for this ICE only worked if the code was reachable.
diff --git a/src/test/ui/issues/issue-54943.nll.stderr b/src/test/ui/issues/issue-54943.nll.stderr
new file mode 100644
index 00000000000..59be0f983b9
--- /dev/null
+++ b/src/test/ui/issues/issue-54943.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-54943.rs:6:13
+   |
+LL | fn boo<'a>() {
+   |        -- lifetime `'a` defined here
+...
+LL |     let x = foo::<&'a u32>();
+   |             ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-54943.rs b/src/test/ui/issues/issue-54943.rs
index ce4e0106743..85722300bf0 100644
--- a/src/test/ui/issues/issue-54943.rs
+++ b/src/test/ui/issues/issue-54943.rs
@@ -1,13 +1,10 @@
-#![feature(nll)]
-#![allow(warnings)]
-
 fn foo<T: 'static>() { }
 
 fn boo<'a>() {
     return;
 
     let x = foo::<&'a u32>();
-    //~^ ERROR lifetime may not live long enough
+    //~^ ERROR
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-54943.stderr b/src/test/ui/issues/issue-54943.stderr
index aa68177bcdb..d0f03f90c83 100644
--- a/src/test/ui/issues/issue-54943.stderr
+++ b/src/test/ui/issues/issue-54943.stderr
@@ -1,11 +1,10 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-54943.rs:9:13
+error[E0477]: the type `&'a u32` does not fulfill the required lifetime
+  --> $DIR/issue-54943.rs:6:13
    |
-LL | fn boo<'a>() {
-   |        -- lifetime `'a` defined here
-...
 LL |     let x = foo::<&'a u32>();
-   |             ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: type must satisfy the static lifetime
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-55731.nll.stderr b/src/test/ui/issues/issue-55731.nll.stderr
new file mode 100644
index 00000000000..dd38bb62912
--- /dev/null
+++ b/src/test/ui/issues/issue-55731.nll.stderr
@@ -0,0 +1,11 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-55731.rs:48:5
+   |
+LL | /     multi(Map {
+LL | |         i: Cloned(PhantomData),
+LL | |         f: X,
+LL | |     });
+   | |______^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-55796.nll.stderr b/src/test/ui/issues/issue-55796.nll.stderr
new file mode 100644
index 00000000000..5809a56cd4b
--- /dev/null
+++ b/src/test/ui/issues/issue-55796.nll.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-55796.rs:16:9
+   |
+LL | pub trait Graph<'a> {
+   |                 -- lifetime `'a` defined here
+...
+LL |         Box::new(self.out_edges(u).map(|e| e.target()))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-55796.rs:21:9
+   |
+LL | pub trait Graph<'a> {
+   |                 -- lifetime `'a` defined here
+...
+LL |         Box::new(self.in_edges(u).map(|e| e.target()))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issues/issue-57843.nll.stderr b/src/test/ui/issues/issue-57843.nll.stderr
new file mode 100644
index 00000000000..70310780b43
--- /dev/null
+++ b/src/test/ui/issues/issue-57843.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-57843.rs:23:9
+   |
+LL |     Foo(Box::new(|_| ()));
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-60662.rs b/src/test/ui/issues/issue-60662.rs
new file mode 100644
index 00000000000..fe4eaff742d
--- /dev/null
+++ b/src/test/ui/issues/issue-60662.rs
@@ -0,0 +1,11 @@
+// compile-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(existential_type)]
+
+trait Animal {
+}
+
+fn main() {
+    pub existential type ServeFut: Animal;
+}
diff --git a/src/test/ui/issues/issue-60662.stdout b/src/test/ui/issues/issue-60662.stdout
new file mode 100644
index 00000000000..5acfdf9ed53
--- /dev/null
+++ b/src/test/ui/issues/issue-60662.stdout
@@ -0,0 +1,14 @@
+// compile-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(existential_type)]
+#[prelude_import]
+use ::std::prelude::v1::*;
+#[macro_use]
+extern crate std;
+
+trait Animal { }
+
+fn main() {
+              pub existential type ServeFut : Animal;
+          }
diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr
new file mode 100644
index 00000000000..c1f662fda61
--- /dev/null
+++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr
@@ -0,0 +1,63 @@
+error[E0277]: `T` cannot be sent between threads safely
+  --> $DIR/kindck-impl-type-params.rs:18:13
+   |
+LL |     let a = &t as &Gettable<T>;
+   |             ^^ `T` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `T`
+   = help: consider adding a `where T: std::marker::Send` bound
+   = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
+   = note: required for the cast to the object type `dyn Gettable<T>`
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/kindck-impl-type-params.rs:18:13
+   |
+LL |     let a = &t as &Gettable<T>;
+   |             ^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = help: consider adding a `where T: std::marker::Copy` bound
+   = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
+   = note: required for the cast to the object type `dyn Gettable<T>`
+
+error[E0277]: `T` cannot be sent between threads safely
+  --> $DIR/kindck-impl-type-params.rs:25:27
+   |
+LL |     let a: &Gettable<T> = &t;
+   |                           ^^ `T` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `T`
+   = help: consider adding a `where T: std::marker::Send` bound
+   = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
+   = note: required for the cast to the object type `dyn Gettable<T>`
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+  --> $DIR/kindck-impl-type-params.rs:25:27
+   |
+LL |     let a: &Gettable<T> = &t;
+   |                           ^^ the trait `std::marker::Copy` is not implemented for `T`
+   |
+   = help: consider adding a `where T: std::marker::Copy` bound
+   = note: required because of the requirements on the impl of `Gettable<T>` for `S<T>`
+   = note: required for the cast to the object type `dyn Gettable<T>`
+
+error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
+  --> $DIR/kindck-impl-type-params.rs:38:13
+   |
+LL |     let a = t as Box<Gettable<String>>;
+   |             ^ the trait `std::marker::Copy` is not implemented for `std::string::String`
+   |
+   = note: required because of the requirements on the impl of `Gettable<std::string::String>` for `S<std::string::String>`
+   = note: required for the cast to the object type `dyn Gettable<std::string::String>`
+
+error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied
+  --> $DIR/kindck-impl-type-params.rs:46:33
+   |
+LL |     let a: Box<Gettable<Foo>> = t;
+   |                                 ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo`
+   |
+   = note: required because of the requirements on the impl of `Gettable<foo3::Foo>` for `S<foo3::Foo>`
+   = note: required for the cast to the object type `dyn Gettable<foo3::Foo>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/kindck/kindck-send-object1.nll.stderr b/src/test/ui/kindck/kindck-send-object1.nll.stderr
new file mode 100644
index 00000000000..1df7412132b
--- /dev/null
+++ b/src/test/ui/kindck/kindck-send-object1.nll.stderr
@@ -0,0 +1,32 @@
+error[E0277]: `(dyn Dummy + 'a)` cannot be shared between threads safely
+  --> $DIR/kindck-send-object1.rs:10:5
+   |
+LL |     assert_send::<&'a Dummy>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely
+   |
+   = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)`
+   = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)`
+note: required by `assert_send`
+  --> $DIR/kindck-send-object1.rs:5:1
+   |
+LL | fn assert_send<T:Send+'static>() { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
+  --> $DIR/kindck-send-object1.rs:29:5
+   |
+LL |     assert_send::<Box<Dummy+'a>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely
+   |
+   = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)`
+   = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>`
+   = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>`
+note: required by `assert_send`
+  --> $DIR/kindck-send-object1.rs:5:1
+   |
+LL | fn assert_send<T:Send+'static>() { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr
new file mode 100644
index 00000000000..8b24563e920
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr
@@ -0,0 +1,20 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/lifetime-bound-will-change-warning.rs:34:5
+   |
+LL | fn test2<'a>(x: &'a Box<Fn()+'a>) {
+   |              - `x` is a reference that is only valid in the function body
+LL |     // but ref_obj will not, so warn.
+LL |     ref_obj(x)
+   |     ^^^^^^^^^^ `x` escapes the function body here
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/lifetime-bound-will-change-warning.rs:39:5
+   |
+LL | fn test2cc<'a>(x: &'a Box<Fn()+'a>) {
+   |                - `x` is a reference that is only valid in the function body
+LL |     // same as test2, but cross crate
+LL |     lib::ref_obj(x)
+   |     ^^^^^^^^^^^^^^^ `x` escapes the function body here
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr
new file mode 100644
index 00000000000..fc9093bb2e4
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:11:20
+   |
+LL |     fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
+   |            --     - let's call the lifetime of this reference `'1`
+   |            |
+   |            lifetime `'a` defined here
+LL | 
+LL |         if x > y { x } else { y }
+   |                    ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr
new file mode 100644
index 00000000000..3384c24da8f
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:8:5
+   |
+LL |   fn foo<'a>(&self, x: &'a i32) -> &i32 {
+   |          --  - let's call the lifetime of this reference `'1`
+   |          |
+   |          lifetime `'a` defined here
+LL | 
+LL |     x
+   |     ^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr
new file mode 100644
index 00000000000..5ef29076e07
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:8:30
+   |
+LL |     fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
+   |            --  - let's call the lifetime of this reference `'1`
+   |            |
+   |            lifetime `'a` defined here
+LL | 
+LL |         if true { x } else { self }
+   |                              ^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr
new file mode 100644
index 00000000000..90d4754ebab
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr
@@ -0,0 +1,11 @@
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/ex2a-push-one-existing-name-2.rs:6:5
+   |
+LL | fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) {
+   |               -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>`
+LL |     y.push(x);
+   |     ^^^^^^^^^ lifetime `'a` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr
new file mode 100644
index 00000000000..a03e16b3b79
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr
@@ -0,0 +1,12 @@
+error[E0621]: explicit lifetime required in the type of `y`
+  --> $DIR/ex2a-push-one-existing-name-early-bound.rs:8:5
+   |
+LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
+   |                                          -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
+...
+LL |     x.push(y);
+   |     ^^^^^^^^^ lifetime `'a` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr
new file mode 100644
index 00000000000..487b34e3d18
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.nll.stderr
@@ -0,0 +1,11 @@
+error[E0621]: explicit lifetime required in the type of `y`
+  --> $DIR/ex2a-push-one-existing-name.rs:6:5
+   |
+LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
+   |                                          -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>`
+LL |     x.push(y);
+   |     ^^^^^^^^^ lifetime `'a` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr
new file mode 100644
index 00000000000..735f7a0dfc6
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex2b-push-no-existing-names.rs:6:5
+   |
+LL | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) {
+   |        -                      - has type `Ref<'1, i32>`
+   |        |
+   |        has type `&mut std::vec::Vec<Ref<'2, i32>>`
+LL |     x.push(y);
+   |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr
new file mode 100644
index 00000000000..fbefa1f5667
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2c-push-inference-variable.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex2c-push-inference-variable.rs:7:5
+   |
+LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
+   |            --  -- lifetime `'c` defined here
+   |            |
+   |            lifetime `'b` defined here
+LL |     let z = Ref { data: y.data };
+LL |     x.push(z);
+   |     ^^^^^^^^^ argument requires that `'c` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr
new file mode 100644
index 00000000000..d889eb4afdb
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex2d-push-inference-variable-2.rs:8:5
+   |
+LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
+   |            --  -- lifetime `'c` defined here
+   |            |
+   |            lifetime `'b` defined here
+...
+LL |     a.push(b);
+   |     ^^^^^^^^^ argument requires that `'c` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr
new file mode 100644
index 00000000000..39eb4079352
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex2e-push-inference-variable-3.rs:8:5
+   |
+LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) {
+   |            --  -- lifetime `'c` defined here
+   |            |
+   |            lifetime `'b` defined here
+...
+LL |     Vec::push(a, b);
+   |     ^^^^^^^^^^^^^^^ argument requires that `'c` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr
new file mode 100644
index 00000000000..a94f9a79906
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-2.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-2.rs:2:5
+   |
+LL | fn foo(&mut (ref mut v, w): &mut (&u8, &u8), x: &u8) {
+   |                                   -             - let's call the lifetime of this reference `'1`
+   |                                   |
+   |                                   let's call the lifetime of this reference `'2`
+LL |     *v = x;
+   |     ^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
new file mode 100644
index 00000000000..779e2eb8b92
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-3.nll.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-3.rs:2:5
+   |
+LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+   |                     -                   - let's call the lifetime of this reference `'1`
+   |                     |
+   |                     let's call the lifetime of this reference `'2`
+LL |     z.push((x,y));
+   |     ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-3.rs:2:5
+   |
+LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) {
+   |                         -                    - let's call the lifetime of this reference `'1`
+   |                         |
+   |                         let's call the lifetime of this reference `'2`
+LL |     z.push((x,y));
+   |     ^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr
new file mode 100644
index 00000000000..4c0ffe5c090
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:7:5
+   |
+LL | fn foo(mut x: Ref, y: Ref) {
+   |        -----       - has type `Ref<'_, '1>`
+   |        |
+   |        has type `Ref<'_, '2>`
+LL |     x.b = y.b;
+   |     ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr
new file mode 100644
index 00000000000..97c665347f6
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:7:5
+   |
+LL | fn foo(mut x: Ref) {
+   |        -----
+   |        |
+   |        has type `Ref<'_, '1>`
+   |        has type `Ref<'2, '_>`
+LL |     x.a = x.b;
+   |     ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr
new file mode 100644
index 00000000000..a39bb165806
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:9:5
+   |
+LL | fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>)
+   |        --  -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+...
+LL |     x.push(y);
+   |     ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr
new file mode 100644
index 00000000000..48ce5301ade
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:6:5
+   |
+LL | fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>) {
+   |        --  -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+LL |     x.push(y);
+   |     ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr
new file mode 100644
index 00000000000..f9c33c24806
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-both-are-structs.rs:6:5
+   |
+LL | fn foo(mut x: Vec<Ref>, y: Ref) {
+   |        -----            - has type `Ref<'1>`
+   |        |
+   |        has type `std::vec::Vec<Ref<'2>>`
+LL |     x.push(y);
+   |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr
new file mode 100644
index 00000000000..09960683980
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-latebound-regions.rs:2:5
+   |
+LL | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) {
+   |        -- -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+LL |     x.push(y);
+   |     ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr
new file mode 100644
index 00000000000..5751c319489
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr
@@ -0,0 +1,21 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5
+   |
+LL | fn foo(mut x: Ref, y: &u32) {
+   |        -----          - let's call the lifetime of this reference `'2`
+   |        |
+   |        has type `Ref<'_, '1>`
+LL |     y = x.b;
+   |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error[E0384]: cannot assign to immutable argument `y`
+  --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5
+   |
+LL | fn foo(mut x: Ref, y: &u32) {
+   |                    - help: make this binding mutable: `mut y`
+LL |     y = x.b;
+   |     ^^^^^^^ cannot assign to immutable argument
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0384`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr
new file mode 100644
index 00000000000..79e7e8e157d
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:4:5
+   |
+LL | fn foo(mut y: Ref, x: &u32) {
+   |        -----          - let's call the lifetime of this reference `'1`
+   |        |
+   |        has type `Ref<'_, '2>`
+LL |     y.b = x;
+   |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr
new file mode 100644
index 00000000000..53615fd1aba
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:4:5
+   |
+LL | fn foo(mut y: Ref, x: &u32) {
+   |        -----          - let's call the lifetime of this reference `'1`
+   |        |
+   |        has type `Ref<'_, '2>`
+LL |     y.b = x;
+   |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr
new file mode 100644
index 00000000000..6ff44116737
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-one-is-struct.rs:7:5
+   |
+LL | fn foo(mut x: Ref, y: &u32) {
+   |        -----          - let's call the lifetime of this reference `'1`
+   |        |
+   |        has type `Ref<'_, '2>`
+LL |     x.b = y;
+   |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr
new file mode 100644
index 00000000000..1c258ad98ba
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:7:5
+   |
+LL |   fn foo<'a>(&self, x: &i32) -> &i32 {
+   |              -         - let's call the lifetime of this reference `'1`
+   |              |
+   |              let's call the lifetime of this reference `'2`
+LL |     x
+   |     ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr
new file mode 100644
index 00000000000..ffe39fdd8c9
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-self-is-anon.rs:7:19
+   |
+LL |     fn foo<'a>(&self, x: &Foo) -> &Foo {
+   |                -         - let's call the lifetime of this reference `'1`
+   |                |
+   |                let's call the lifetime of this reference `'2`
+LL |         if true { x } else { self }
+   |                   ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr
new file mode 100644
index 00000000000..33be98c6491
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr
@@ -0,0 +1,21 @@
+error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
+  --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
+   |
+LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+   |                        - help: consider changing this to be mutable: `mut y`
+LL |   y.push(z);
+   |   ^ cannot borrow as mutable
+
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3
+   |
+LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
+   |                               -        - let's call the lifetime of this reference `'1`
+   |                               |
+   |                               let's call the lifetime of this reference `'2`
+LL |   y.push(z);
+   |   ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr
new file mode 100644
index 00000000000..f3502674849
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-using-impl-items.rs:6:9
+   |
+LL |     fn foo(x: &mut Vec<&u8>, y: &u8) {
+   |                        -        - let's call the lifetime of this reference `'1`
+   |                        |
+   |                        let's call the lifetime of this reference `'2`
+LL |         x.push(y);
+   |         ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr
new file mode 100644
index 00000000000..c4e7ff90069
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr
@@ -0,0 +1,21 @@
+error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
+  --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
+   |
+LL | fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
+   |                              - help: consider changing this to be mutable: `mut y`
+LL |   y.push(z);
+   |   ^ cannot borrow as mutable
+
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3
+   |
+LL | fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) {
+   |                                     -        - let's call the lifetime of this reference `'1`
+   |                                     |
+   |                                     let's call the lifetime of this reference `'2`
+LL |   y.push(z);
+   |   ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr
new file mode 100644
index 00000000000..6989acfa196
--- /dev/null
+++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/ex3-both-anon-regions.rs:2:5
+   |
+LL | fn foo(x: &mut Vec<&u8>, y: &u8) {
+   |                    -        - let's call the lifetime of this reference `'1`
+   |                    |
+   |                    let's call the lifetime of this reference `'2`
+LL |     x.push(y);
+   |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/linkage2.rs b/src/test/ui/linkage2.rs
index fa4221fb339..f9ea5319d54 100644
--- a/src/test/ui/linkage2.rs
+++ b/src/test/ui/linkage2.rs
@@ -1,6 +1,7 @@
 // FIXME https://github.com/rust-lang/rust/issues/59774
 // normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
 // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// ignore-sgx no weak linkages permitted
 
 #![feature(linkage)]
 
diff --git a/src/test/ui/linkage2.stderr b/src/test/ui/linkage2.stderr
index c72978388eb..8326c0baccc 100644
--- a/src/test/ui/linkage2.stderr
+++ b/src/test/ui/linkage2.stderr
@@ -1,5 +1,5 @@
 error: must have type `*const T` or `*mut T`
-  --> $DIR/linkage2.rs:8:32
+  --> $DIR/linkage2.rs:9:32
    |
 LL |     #[linkage = "extern_weak"] static foo: i32;
    |                                ^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/lub-if.nll.stderr b/src/test/ui/lub-if.nll.stderr
new file mode 100644
index 00000000000..832688f5162
--- /dev/null
+++ b/src/test/ui/lub-if.nll.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/lub-if.rs:28:9
+   |
+LL | pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
+   |                 -- lifetime `'a` defined here
+...
+LL |         s
+   |         ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/lub-if.rs:35:9
+   |
+LL | pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
+   |                 -- lifetime `'a` defined here
+...
+LL |         s
+   |         ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lub-match.nll.stderr b/src/test/ui/lub-match.nll.stderr
new file mode 100644
index 00000000000..3a344a77d2c
--- /dev/null
+++ b/src/test/ui/lub-match.nll.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/lub-match.rs:30:13
+   |
+LL | pub fn opt_str2<'a>(maybestr: &'a Option<String>) -> &'static str {
+   |                 -- lifetime `'a` defined here
+...
+LL |             s
+   |             ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/lub-match.rs:39:13
+   |
+LL | pub fn opt_str3<'a>(maybestr: &'a Option<String>) -> &'static str {
+   |                 -- lifetime `'a` defined here
+...
+LL |             s
+   |             ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/macros/macro-attribute.stderr b/src/test/ui/macros/macro-attribute.stderr
index aa1cd94b0c6..d28ce25341d 100644
--- a/src/test/ui/macros/macro-attribute.stderr
+++ b/src/test/ui/macros/macro-attribute.stderr
@@ -1,8 +1,8 @@
 error: unexpected token: `$`
-  --> $DIR/macro-attribute.rs:1:7
+  --> $DIR/macro-attribute.rs:1:9
    |
 LL | #[doc = $not_there]
-   |       ^
+   |         ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs
index e452435968b..7c4ca3c017e 100644
--- a/src/test/ui/malformed/malformed-interpolated.rs
+++ b/src/test/ui/malformed/malformed-interpolated.rs
@@ -2,8 +2,7 @@
 
 macro_rules! check {
     ($expr: expr) => (
-        #[my_attr = $expr] //~ ERROR suffixed literals are not allowed in attributes
-                           //~| ERROR unexpected token: `-0`
+        #[my_attr = $expr] //~ ERROR unexpected token: `-0`
                            //~| ERROR unexpected token: `0 + 0`
         use main as _;
     );
@@ -11,7 +10,7 @@ macro_rules! check {
 
 check!("0"); // OK
 check!(0); // OK
-check!(0u8); // ERROR, see above
+check!(0u8); //~ ERROR suffixed literals are not allowed in attributes
 check!(-0); // ERROR, see above
 check!(0 + 0); // ERROR, see above
 
diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr
index efeede0148d..e805416172b 100644
--- a/src/test/ui/malformed/malformed-interpolated.stderr
+++ b/src/test/ui/malformed/malformed-interpolated.stderr
@@ -1,28 +1,25 @@
 error: suffixed literals are not allowed in attributes
-  --> $DIR/malformed-interpolated.rs:5:21
+  --> $DIR/malformed-interpolated.rs:13:8
    |
-LL |         #[my_attr = $expr]
-   |                     ^^^^^
-...
-LL | check!(0u8); // ERROR, see above
-   | ------------ in this macro invocation
+LL | check!(0u8);
+   |        ^^^
    |
    = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.).
 
 error: unexpected token: `-0`
-  --> $DIR/malformed-interpolated.rs:5:19
+  --> $DIR/malformed-interpolated.rs:5:21
    |
 LL |         #[my_attr = $expr]
-   |                   ^
+   |                     ^^^^^
 ...
 LL | check!(-0); // ERROR, see above
    | ----------- in this macro invocation
 
 error: unexpected token: `0 + 0`
-  --> $DIR/malformed-interpolated.rs:5:19
+  --> $DIR/malformed-interpolated.rs:5:21
    |
 LL |         #[my_attr = $expr]
-   |                   ^
+   |                     ^^^^^
 ...
 LL | check!(0 + 0); // ERROR, see above
    | -------------- in this macro invocation
diff --git a/src/test/ui/match/match-ref-mut-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-invariance.nll.stderr
new file mode 100644
index 00000000000..505b8db6a33
--- /dev/null
+++ b/src/test/ui/match/match-ref-mut-invariance.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/match-ref-mut-invariance.rs:10:9
+   |
+LL | impl<'b> S<'b> {
+   |      -- lifetime `'b` defined here
+LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+   |            -- lifetime `'a` defined here
+LL |         match self.0 { ref mut x => x }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
new file mode 100644
index 00000000000..ab5f43d0222
--- /dev/null
+++ b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/match-ref-mut-let-invariance.rs:11:9
+   |
+LL | impl<'b> S<'b> {
+   |      -- lifetime `'b` defined here
+LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
+   |            -- lifetime `'a` defined here
+LL |         let ref mut x = self.0;
+LL |         x
+   |         ^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/mir-dataflow/def-inits-1.rs b/src/test/ui/mir-dataflow/def-inits-1.rs
index 07ac1900bc7..91d41e9b579 100644
--- a/src/test/ui/mir-dataflow/def-inits-1.rs
+++ b/src/test/ui/mir-dataflow/def-inits-1.rs
@@ -1,6 +1,5 @@
 // General test of maybe_uninits state computed by MIR dataflow.
 
-#![feature(nll)]
 #![feature(core_intrinsics, rustc_attrs)]
 
 use std::intrinsics::rustc_peek;
diff --git a/src/test/ui/mir-dataflow/def-inits-1.stderr b/src/test/ui/mir-dataflow/def-inits-1.stderr
index 6bc5f7dcb99..48d84504894 100644
--- a/src/test/ui/mir-dataflow/def-inits-1.stderr
+++ b/src/test/ui/mir-dataflow/def-inits-1.stderr
@@ -1,23 +1,23 @@
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:15:14
+  --> $DIR/def-inits-1.rs:14:14
    |
 LL |     unsafe { rustc_peek(&ret); }
    |              ^^^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:31:14
+  --> $DIR/def-inits-1.rs:30:14
    |
 LL |     unsafe { rustc_peek(&z); }
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:34:14
+  --> $DIR/def-inits-1.rs:33:14
    |
 LL |     unsafe { rustc_peek(&y); }
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/def-inits-1.rs:42:14
+  --> $DIR/def-inits-1.rs:41:14
    |
 LL |     unsafe { rustc_peek(&x); }
    |              ^^^^^^^^^^^^^^
diff --git a/src/test/ui/mir-dataflow/inits-1.rs b/src/test/ui/mir-dataflow/inits-1.rs
index 13f900e4a75..4a4786a2a73 100644
--- a/src/test/ui/mir-dataflow/inits-1.rs
+++ b/src/test/ui/mir-dataflow/inits-1.rs
@@ -1,6 +1,5 @@
 // General test of maybe_inits state computed by MIR dataflow.
 
-#![feature(nll)]
 #![feature(core_intrinsics, rustc_attrs)]
 
 use std::intrinsics::rustc_peek;
diff --git a/src/test/ui/mir-dataflow/inits-1.stderr b/src/test/ui/mir-dataflow/inits-1.stderr
index 38a9c60b168..23d0679cb1a 100644
--- a/src/test/ui/mir-dataflow/inits-1.stderr
+++ b/src/test/ui/mir-dataflow/inits-1.stderr
@@ -1,17 +1,17 @@
 error: rustc_peek: bit not set
-  --> $DIR/inits-1.rs:15:14
+  --> $DIR/inits-1.rs:14:14
    |
 LL |     unsafe { rustc_peek(&ret); }
    |              ^^^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/inits-1.rs:35:14
+  --> $DIR/inits-1.rs:34:14
    |
 LL |     unsafe { rustc_peek(&y); }
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/inits-1.rs:43:14
+  --> $DIR/inits-1.rs:42:14
    |
 LL |     unsafe { rustc_peek(&x); }
    |              ^^^^^^^^^^^^^^
diff --git a/src/test/ui/mir-dataflow/uninits-1.rs b/src/test/ui/mir-dataflow/uninits-1.rs
index 4c643596932..66b3f458a51 100644
--- a/src/test/ui/mir-dataflow/uninits-1.rs
+++ b/src/test/ui/mir-dataflow/uninits-1.rs
@@ -1,6 +1,5 @@
 // General test of maybe_uninits state computed by MIR dataflow.
 
-#![feature(nll)]
 #![feature(core_intrinsics, rustc_attrs)]
 
 use std::intrinsics::rustc_peek;
diff --git a/src/test/ui/mir-dataflow/uninits-1.stderr b/src/test/ui/mir-dataflow/uninits-1.stderr
index c60987050e6..5f6dbde212d 100644
--- a/src/test/ui/mir-dataflow/uninits-1.stderr
+++ b/src/test/ui/mir-dataflow/uninits-1.stderr
@@ -1,29 +1,29 @@
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:19:14
+  --> $DIR/uninits-1.rs:18:14
    |
 LL |     unsafe { rustc_peek(&x) };
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:20:14
+  --> $DIR/uninits-1.rs:19:14
    |
 LL |     unsafe { rustc_peek(&y) };
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:21:14
+  --> $DIR/uninits-1.rs:20:14
    |
 LL |     unsafe { rustc_peek(&z) };
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:37:14
+  --> $DIR/uninits-1.rs:36:14
    |
 LL |     unsafe { rustc_peek(&x); }
    |              ^^^^^^^^^^^^^^
 
 error: rustc_peek: bit not set
-  --> $DIR/uninits-1.rs:45:14
+  --> $DIR/uninits-1.rs:44:14
    |
 LL |     unsafe { rustc_peek(&ret); }
    |              ^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/mir-dataflow/uninits-2.rs b/src/test/ui/mir-dataflow/uninits-2.rs
index 2247e68d097..2ccf1c7f9d6 100644
--- a/src/test/ui/mir-dataflow/uninits-2.rs
+++ b/src/test/ui/mir-dataflow/uninits-2.rs
@@ -1,6 +1,5 @@
 // General test of maybe_uninits state computed by MIR dataflow.
 
-#![feature(nll)]
 #![feature(core_intrinsics, rustc_attrs)]
 
 use std::intrinsics::rustc_peek;
diff --git a/src/test/ui/mir-dataflow/uninits-2.stderr b/src/test/ui/mir-dataflow/uninits-2.stderr
index de3e58e52de..dcb61371994 100644
--- a/src/test/ui/mir-dataflow/uninits-2.stderr
+++ b/src/test/ui/mir-dataflow/uninits-2.stderr
@@ -1,5 +1,5 @@
 error: rustc_peek: bit not set
-  --> $DIR/uninits-2.rs:15:14
+  --> $DIR/uninits-2.rs:14:14
    |
 LL |     unsafe { rustc_peek(&x) };
    |              ^^^^^^^^^^^^^^
diff --git a/src/test/ui/nll/borrow-use-issue-46875.rs b/src/test/ui/nll/borrow-use-issue-46875.rs
index 03db28fc508..42e28b9674b 100644
--- a/src/test/ui/nll/borrow-use-issue-46875.rs
+++ b/src/test/ui/nll/borrow-use-issue-46875.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // run-pass
 
 fn vec() {
diff --git a/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs b/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
index 59936a80925..7d3b00dfc71 100644
--- a/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
+++ b/src/test/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.rs
@@ -3,7 +3,6 @@
 //
 // FIXME(#54366) - We probably shouldn't allow #[thread_local] static mut to get a 'static lifetime.
 
-#![feature(nll)]
 #![feature(thread_local)]
 
 #[thread_local]
diff --git a/src/test/ui/nll/borrowed-local-error.rs b/src/test/ui/nll/borrowed-local-error.rs
index d37e61b63a8..d333356d964 100644
--- a/src/test/ui/nll/borrowed-local-error.rs
+++ b/src/test/ui/nll/borrowed-local-error.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn gimme(x: &(u32,)) -> &u32 {
     &x.0
 }
diff --git a/src/test/ui/nll/borrowed-local-error.stderr b/src/test/ui/nll/borrowed-local-error.stderr
index 799eec9d342..d629caa4353 100644
--- a/src/test/ui/nll/borrowed-local-error.stderr
+++ b/src/test/ui/nll/borrowed-local-error.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `v` does not live long enough
-  --> $DIR/borrowed-local-error.rs:10:9
+  --> $DIR/borrowed-local-error.rs:8:9
    |
 LL |     let x = gimme({
    |             ----- borrow later used by call
diff --git a/src/test/ui/nll/borrowed-referent-issue-38899.rs b/src/test/ui/nll/borrowed-referent-issue-38899.rs
index 7bad6dc2cd3..d4b05fb7931 100644
--- a/src/test/ui/nll/borrowed-referent-issue-38899.rs
+++ b/src/test/ui/nll/borrowed-referent-issue-38899.rs
@@ -1,7 +1,6 @@
 // Regression test for issue #38899
 
 #![feature(nll)]
-#![allow(dead_code)]
 
 pub struct Block<'a> {
     current: &'a u8,
diff --git a/src/test/ui/nll/borrowed-referent-issue-38899.stderr b/src/test/ui/nll/borrowed-referent-issue-38899.stderr
index 5c9c48f5b1d..38a6e27a0e5 100644
--- a/src/test/ui/nll/borrowed-referent-issue-38899.stderr
+++ b/src/test/ui/nll/borrowed-referent-issue-38899.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowed-referent-issue-38899.rs:14:21
+  --> $DIR/borrowed-referent-issue-38899.rs:13:21
    |
 LL |     let x = &mut block;
    |             ---------- mutable borrow occurs here
diff --git a/src/test/ui/nll/borrowed-temporary-error.rs b/src/test/ui/nll/borrowed-temporary-error.rs
index 5ad987c7214..37d0e670d35 100644
--- a/src/test/ui/nll/borrowed-temporary-error.rs
+++ b/src/test/ui/nll/borrowed-temporary-error.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn gimme(x: &(u32,)) -> &u32 {
     &x.0
 }
diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr
index c0d42312eb1..2c6bd92641f 100644
--- a/src/test/ui/nll/borrowed-temporary-error.stderr
+++ b/src/test/ui/nll/borrowed-temporary-error.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/borrowed-temporary-error.rs:10:10
+  --> $DIR/borrowed-temporary-error.rs:8:10
    |
 LL |         &(v,)
    |          ^^^^ creates a temporary which is freed while still in use
diff --git a/src/test/ui/nll/borrowed-universal-error-2.rs b/src/test/ui/nll/borrowed-universal-error-2.rs
index a10a62b470d..3f9b2f2924c 100644
--- a/src/test/ui/nll/borrowed-universal-error-2.rs
+++ b/src/test/ui/nll/borrowed-universal-error-2.rs
@@ -1,6 +1,3 @@
-#![feature(nll)]
-#![allow(warnings)]
-
 fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
     let v = 22;
     &v
diff --git a/src/test/ui/nll/borrowed-universal-error-2.stderr b/src/test/ui/nll/borrowed-universal-error-2.stderr
index e89a77a2d36..7213ed3bafb 100644
--- a/src/test/ui/nll/borrowed-universal-error-2.stderr
+++ b/src/test/ui/nll/borrowed-universal-error-2.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return reference to local variable `v`
-  --> $DIR/borrowed-universal-error-2.rs:6:5
+  --> $DIR/borrowed-universal-error-2.rs:3:5
    |
 LL |     &v
    |     ^^ returns a reference to data owned by the current function
diff --git a/src/test/ui/nll/borrowed-universal-error.rs b/src/test/ui/nll/borrowed-universal-error.rs
index 18a0a72c4bb..fc9ffd47061 100644
--- a/src/test/ui/nll/borrowed-universal-error.rs
+++ b/src/test/ui/nll/borrowed-universal-error.rs
@@ -1,6 +1,3 @@
-#![feature(nll)]
-#![allow(warnings)]
-
 fn gimme(x: &(u32,)) -> &u32 {
     &x.0
 }
diff --git a/src/test/ui/nll/borrowed-universal-error.stderr b/src/test/ui/nll/borrowed-universal-error.stderr
index 4b76795943e..88a2d8fcf8c 100644
--- a/src/test/ui/nll/borrowed-universal-error.stderr
+++ b/src/test/ui/nll/borrowed-universal-error.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing temporary value
-  --> $DIR/borrowed-universal-error.rs:10:5
+  --> $DIR/borrowed-universal-error.rs:7:5
    |
 LL |     gimme(&(v,))
    |     ^^^^^^^----^
diff --git a/src/test/ui/nll/capture-mut-ref.rs b/src/test/ui/nll/capture-mut-ref.rs
index 222f4e71c52..9d2624a9d6f 100644
--- a/src/test/ui/nll/capture-mut-ref.rs
+++ b/src/test/ui/nll/capture-mut-ref.rs
@@ -1,7 +1,6 @@
 // Check that capturing a mutable reference by move and assigning to its
 // referent doesn't make the unused mut lint think that it is mutable.
 
-#![feature(nll)]
 #![deny(unused_mut)]
 
 fn mutable_upvar() {
diff --git a/src/test/ui/nll/capture-mut-ref.stderr b/src/test/ui/nll/capture-mut-ref.stderr
index 327ce0c6e81..883b2d05a7f 100644
--- a/src/test/ui/nll/capture-mut-ref.stderr
+++ b/src/test/ui/nll/capture-mut-ref.stderr
@@ -1,5 +1,5 @@
 error: variable does not need to be mutable
-  --> $DIR/capture-mut-ref.rs:8:9
+  --> $DIR/capture-mut-ref.rs:7:9
    |
 LL |     let mut x = &mut 0;
    |         ----^
@@ -7,7 +7,7 @@ LL |     let mut x = &mut 0;
    |         help: remove this `mut`
    |
 note: lint level defined here
-  --> $DIR/capture-mut-ref.rs:5:9
+  --> $DIR/capture-mut-ref.rs:4:9
    |
 LL | #![deny(unused_mut)]
    |         ^^^^^^^^^^
diff --git a/src/test/ui/nll/capture-ref-in-struct.rs b/src/test/ui/nll/capture-ref-in-struct.rs
index bf2db32901e..db6ac7d66cc 100644
--- a/src/test/ui/nll/capture-ref-in-struct.rs
+++ b/src/test/ui/nll/capture-ref-in-struct.rs
@@ -1,9 +1,6 @@
 // Test that a structure which tries to store a pointer to `y` into
 // `p` (indirectly) fails to compile.
 
-#![feature(rustc_attrs)]
-#![feature(nll)]
-
 struct SomeStruct<'a, 'b: 'a> {
     p: &'a mut &'b i32,
     y: &'b i32,
diff --git a/src/test/ui/nll/capture-ref-in-struct.stderr b/src/test/ui/nll/capture-ref-in-struct.stderr
index 7fafb4474fd..521e543bd26 100644
--- a/src/test/ui/nll/capture-ref-in-struct.stderr
+++ b/src/test/ui/nll/capture-ref-in-struct.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `y` does not live long enough
-  --> $DIR/capture-ref-in-struct.rs:21:16
+  --> $DIR/capture-ref-in-struct.rs:18:16
    |
 LL |             y: &y,
    |                ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/closure-access-spans.rs b/src/test/ui/nll/closure-access-spans.rs
index 1e11b481818..2a59e80b25c 100644
--- a/src/test/ui/nll/closure-access-spans.rs
+++ b/src/test/ui/nll/closure-access-spans.rs
@@ -1,7 +1,5 @@
 // check that accesses due to a closure capture give a special note
 
-#![feature(nll)]
-
 fn closure_imm_capture_conflict(mut x: i32) {
     let r = &mut x;
     || x; //~ ERROR
diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr
index 32958e28a3d..4a8086905b7 100644
--- a/src/test/ui/nll/closure-access-spans.stderr
+++ b/src/test/ui/nll/closure-access-spans.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/closure-access-spans.rs:7:5
+  --> $DIR/closure-access-spans.rs:5:5
    |
 LL |     let r = &mut x;
    |             ------ mutable borrow occurs here
@@ -11,7 +11,7 @@ LL |     r.use_mut();
    |     - mutable borrow later used here
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/closure-access-spans.rs:13:5
+  --> $DIR/closure-access-spans.rs:11:5
    |
 LL |     let r = &mut x;
    |             ------ first mutable borrow occurs here
@@ -23,7 +23,7 @@ LL |     r.use_mut();
    |     - first borrow later used here
 
 error[E0500]: closure requires unique access to `x` but it is already borrowed
-  --> $DIR/closure-access-spans.rs:19:5
+  --> $DIR/closure-access-spans.rs:17:5
    |
 LL |     let r = &mut x;
    |             ------ borrow occurs here
@@ -35,7 +35,7 @@ LL |     r.use_mut();
    |     - first borrow later used here
 
 error[E0503]: cannot use `x` because it was mutably borrowed
-  --> $DIR/closure-access-spans.rs:25:13
+  --> $DIR/closure-access-spans.rs:23:13
    |
 LL |     let r = &mut x;
    |             ------ borrow of `x` occurs here
@@ -45,7 +45,7 @@ LL |     r.use_ref();
    |     - borrow later used here
 
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/closure-access-spans.rs:31:5
+  --> $DIR/closure-access-spans.rs:29:5
    |
 LL |     let r = &x;
    |             -- borrow of `x` occurs here
@@ -57,7 +57,7 @@ LL |     r.use_ref();
    |     - borrow later used here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-access-spans.rs:37:5
+  --> $DIR/closure-access-spans.rs:35:5
    |
 LL | fn closure_imm_capture_moved(mut x: String) {
    |                              ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
@@ -69,7 +69,7 @@ LL |     || x.len();
    |     value borrowed here after move
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-access-spans.rs:42:5
+  --> $DIR/closure-access-spans.rs:40:5
    |
 LL | fn closure_mut_capture_moved(mut x: String) {
    |                              ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
@@ -81,7 +81,7 @@ LL |     || x = String::new();
    |     value borrowed here after move
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-access-spans.rs:47:5
+  --> $DIR/closure-access-spans.rs:45:5
    |
 LL | fn closure_unique_capture_moved(x: &mut String) {
    |                                 - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
@@ -93,7 +93,7 @@ LL |     || *x = String::new();
    |     value borrowed here after move
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/closure-access-spans.rs:52:5
+  --> $DIR/closure-access-spans.rs:50:5
    |
 LL | fn closure_move_capture_moved(x: &mut String) {
    |                               - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/closure-borrow-spans.rs b/src/test/ui/nll/closure-borrow-spans.rs
index 7fc301b7038..b38f7900e8e 100644
--- a/src/test/ui/nll/closure-borrow-spans.rs
+++ b/src/test/ui/nll/closure-borrow-spans.rs
@@ -1,7 +1,5 @@
 // check that existing borrows due to a closure capture give a special note
 
-#![feature(nll)]
-
 fn move_while_borrowed(x: String) {
     let f = || x.len();
     let y = x; //~ ERROR
diff --git a/src/test/ui/nll/closure-borrow-spans.stderr b/src/test/ui/nll/closure-borrow-spans.stderr
index 30d99d56678..a3bcbbab3ec 100644
--- a/src/test/ui/nll/closure-borrow-spans.stderr
+++ b/src/test/ui/nll/closure-borrow-spans.stderr
@@ -1,5 +1,5 @@
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/closure-borrow-spans.rs:7:13
+  --> $DIR/closure-borrow-spans.rs:5:13
    |
 LL |     let f = || x.len();
    |             -- - borrow occurs due to use in closure
@@ -11,7 +11,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/closure-borrow-spans.rs:13:13
+  --> $DIR/closure-borrow-spans.rs:11:13
    |
 LL |     let f = || x;
    |             -- - first borrow occurs due to use of `x` in closure
@@ -23,7 +23,7 @@ LL |     f.use_ref();
    |     - immutable borrow later used here
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/closure-borrow-spans.rs:21:16
+  --> $DIR/closure-borrow-spans.rs:19:16
    |
 LL |         f = || x;
    |             -- ^ borrowed value does not live long enough
@@ -35,7 +35,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/closure-borrow-spans.rs:28:5
+  --> $DIR/closure-borrow-spans.rs:26:5
    |
 LL |     let f = || x;
    |             -- - borrow occurs due to use in closure
@@ -47,7 +47,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0503]: cannot use `x` because it was mutably borrowed
-  --> $DIR/closure-borrow-spans.rs:34:13
+  --> $DIR/closure-borrow-spans.rs:32:13
    |
 LL |     let f = || x = 0;
    |             -- - borrow occurs due to use of `x` in closure
@@ -59,7 +59,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/closure-borrow-spans.rs:40:13
+  --> $DIR/closure-borrow-spans.rs:38:13
    |
 LL |     let f = || x = 0;
    |             -- - first borrow occurs due to use of `x` in closure
@@ -71,7 +71,7 @@ LL |     f.use_ref();
    |     - mutable borrow later used here
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/closure-borrow-spans.rs:46:13
+  --> $DIR/closure-borrow-spans.rs:44:13
    |
 LL |     let f = || x = 0;
    |             -- - first borrow occurs due to use of `x` in closure
@@ -83,7 +83,7 @@ LL |     f.use_ref();
    |     - first borrow later used here
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/closure-borrow-spans.rs:54:16
+  --> $DIR/closure-borrow-spans.rs:52:16
    |
 LL |         f = || x = 0;
    |             -- ^ borrowed value does not live long enough
@@ -95,7 +95,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/closure-borrow-spans.rs:61:5
+  --> $DIR/closure-borrow-spans.rs:59:5
    |
 LL |     let f = || x = 0;
    |             -- - borrow occurs due to use in closure
@@ -107,7 +107,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/closure-borrow-spans.rs:67:13
+  --> $DIR/closure-borrow-spans.rs:65:13
    |
 LL |     let f = || *x = 0;
    |             --  - borrow occurs due to use in closure
@@ -119,7 +119,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
-  --> $DIR/closure-borrow-spans.rs:73:13
+  --> $DIR/closure-borrow-spans.rs:71:13
    |
 LL |     let f = || *x = 0;
    |             --  - first borrow occurs due to use of `x` in closure
@@ -131,7 +131,7 @@ LL |     f.use_ref();
    |     - first borrow later used here
 
 error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access
-  --> $DIR/closure-borrow-spans.rs:79:13
+  --> $DIR/closure-borrow-spans.rs:77:13
    |
 LL |     let f = || *x = 0;
    |             --  - first borrow occurs due to use of `x` in closure
@@ -143,7 +143,7 @@ LL |     f.use_ref();
    |     - first borrow later used here
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/closure-borrow-spans.rs:88:17
+  --> $DIR/closure-borrow-spans.rs:86:17
    |
 LL |         f = || *x = 0;
    |             --  ^ borrowed value does not live long enough
@@ -155,7 +155,7 @@ LL |     f.use_ref();
    |     - borrow later used here
 
 error[E0506]: cannot assign to `*x` because it is borrowed
-  --> $DIR/closure-borrow-spans.rs:95:5
+  --> $DIR/closure-borrow-spans.rs:93:5
    |
 LL |     let f = || *x = 0;
    |             --  - borrow occurs due to use in closure
diff --git a/src/test/ui/nll/closure-captures.rs b/src/test/ui/nll/closure-captures.rs
index 3a01f86cad8..16d90b97174 100644
--- a/src/test/ui/nll/closure-captures.rs
+++ b/src/test/ui/nll/closure-captures.rs
@@ -1,8 +1,5 @@
 // Some cases with closures that might be problems
 
-#![allow(unused)]
-#![feature(nll)]
-
 // Should have one error per assignment
 
 fn one_closure(x: i32) {
diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr
index fbd02bc8095..77f7d815eeb 100644
--- a/src/test/ui/nll/closure-captures.stderr
+++ b/src/test/ui/nll/closure-captures.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/closure-captures.rs:10:5
+  --> $DIR/closure-captures.rs:7:5
    |
 LL | fn one_closure(x: i32) {
    |                - help: consider changing this to be mutable: `mut x`
@@ -8,7 +8,7 @@ LL |     x = 1;
    |     ^^^^^ cannot assign
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/closure-captures.rs:12:5
+  --> $DIR/closure-captures.rs:9:5
    |
 LL | fn one_closure(x: i32) {
    |                - help: consider changing this to be mutable: `mut x`
@@ -17,7 +17,7 @@ LL |     x = 1;
    |     ^^^^^ cannot assign
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/closure-captures.rs:18:9
+  --> $DIR/closure-captures.rs:15:9
    |
 LL | fn two_closures(x: i32) {
    |                 - help: consider changing this to be mutable: `mut x`
@@ -26,7 +26,7 @@ LL |         x = 1;
    |         ^^^^^ cannot assign
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/closure-captures.rs:22:9
+  --> $DIR/closure-captures.rs:19:9
    |
 LL | fn two_closures(x: i32) {
    |                 - help: consider changing this to be mutable: `mut x`
@@ -35,7 +35,7 @@ LL |         x = 1;
    |         ^^^^^ cannot assign
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
-  --> $DIR/closure-captures.rs:30:9
+  --> $DIR/closure-captures.rs:27:9
    |
 LL |         ||
    |         ^^ cannot borrow as mutable
@@ -43,7 +43,7 @@ LL |          x = 1;}
    |          - mutable borrow occurs due to use of `x` in closure
    |
 help: consider changing this to accept closures that implement `FnMut`
-  --> $DIR/closure-captures.rs:29:12
+  --> $DIR/closure-captures.rs:26:12
    |
 LL |       fn_ref(|| {
    |  ____________^
@@ -52,7 +52,7 @@ LL | |          x = 1;}
    | |________________^
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
-  --> $DIR/closure-captures.rs:34:9
+  --> $DIR/closure-captures.rs:31:9
    |
 LL |         ||
    |         ^^ cannot borrow as mutable
@@ -60,7 +60,7 @@ LL |     x = 1;});
    |     - mutable borrow occurs due to use of `x` in closure
    |
 help: consider changing this to accept closures that implement `FnMut`
-  --> $DIR/closure-captures.rs:33:12
+  --> $DIR/closure-captures.rs:30:12
    |
 LL |       fn_ref(move || {
    |  ____________^
@@ -69,7 +69,7 @@ LL | |     x = 1;});
    | |___________^
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/closure-captures.rs:42:10
+  --> $DIR/closure-captures.rs:39:10
    |
 LL | fn two_closures_ref(x: i32) {
    |                     - help: consider changing this to be mutable: `mut x`
@@ -78,7 +78,7 @@ LL |          x = 1;}
    |          ^^^^^ cannot assign
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
-  --> $DIR/closure-captures.rs:41:9
+  --> $DIR/closure-captures.rs:38:9
    |
 LL |         ||
    |         ^^ cannot borrow as mutable
@@ -86,7 +86,7 @@ LL |          x = 1;}
    |          - mutable borrow occurs due to use of `x` in closure
    |
 help: consider changing this to accept closures that implement `FnMut`
-  --> $DIR/closure-captures.rs:40:12
+  --> $DIR/closure-captures.rs:37:12
    |
 LL |       fn_ref(|| {
    |  ____________^
@@ -95,7 +95,7 @@ LL | |          x = 1;}
    | |________________^
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
-  --> $DIR/closure-captures.rs:46:5
+  --> $DIR/closure-captures.rs:43:5
    |
 LL | fn two_closures_ref(x: i32) {
    |                     - help: consider changing this to be mutable: `mut x`
@@ -104,7 +104,7 @@ LL |     x = 1;});
    |     ^^^^^ cannot assign
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
-  --> $DIR/closure-captures.rs:45:9
+  --> $DIR/closure-captures.rs:42:9
    |
 LL |         ||
    |         ^^ cannot borrow as mutable
@@ -112,7 +112,7 @@ LL |     x = 1;});
    |     - mutable borrow occurs due to use of `x` in closure
    |
 help: consider changing this to accept closures that implement `FnMut`
-  --> $DIR/closure-captures.rs:44:12
+  --> $DIR/closure-captures.rs:41:12
    |
 LL |       fn_ref(move || {
    |  ____________^
@@ -121,7 +121,7 @@ LL | |     x = 1;});
    | |___________^
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
-  --> $DIR/closure-captures.rs:51:9
+  --> $DIR/closure-captures.rs:48:9
    |
 LL |         ||
    |         ^^ cannot borrow as mutable
@@ -129,7 +129,7 @@ LL |         *x = 1;});
    |          - mutable borrow occurs due to use of `x` in closure
    |
 help: consider changing this to accept closures that implement `FnMut`
-  --> $DIR/closure-captures.rs:50:12
+  --> $DIR/closure-captures.rs:47:12
    |
 LL |       fn_ref(|| {
    |  ____________^
@@ -138,7 +138,7 @@ LL | |         *x = 1;});
    | |________________^
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
-  --> $DIR/closure-captures.rs:54:9
+  --> $DIR/closure-captures.rs:51:9
    |
 LL |         ||
    |         ^^ cannot borrow as mutable
@@ -146,7 +146,7 @@ LL |         *x = 1;});
    |          - mutable borrow occurs due to use of `x` in closure
    |
 help: consider changing this to accept closures that implement `FnMut`
-  --> $DIR/closure-captures.rs:53:12
+  --> $DIR/closure-captures.rs:50:12
    |
 LL |       fn_ref(move || {
    |  ____________^
diff --git a/src/test/ui/nll/closure-move-spans.rs b/src/test/ui/nll/closure-move-spans.rs
index ffbfa9f8ae4..bf2431870a9 100644
--- a/src/test/ui/nll/closure-move-spans.rs
+++ b/src/test/ui/nll/closure-move-spans.rs
@@ -1,7 +1,5 @@
 // check that moves due to a closure capture give a special note
 
-#![feature(nll)]
-
 fn move_after_move(x: String) {
     || x;
     let y = x; //~ ERROR
diff --git a/src/test/ui/nll/closure-move-spans.stderr b/src/test/ui/nll/closure-move-spans.stderr
index 1cc4ca85b9f..972dbc6a61d 100644
--- a/src/test/ui/nll/closure-move-spans.stderr
+++ b/src/test/ui/nll/closure-move-spans.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/closure-move-spans.rs:7:13
+  --> $DIR/closure-move-spans.rs:5:13
    |
 LL | fn move_after_move(x: String) {
    |                    - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
@@ -11,7 +11,7 @@ LL |     let y = x;
    |             ^ value used here after move
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-move-spans.rs:12:13
+  --> $DIR/closure-move-spans.rs:10:13
    |
 LL | fn borrow_after_move(x: String) {
    |                      - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
@@ -23,7 +23,7 @@ LL |     let y = &x;
    |             ^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/closure-move-spans.rs:17:13
+  --> $DIR/closure-move-spans.rs:15:13
    |
 LL | fn borrow_mut_after_move(mut x: String) {
    |                          ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs b/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
index 71d5d4053ee..8ed6554877e 100644
--- a/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
+++ b/src/test/ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs
@@ -1,7 +1,3 @@
-// revisions: migrate nll
-//[migrate]compile-flags: -Z borrowck=migrate
-#![cfg_attr(nll, feature(nll))]
-
 // compile-pass
 
 // Test that we propagate region relations from closures precisely when there is
diff --git a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs
index dbc659b4aee..a9d2a07715d 100644
--- a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs
+++ b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs
@@ -1,8 +1,6 @@
 // Test that we propagate *all* requirements to the caller, not just the first
 // one.
 
-#![feature(nll)]
-
 fn once<S, T, U, F: FnOnce(S, T) -> U>(f: F, s: S, t: T) -> U {
     f(s, t)
 }
diff --git a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
index 332724daaa8..2fec9bc62d1 100644
--- a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `local_arr` does not live long enough
-  --> $DIR/propagate-multiple-requirements.rs:17:14
+  --> $DIR/propagate-multiple-requirements.rs:15:14
    |
 LL |     let mut out: &mut &'static [i32] = &mut (&[1] as _);
    |                  ------------------- type annotation requires that `local_arr` is borrowed for `'static`
diff --git a/src/test/ui/nll/closure-use-spans.rs b/src/test/ui/nll/closure-use-spans.rs
index c7cd519cffb..6768250dcbc 100644
--- a/src/test/ui/nll/closure-use-spans.rs
+++ b/src/test/ui/nll/closure-use-spans.rs
@@ -1,7 +1,5 @@
 // check that liveness due to a closure capture gives a special note
 
-#![feature(nll)]
-
 fn use_as_borrow_capture(mut x: i32) {
     let y = &x;
     x = 0; //~ ERROR
diff --git a/src/test/ui/nll/closure-use-spans.stderr b/src/test/ui/nll/closure-use-spans.stderr
index 20696da3b8e..ec7e0f30855 100644
--- a/src/test/ui/nll/closure-use-spans.stderr
+++ b/src/test/ui/nll/closure-use-spans.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/closure-use-spans.rs:7:5
+  --> $DIR/closure-use-spans.rs:5:5
    |
 LL |     let y = &x;
    |             -- borrow of `x` occurs here
@@ -9,7 +9,7 @@ LL |     || *y;
    |         - borrow later captured here by closure
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/closure-use-spans.rs:13:5
+  --> $DIR/closure-use-spans.rs:11:5
    |
 LL |     let y = &mut x;
    |             ------ borrow of `x` occurs here
@@ -19,7 +19,7 @@ LL |     || *y = 1;
    |         - borrow later captured here by closure
 
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/closure-use-spans.rs:19:5
+  --> $DIR/closure-use-spans.rs:17:5
    |
 LL |     let y = &x;
    |             -- borrow of `x` occurs here
diff --git a/src/test/ui/nll/closures-in-loops.rs b/src/test/ui/nll/closures-in-loops.rs
index d2afa564734..491c186ecb5 100644
--- a/src/test/ui/nll/closures-in-loops.rs
+++ b/src/test/ui/nll/closures-in-loops.rs
@@ -1,8 +1,6 @@
 // Test messages where a closure capture conflicts with itself because it's in
 // a loop.
 
-#![feature(nll)]
-
 fn repreated_move(x: String) {
     for i in 0..10 {
         || x; //~ ERROR
diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr
index 692eaea92b8..7603f9650b5 100644
--- a/src/test/ui/nll/closures-in-loops.stderr
+++ b/src/test/ui/nll/closures-in-loops.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/closures-in-loops.rs:8:9
+  --> $DIR/closures-in-loops.rs:6:9
    |
 LL | fn repreated_move(x: String) {
    |                   - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
@@ -10,7 +10,7 @@ LL |         || x;
    |         value moved into closure here, in previous iteration of loop
 
 error[E0499]: cannot borrow `x` as mutable more than once at a time
-  --> $DIR/closures-in-loops.rs:15:16
+  --> $DIR/closures-in-loops.rs:13:16
    |
 LL |         v.push(|| x = String::new());
    |                ^^ - borrows occur due to use of `x` in closure
@@ -18,7 +18,7 @@ LL |         v.push(|| x = String::new());
    |                mutable borrow starts here in previous iteration of loop
 
 error[E0524]: two closures require unique access to `x` at the same time
-  --> $DIR/closures-in-loops.rs:22:16
+  --> $DIR/closures-in-loops.rs:20:16
    |
 LL |         v.push(|| *x = String::new());
    |                ^^  - borrows occur due to use of `x` in closure
diff --git a/src/test/ui/nll/constant-thread-locals-issue-47053.rs b/src/test/ui/nll/constant-thread-locals-issue-47053.rs
index 4dd01410c5e..dde0ef7a5bb 100644
--- a/src/test/ui/nll/constant-thread-locals-issue-47053.rs
+++ b/src/test/ui/nll/constant-thread-locals-issue-47053.rs
@@ -1,6 +1,5 @@
 // Regression test for issue #47053
 
-#![feature(nll)]
 #![feature(thread_local)]
 
 #[thread_local]
diff --git a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr
index 16a6e59e4da..8afb42d66a6 100644
--- a/src/test/ui/nll/constant-thread-locals-issue-47053.stderr
+++ b/src/test/ui/nll/constant-thread-locals-issue-47053.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to immutable static item `FOO`
-  --> $DIR/constant-thread-locals-issue-47053.rs:10:5
+  --> $DIR/constant-thread-locals-issue-47053.rs:9:5
    |
 LL |     FOO = 6;
    |     ^^^^^^^ cannot assign
diff --git a/src/test/ui/nll/decl-macro-illegal-copy.rs b/src/test/ui/nll/decl-macro-illegal-copy.rs
index 38bdb7dd270..f7243294669 100644
--- a/src/test/ui/nll/decl-macro-illegal-copy.rs
+++ b/src/test/ui/nll/decl-macro-illegal-copy.rs
@@ -1,6 +1,5 @@
 // Regression test for #46314
 
-#![feature(nll)]
 #![feature(decl_macro)]
 
 struct NonCopy(String);
diff --git a/src/test/ui/nll/decl-macro-illegal-copy.stderr b/src/test/ui/nll/decl-macro-illegal-copy.stderr
index 9232ff52393..7948485bd68 100644
--- a/src/test/ui/nll/decl-macro-illegal-copy.stderr
+++ b/src/test/ui/nll/decl-macro-illegal-copy.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `wrapper.inner`
-  --> $DIR/decl-macro-illegal-copy.rs:22:9
+  --> $DIR/decl-macro-illegal-copy.rs:21:9
    |
 LL |     $wrapper.inner
    |     -------------- value moved here
diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr
new file mode 100644
index 00000000000..27912306987
--- /dev/null
+++ b/src/test/ui/nll/get_default.nll.stderr
@@ -0,0 +1,48 @@
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:21:17
+   |
+LL | fn ok(map: &mut Map) -> &String {
+   |            - let's call the lifetime of this reference `'1`
+LL |     loop {
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+LL |             Some(v) => {
+LL |                 return v;
+   |                        - returning this value requires that `*map` is borrowed for `'1`
+...
+LL |                 map.set(String::new()); // Ideally, this would not error.
+   |                 ^^^ mutable borrow occurs here
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:32:17
+   |
+LL | fn err(map: &mut Map) -> &String {
+   |             - let's call the lifetime of this reference `'1`
+LL |     loop {
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+LL |             Some(v) => {
+LL |                 map.set(String::new()); // Both AST and MIR error here
+   |                 ^^^ mutable borrow occurs here
+LL |
+LL |                 return v;
+   |                        - returning this value requires that `*map` is borrowed for `'1`
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
+  --> $DIR/get_default.rs:37:17
+   |
+LL | fn err(map: &mut Map) -> &String {
+   |             - let's call the lifetime of this reference `'1`
+LL |     loop {
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 return v;
+   |                        - returning this value requires that `*map` is borrowed for `'1`
+...
+LL |                 map.set(String::new()); // Ideally, just AST would error here
+   |                 ^^^ mutable borrow occurs here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/issue-16223.rs b/src/test/ui/nll/issue-16223.rs
index 881e202acf8..e7536275064 100644
--- a/src/test/ui/nll/issue-16223.rs
+++ b/src/test/ui/nll/issue-16223.rs
@@ -15,7 +15,6 @@
 
 // compile-pass
 
-#![feature(nll)]
 #![feature(box_patterns)]
 
 struct Root {
diff --git a/src/test/ui/nll/issue-21114-ebfull.rs b/src/test/ui/nll/issue-21114-ebfull.rs
index f5738968746..1fe4fffa324 100644
--- a/src/test/ui/nll/issue-21114-ebfull.rs
+++ b/src/test/ui/nll/issue-21114-ebfull.rs
@@ -1,6 +1,4 @@
-// (this works, but only in NLL)
 // compile-pass
-#![feature(nll)]
 
 use std::collections::HashMap;
 use std::sync::Mutex;
diff --git a/src/test/ui/nll/issue-21114-kixunil.rs b/src/test/ui/nll/issue-21114-kixunil.rs
index 2add951b70b..80a85293e5a 100644
--- a/src/test/ui/nll/issue-21114-kixunil.rs
+++ b/src/test/ui/nll/issue-21114-kixunil.rs
@@ -1,6 +1,4 @@
-// (this works, but only in NLL)
 // compile-pass
-#![feature(nll)]
 
 fn from_stdin(min: u64) -> Vec<u64> {
     use std::io::BufRead;
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
index abafd330573..906ea32b9c4 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
+++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
@@ -8,8 +8,6 @@
 // meant to compile and run successfully once rust-lang/rust#54987 is
 // implemented.
 
-#![feature(nll)]
-
 struct D {
     x: u32,
     s: S,
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
index 862432a5bc6..153d9bdf321 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
@@ -1,17 +1,17 @@
 error[E0381]: assign of possibly uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:30:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5
    |
 LL |     d.x = 10;
    |     ^^^^^^^^ use of possibly uninitialized `d`
 
 error[E0381]: assign of possibly uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:36:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:34:5
    |
 LL |     d.x = 10;
    |     ^^^^^^^^ use of possibly uninitialized `d`
 
 error[E0382]: assign of moved value: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:43:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:41:5
    |
 LL |     let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
    |         ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
@@ -21,19 +21,19 @@ LL |     d.x = 10;
    |     ^^^^^^^^ value assigned here after move
 
 error[E0381]: assign to part of possibly uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:49:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:47:5
    |
 LL |     d.s.y = 20;
    |     ^^^^^^^^^^ use of possibly uninitialized `d.s`
 
 error[E0381]: assign to part of possibly uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:55:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:53:5
    |
 LL |     d.s.y = 20;
    |     ^^^^^^^^^^ use of possibly uninitialized `d.s`
 
 error[E0382]: assign to part of moved value: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:62:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:60:5
    |
 LL |     let mut d = D { x: 0, s: S{ y: 0, z: 0} };
    |         ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/issue-22323-temp-destruction.rs b/src/test/ui/nll/issue-22323-temp-destruction.rs
index 2c547fb7c7d..6357c3ccef1 100644
--- a/src/test/ui/nll/issue-22323-temp-destruction.rs
+++ b/src/test/ui/nll/issue-22323-temp-destruction.rs
@@ -3,8 +3,6 @@
 
 // compile-pass
 
-#![feature(nll)]
-
 fn main() {
     let _s = construct().borrow().consume_borrowed();
 }
diff --git a/src/test/ui/nll/issue-30104.rs b/src/test/ui/nll/issue-30104.rs
index 88e49bf8df7..27e519005f6 100644
--- a/src/test/ui/nll/issue-30104.rs
+++ b/src/test/ui/nll/issue-30104.rs
@@ -2,8 +2,6 @@
 
 // compile-pass
 
-#![feature(nll)]
-
 use std::ops::{Deref, DerefMut};
 
 fn box_two_field(v: &mut Box<(i32, i32)>) {
diff --git a/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs b/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs
index a114d7092ec..7e0ffd6cf36 100644
--- a/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs
+++ b/src/test/ui/nll/issue-32382-index-assoc-type-with-lifetime.rs
@@ -1,4 +1,3 @@
-#![feature(nll)]
 // compile-pass
 
 // rust-lang/rust#32382: Borrow checker used to complain about
diff --git a/src/test/ui/nll/issue-43058.rs b/src/test/ui/nll/issue-43058.rs
index c5bae7a12d7..c50473511f1 100644
--- a/src/test/ui/nll/issue-43058.rs
+++ b/src/test/ui/nll/issue-43058.rs
@@ -1,7 +1,5 @@
 // compile-pass
 
-#![feature(nll)]
-
 use std::borrow::Cow;
 
 #[derive(Clone, Debug)]
diff --git a/src/test/ui/nll/issue-46589.rs b/src/test/ui/nll/issue-46589.rs
index 690f6f269eb..8c0c356e967 100644
--- a/src/test/ui/nll/issue-46589.rs
+++ b/src/test/ui/nll/issue-46589.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Foo;
 
 impl Foo {
diff --git a/src/test/ui/nll/issue-46589.stderr b/src/test/ui/nll/issue-46589.stderr
index 7b02b905303..397909a4366 100644
--- a/src/test/ui/nll/issue-46589.stderr
+++ b/src/test/ui/nll/issue-46589.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `**other` as mutable more than once at a time
-  --> $DIR/issue-46589.rs:19:21
+  --> $DIR/issue-46589.rs:17:21
    |
 LL |         *other = match (*other).get_self() {
    |                        -------- first mutable borrow occurs here
diff --git a/src/test/ui/nll/issue-47022.rs b/src/test/ui/nll/issue-47022.rs
index 1add2c334da..3f8e0f5ad3d 100644
--- a/src/test/ui/nll/issue-47022.rs
+++ b/src/test/ui/nll/issue-47022.rs
@@ -1,8 +1,5 @@
 // compile-pass
 
-#![allow(warnings)]
-#![feature(nll)]
-
 struct LoadedObject {
     bodies: Vec<Body>,
     color: Color,
diff --git a/src/test/ui/nll/issue-47388.rs b/src/test/ui/nll/issue-47388.rs
index df47baa3c17..207af380e62 100644
--- a/src/test/ui/nll/issue-47388.rs
+++ b/src/test/ui/nll/issue-47388.rs
@@ -1,4 +1,3 @@
-#![feature(nll)]
 struct FancyNum {
     num: u8,
 }
diff --git a/src/test/ui/nll/issue-47388.stderr b/src/test/ui/nll/issue-47388.stderr
index a5f5bf6ee2f..d4064b3f50a 100644
--- a/src/test/ui/nll/issue-47388.stderr
+++ b/src/test/ui/nll/issue-47388.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `fancy_ref.num` which is behind a `&` reference
-  --> $DIR/issue-47388.rs:9:5
+  --> $DIR/issue-47388.rs:8:5
    |
 LL |     let fancy_ref = &(&mut fancy);
    |                     ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
diff --git a/src/test/ui/nll/issue-47470.rs b/src/test/ui/nll/issue-47470.rs
index 67150b46c35..72ee7f88650 100644
--- a/src/test/ui/nll/issue-47470.rs
+++ b/src/test/ui/nll/issue-47470.rs
@@ -2,8 +2,6 @@
 // causing region relations not to be enforced at all the places where
 // they have to be enforced.
 
-#![feature(nll)]
-
 struct Foo<'a>(&'a ());
 trait Bar {
     type Assoc;
diff --git a/src/test/ui/nll/issue-47470.stderr b/src/test/ui/nll/issue-47470.stderr
index d23cee3fc7c..0b1247d60ec 100644
--- a/src/test/ui/nll/issue-47470.stderr
+++ b/src/test/ui/nll/issue-47470.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return reference to local variable `local`
-  --> $DIR/issue-47470.rs:17:9
+  --> $DIR/issue-47470.rs:15:9
    |
 LL |         &local
    |         ^^^^^^ returns a reference to data owned by the current function
diff --git a/src/test/ui/nll/issue-48070.rs b/src/test/ui/nll/issue-48070.rs
index c69bd3dbe90..47426cdfa57 100644
--- a/src/test/ui/nll/issue-48070.rs
+++ b/src/test/ui/nll/issue-48070.rs
@@ -1,8 +1,6 @@
 // run-pass
 // revisions: lxl nll
 
-#![cfg_attr(nll, feature(nll))]
-
 struct Foo {
     x: u32
 }
diff --git a/src/test/ui/nll/issue-48697.rs b/src/test/ui/nll/issue-48697.rs
index ececd6fccd8..16e29ab2a8a 100644
--- a/src/test/ui/nll/issue-48697.rs
+++ b/src/test/ui/nll/issue-48697.rs
@@ -1,7 +1,5 @@
 // Regression test for #48697
 
-#![feature(nll)]
-
 fn foo(x: &i32) -> &i32 {
     let z = 4;
     let f = &|y| y;
diff --git a/src/test/ui/nll/issue-48697.stderr b/src/test/ui/nll/issue-48697.stderr
index 73832fd5787..f0c29b72b42 100644
--- a/src/test/ui/nll/issue-48697.stderr
+++ b/src/test/ui/nll/issue-48697.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing local variable `z`
-  --> $DIR/issue-48697.rs:9:5
+  --> $DIR/issue-48697.rs:7:5
    |
 LL |     let k = f(&z);
    |               -- `z` is borrowed here
diff --git a/src/test/ui/nll/issue-50716-1.rs b/src/test/ui/nll/issue-50716-1.rs
index d963a620c9a..ec992959a66 100644
--- a/src/test/ui/nll/issue-50716-1.rs
+++ b/src/test/ui/nll/issue-50716-1.rs
@@ -3,12 +3,8 @@
 // bounds derived from `Sized` requirements” that checks that the fixed compiler
 // accepts this code fragment with both AST and MIR borrow checkers.
 //
-// revisions: migrate nll
-//
 // compile-pass
 
-#![cfg_attr(nll, feature(nll))]
-
 struct Qey<Q: ?Sized>(Q);
 
 fn main() {}
diff --git a/src/test/ui/nll/issue-50716.nll.stderr b/src/test/ui/nll/issue-50716.nll.stderr
new file mode 100644
index 00000000000..38dd1b5f6fe
--- /dev/null
+++ b/src/test/ui/nll/issue-50716.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-50716.rs:14:14
+   |
+LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+   |        -- lifetime `'a` defined here
+...
+LL |     let _x = *s;
+   |              ^^ proving this value is `Sized` requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-50716.rs b/src/test/ui/nll/issue-50716.rs
index ce4bee36656..c2fc345fa2b 100644
--- a/src/test/ui/nll/issue-50716.rs
+++ b/src/test/ui/nll/issue-50716.rs
@@ -2,8 +2,6 @@
 // Regression test for the issue #50716: NLL ignores lifetimes bounds
 // derived from `Sized` requirements
 
-#![feature(nll)]
-
 trait A {
     type X: ?Sized;
 }
diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr
index 7e5ffb51501..b19e3a9dfb3 100644
--- a/src/test/ui/nll/issue-50716.stderr
+++ b/src/test/ui/nll/issue-50716.stderr
@@ -1,11 +1,18 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-50716.rs:16:14
+error[E0308]: mismatched types
+  --> $DIR/issue-50716.rs:14:9
    |
-LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
-   |        -- lifetime `'a` defined here
-...
 LL |     let _x = *s;
-   |              ^^ proving this value is `Sized` requires that `'a` must outlive `'static`
+   |         ^^ lifetime mismatch
+   |
+   = note: expected type `std::marker::Sized`
+              found type `std::marker::Sized`
+note: the lifetime 'a as defined on the function body at 9:8...
+  --> $DIR/issue-50716.rs:9:8
+   |
+LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+   |        ^^
+   = note: ...does not necessarily outlive the static lifetime
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/nll/issue-51191.rs b/src/test/ui/nll/issue-51191.rs
index 6704b648699..747bfe3a8a5 100644
--- a/src/test/ui/nll/issue-51191.rs
+++ b/src/test/ui/nll/issue-51191.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Struct;
 
 impl Struct {
diff --git a/src/test/ui/nll/issue-51191.stderr b/src/test/ui/nll/issue-51191.stderr
index e80cd873d5a..e226de15dc2 100644
--- a/src/test/ui/nll/issue-51191.stderr
+++ b/src/test/ui/nll/issue-51191.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-51191.rs:6:5
+  --> $DIR/issue-51191.rs:4:5
    |
 LL |     fn bar(self: &mut Self) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -11,7 +11,7 @@ LL |         (&mut self).bar();
    = help: a `loop` may express intention better if this is on purpose
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:8:9
+  --> $DIR/issue-51191.rs:6:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |         (&mut self).bar();
    |         try removing `&mut` here
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:13:9
+  --> $DIR/issue-51191.rs:11:9
    |
 LL |     fn imm(self) {
    |            ---- help: consider changing this to be mutable: `mut self`
@@ -28,19 +28,19 @@ LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:22:9
+  --> $DIR/issue-51191.rs:20:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/issue-51191.rs:22:9
+  --> $DIR/issue-51191.rs:20:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:28:9
+  --> $DIR/issue-51191.rs:26:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^
diff --git a/src/test/ui/nll/issue-51244.rs b/src/test/ui/nll/issue-51244.rs
index aaf98ddfa27..743415d58af 100644
--- a/src/test/ui/nll/issue-51244.rs
+++ b/src/test/ui/nll/issue-51244.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn main() {
     let ref my_ref @ _ = 0;
     *my_ref = 0;
diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr
index 6b543389af5..8a7e71e0326 100644
--- a/src/test/ui/nll/issue-51244.stderr
+++ b/src/test/ui/nll/issue-51244.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `*my_ref` which is behind a `&` reference
-  --> $DIR/issue-51244.rs:5:5
+  --> $DIR/issue-51244.rs:3:5
    |
 LL |     let ref my_ref @ _ = 0;
    |         -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _`
diff --git a/src/test/ui/nll/issue-51268.rs b/src/test/ui/nll/issue-51268.rs
index c14146a3de2..12d0449abb1 100644
--- a/src/test/ui/nll/issue-51268.rs
+++ b/src/test/ui/nll/issue-51268.rs
@@ -1,7 +1,5 @@
 // ignore-tidy-linelength
 
-#![feature(nll)]
-
 struct Bar;
 
 impl Bar {
diff --git a/src/test/ui/nll/issue-51268.stderr b/src/test/ui/nll/issue-51268.stderr
index 0be181745fd..420c94f8e1b 100644
--- a/src/test/ui/nll/issue-51268.stderr
+++ b/src/test/ui/nll/issue-51268.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `self.thing` as mutable because it is also borrowed as immutable
-  --> $DIR/issue-51268.rs:18:9
+  --> $DIR/issue-51268.rs:16:9
    |
 LL |           self.thing.bar(|| {
    |           ^          --- -- immutable borrow occurs here
diff --git a/src/test/ui/nll/issue-51351.rs b/src/test/ui/nll/issue-51351.rs
index 939993f154f..b45477c7fb1 100644
--- a/src/test/ui/nll/issue-51351.rs
+++ b/src/test/ui/nll/issue-51351.rs
@@ -8,8 +8,6 @@
 //
 // compile-pass
 
-#![feature(nll)]
-
 fn creash<'a>() {
     let x: &'a () = &();
 }
diff --git a/src/test/ui/nll/issue-51512.rs b/src/test/ui/nll/issue-51512.rs
index 7e2e6e0a16c..691760eb91e 100644
--- a/src/test/ui/nll/issue-51512.rs
+++ b/src/test/ui/nll/issue-51512.rs
@@ -1,6 +1,3 @@
-#![allow(warnings)]
-#![feature(nll)]
-
 fn main() {
     let range = 0..1;
     let r = range;
diff --git a/src/test/ui/nll/issue-51512.stderr b/src/test/ui/nll/issue-51512.stderr
index a84a236ca77..e591ca08290 100644
--- a/src/test/ui/nll/issue-51512.stderr
+++ b/src/test/ui/nll/issue-51512.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `range`
-  --> $DIR/issue-51512.rs:7:13
+  --> $DIR/issue-51512.rs:4:13
    |
 LL |     let range = 0..1;
    |         ----- move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs
index eaa809d2b37..58416c31edd 100644
--- a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs
+++ b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs
@@ -4,7 +4,6 @@
 // of the fact that the type implements Drop.
 
 #![feature(nll)]
-#![allow(dead_code)]
 
 pub struct S<'a> { url: &'a mut String }
 
diff --git a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
index e8741036e1d..34259d06d38 100644
--- a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
+++ b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr
@@ -1,5 +1,5 @@
 error[E0713]: borrow may still be in use when destructor runs
-  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:14:5
+  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:13:5
    |
 LL | fn finish_1(s: S) -> &mut String {
    |             - has type `S<'1>`
@@ -9,7 +9,7 @@ LL | }
    | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait
 
 error[E0713]: borrow may still be in use when destructor runs
-  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:19:13
+  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:18:13
    |
 LL | fn finish_2(s: S) -> &mut String {
    |             - has type `S<'1>`
@@ -19,7 +19,7 @@ LL | }
    | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait
 
 error[E0713]: borrow may still be in use when destructor runs
-  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:24:21
+  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:23:21
    |
 LL | fn finish_3(s: S) -> &mut String {
    |             - has type `S<'1>`
@@ -29,7 +29,7 @@ LL | }
    | - here, drop of `s` needs exclusive access to `*s.url`, because the type `S<'_>` implements the `Drop` trait
 
 error[E0509]: cannot move out of type `S<'_>`, which implements the `Drop` trait
-  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:29:13
+  --> $DIR/issue-52059-report-when-borrow-and-drop-conflict.rs:28:13
    |
 LL |     let p = s.url; p
    |             ^^^^^
diff --git a/src/test/ui/nll/issue-52078.rs b/src/test/ui/nll/issue-52078.rs
index ebe442adbd9..4b8e6c68075 100644
--- a/src/test/ui/nll/issue-52078.rs
+++ b/src/test/ui/nll/issue-52078.rs
@@ -1,6 +1,3 @@
-#![feature(nll)]
-#![allow(unused_variables)]
-
 // Regression test for #52078: we were failing to infer a relationship
 // between `'a` and `'b` below due to inference variables introduced
 // during the normalization process.
diff --git a/src/test/ui/nll/issue-52086.rs b/src/test/ui/nll/issue-52086.rs
index 78765283ec2..0414428e481 100644
--- a/src/test/ui/nll/issue-52086.rs
+++ b/src/test/ui/nll/issue-52086.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 use std::rc::Rc;
 use std::sync::Arc;
 
diff --git a/src/test/ui/nll/issue-52086.stderr b/src/test/ui/nll/issue-52086.stderr
index ed4171ff142..da453fb1f92 100644
--- a/src/test/ui/nll/issue-52086.stderr
+++ b/src/test/ui/nll/issue-52086.stderr
@@ -1,11 +1,11 @@
 error[E0507]: cannot move out of an `Rc`
-  --> $DIR/issue-52086.rs:10:10
+  --> $DIR/issue-52086.rs:8:10
    |
 LL |     drop(x.field);
    |          ^^^^^^^ cannot move out of an `Rc`
 
 error[E0507]: cannot move out of an `Arc`
-  --> $DIR/issue-52086.rs:14:10
+  --> $DIR/issue-52086.rs:12:10
    |
 LL |     drop(y.field);
    |          ^^^^^^^ cannot move out of an `Arc`
diff --git a/src/test/ui/nll/issue-52113.rs b/src/test/ui/nll/issue-52113.rs
index 795f4f426ff..0d7ee037692 100644
--- a/src/test/ui/nll/issue-52113.rs
+++ b/src/test/ui/nll/issue-52113.rs
@@ -1,6 +1,3 @@
-//
-
-#![allow(warnings)]
 #![feature(nll)]
 
 trait Bazinga {}
diff --git a/src/test/ui/nll/issue-52113.stderr b/src/test/ui/nll/issue-52113.stderr
index 8638fe25769..590963ded78 100644
--- a/src/test/ui/nll/issue-52113.stderr
+++ b/src/test/ui/nll/issue-52113.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-52113.rs:37:5
+  --> $DIR/issue-52113.rs:34:5
    |
 LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
    |                --  -- lifetime `'b` defined here
diff --git a/src/test/ui/nll/issue-52534-1.rs b/src/test/ui/nll/issue-52534-1.rs
index 7ab3593c89f..d9ea3ae42c4 100644
--- a/src/test/ui/nll/issue-52534-1.rs
+++ b/src/test/ui/nll/issue-52534-1.rs
@@ -1,6 +1,3 @@
-#![feature(nll)]
-#![allow(warnings)]
-
 struct Test;
 
 impl Test {
diff --git a/src/test/ui/nll/issue-52534-1.stderr b/src/test/ui/nll/issue-52534-1.stderr
index 7d82f5e710f..743179f05c1 100644
--- a/src/test/ui/nll/issue-52534-1.stderr
+++ b/src/test/ui/nll/issue-52534-1.stderr
@@ -1,17 +1,17 @@
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-52534-1.rs:9:9
+  --> $DIR/issue-52534-1.rs:6:9
    |
 LL |         &x
    |         ^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-52534-1.rs:16:5
+  --> $DIR/issue-52534-1.rs:13:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return value referencing local variable `x`
-  --> $DIR/issue-52534-1.rs:22:5
+  --> $DIR/issue-52534-1.rs:19:5
    |
 LL |     &&x
    |     ^--
@@ -20,7 +20,7 @@ LL |     &&x
    |     returns a value referencing data owned by the current function
 
 error[E0515]: cannot return reference to temporary value
-  --> $DIR/issue-52534-1.rs:22:5
+  --> $DIR/issue-52534-1.rs:19:5
    |
 LL |     &&x
    |     ^--
@@ -29,25 +29,25 @@ LL |     &&x
    |     returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-52534-1.rs:29:5
+  --> $DIR/issue-52534-1.rs:26:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-52534-1.rs:35:5
+  --> $DIR/issue-52534-1.rs:32:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-52534-1.rs:41:5
+  --> $DIR/issue-52534-1.rs:38:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
 
 error[E0515]: cannot return reference to local variable `x`
-  --> $DIR/issue-52534-1.rs:47:5
+  --> $DIR/issue-52534-1.rs:44:5
    |
 LL |     &x
    |     ^^ returns a reference to data owned by the current function
diff --git a/src/test/ui/nll/issue-52534-2.rs b/src/test/ui/nll/issue-52534-2.rs
index 6e84869dd6d..e416264ed09 100644
--- a/src/test/ui/nll/issue-52534-2.rs
+++ b/src/test/ui/nll/issue-52534-2.rs
@@ -1,6 +1,3 @@
-#![feature(nll)]
-#![allow(warnings)]
-
 fn foo(x: &u32) -> &u32 {
     let y;
 
diff --git a/src/test/ui/nll/issue-52534-2.stderr b/src/test/ui/nll/issue-52534-2.stderr
index f98deaea718..dd8a87f7e29 100644
--- a/src/test/ui/nll/issue-52534-2.stderr
+++ b/src/test/ui/nll/issue-52534-2.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/issue-52534-2.rs:9:9
+  --> $DIR/issue-52534-2.rs:6:9
    |
 LL |         y = &x
    |         ^^^^^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/issue-52534.rs b/src/test/ui/nll/issue-52534.rs
index 1394560df19..559d4c8591b 100644
--- a/src/test/ui/nll/issue-52534.rs
+++ b/src/test/ui/nll/issue-52534.rs
@@ -1,6 +1,3 @@
-#![feature(nll)]
-#![allow(warnings)]
-
 fn foo(_: impl FnOnce(&u32) -> &u32) {
 }
 
diff --git a/src/test/ui/nll/issue-52534.stderr b/src/test/ui/nll/issue-52534.stderr
index 9ac79eda161..b2b727fd438 100644
--- a/src/test/ui/nll/issue-52534.stderr
+++ b/src/test/ui/nll/issue-52534.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/issue-52534.rs:12:14
+  --> $DIR/issue-52534.rs:9:14
    |
 LL |     foo(|a| &x)
    |          -   ^ `x` would have to be valid for `'0`...
@@ -13,7 +13,7 @@ LL | }
    = note: to learn more, visit <https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#dangling-references>
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/issue-52534.rs:18:26
+  --> $DIR/issue-52534.rs:15:26
    |
 LL |     baz(|first, second| &y)
    |          -----           ^ `y` would have to be valid for `'0`...
diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs
index 3e57d26745a..24a4267f653 100644
--- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs
+++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn expect_fn<F>(f: F) where F : Fn() {
     f();
 }
diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
index 0162c6bcbd1..8958bdf4c2a 100644
--- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
+++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/issue-52663-span-decl-captured-variable.rs:10:26
+  --> $DIR/issue-52663-span-decl-captured-variable.rs:8:26
    |
 LL |        let x = (vec![22], vec![44]);
    |            - captured outer variable
diff --git a/src/test/ui/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs
index 121c3ef4e61..e8e571aadc3 100644
--- a/src/test/ui/nll/issue-52663-trait-object.rs
+++ b/src/test/ui/nll/issue-52663-trait-object.rs
@@ -1,5 +1,4 @@
 #![feature(box_syntax)]
-#![feature(nll)]
 
 trait Foo { fn get(&self); }
 
diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr
index b9437d88ff6..9262117f397 100644
--- a/src/test/ui/nll/issue-52663-trait-object.stderr
+++ b/src/test/ui/nll/issue-52663-trait-object.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `tmp0` does not live long enough
-  --> $DIR/issue-52663-trait-object.rs:13:20
+  --> $DIR/issue-52663-trait-object.rs:12:20
    |
 LL |         let tmp1 = &tmp0;
    |                    ^^^^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/issue-52669.rs b/src/test/ui/nll/issue-52669.rs
index 6027e988141..e33528ac59e 100644
--- a/src/test/ui/nll/issue-52669.rs
+++ b/src/test/ui/nll/issue-52669.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct A {
     b: B,
 }
diff --git a/src/test/ui/nll/issue-52669.stderr b/src/test/ui/nll/issue-52669.stderr
index f51768c3859..db53e444b9e 100644
--- a/src/test/ui/nll/issue-52669.stderr
+++ b/src/test/ui/nll/issue-52669.stderr
@@ -1,5 +1,5 @@
 error[E0382]: borrow of moved value: `a.b`
-  --> $DIR/issue-52669.rs:15:5
+  --> $DIR/issue-52669.rs:13:5
    |
 LL | fn bar(mut a: A) -> B {
    |        ----- move occurs because `a` has type `A`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/issue-52742.nll.stderr b/src/test/ui/nll/issue-52742.nll.stderr
new file mode 100644
index 00000000000..e8b7b3333eb
--- /dev/null
+++ b/src/test/ui/nll/issue-52742.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52742.rs:14:9
+   |
+LL |     fn take_bar(&mut self, b: Bar<'_>) {
+   |                 ---------         -- let's call this `'1`
+   |                 |
+   |                 has type `&mut Foo<'_, '2>`
+LL |         self.y = b.z
+   |         ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-52742.rs b/src/test/ui/nll/issue-52742.rs
index 150e67fe094..db9ddfff285 100644
--- a/src/test/ui/nll/issue-52742.rs
+++ b/src/test/ui/nll/issue-52742.rs
@@ -1,4 +1,3 @@
-#![feature(nll)]
 #![feature(in_band_lifetimes)]
 
 struct Foo<'a, 'b> {
@@ -13,7 +12,7 @@ struct Bar<'b> {
 impl Foo<'_, '_> {
     fn take_bar(&mut self, b: Bar<'_>) {
         self.y = b.z
-        //~^ ERROR lifetime may not live long enough
+        //~^ ERROR
     }
 }
 
diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr
index 6b25296c4bd..b9829158002 100644
--- a/src/test/ui/nll/issue-52742.stderr
+++ b/src/test/ui/nll/issue-52742.stderr
@@ -1,12 +1,22 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-52742.rs:15:9
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/issue-52742.rs:14:18
    |
-LL |     fn take_bar(&mut self, b: Bar<'_>) {
-   |                 ---------         -- let's call this `'1`
-   |                 |
-   |                 has type `&mut Foo<'_, '2>`
 LL |         self.y = b.z
-   |         ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |                  ^^^
+   |
+note: ...the reference is valid for the lifetime '_ as defined on the impl at 12:10...
+  --> $DIR/issue-52742.rs:12:10
+   |
+LL | impl Foo<'_, '_> {
+   |          ^^
+note: ...but the borrowed content is only valid for the anonymous lifetime #2 defined on the method body at 13:5
+  --> $DIR/issue-52742.rs:13:5
+   |
+LL | /     fn take_bar(&mut self, b: Bar<'_>) {
+LL | |         self.y = b.z
+LL | |
+LL | |     }
+   | |_____^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-53119.rs b/src/test/ui/nll/issue-53119.rs
index 97e05c8810d..7a47a77f6bb 100644
--- a/src/test/ui/nll/issue-53119.rs
+++ b/src/test/ui/nll/issue-53119.rs
@@ -1,7 +1,5 @@
 // compile-pass
 
-#![feature(nll)]
-
 use std::ops::Deref;
 
 pub struct TypeFieldIterator<'a, T: 'a> {
diff --git a/src/test/ui/nll/issue-53570.rs b/src/test/ui/nll/issue-53570.rs
index d0baffa2702..cea458dcb65 100644
--- a/src/test/ui/nll/issue-53570.rs
+++ b/src/test/ui/nll/issue-53570.rs
@@ -8,10 +8,6 @@
 //
 // compile-pass
 
-#![feature(nll)]
-#![feature(rustc_attrs)]
-#![allow(dead_code)]
-
 use std::cell::{RefCell, Ref};
 
 trait AnyVec<'a> {
diff --git a/src/test/ui/nll/issue-55288.rs b/src/test/ui/nll/issue-55288.rs
index 9b3eb7f05de..c7b6ac59248 100644
--- a/src/test/ui/nll/issue-55288.rs
+++ b/src/test/ui/nll/issue-55288.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // run-pass
 
 struct Slice(&'static [&'static [u8]]);
diff --git a/src/test/ui/nll/issue-55344.rs b/src/test/ui/nll/issue-55344.rs
index b900acfa159..521d4d33d86 100644
--- a/src/test/ui/nll/issue-55344.rs
+++ b/src/test/ui/nll/issue-55344.rs
@@ -1,7 +1,5 @@
 // compile-pass
 
-#![feature(nll)]
-#![allow(unreachable_code)]
 #![deny(unused_mut)]
 
 pub fn foo() {
diff --git a/src/test/ui/nll/issue-55394.nll.stderr b/src/test/ui/nll/issue-55394.nll.stderr
new file mode 100644
index 00000000000..d0723047ac0
--- /dev/null
+++ b/src/test/ui/nll/issue-55394.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-55394.rs:9:9
+   |
+LL |     fn new(bar: &mut Bar) -> Self {
+   |                 -            ---- return type is Foo<'2>
+   |                 |
+   |                 let's call the lifetime of this reference `'1`
+LL |         Foo { bar }
+   |         ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-55394.rs b/src/test/ui/nll/issue-55394.rs
index deb1034525e..f813d1c915c 100644
--- a/src/test/ui/nll/issue-55394.rs
+++ b/src/test/ui/nll/issue-55394.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Bar;
 
 struct Foo<'s> {
@@ -8,7 +6,7 @@ struct Foo<'s> {
 
 impl Foo<'_> {
     fn new(bar: &mut Bar) -> Self {
-        Foo { bar } //~ERROR lifetime may not live long enough
+        Foo { bar } //~ERROR
     }
 }
 
diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr
index e9a70fd6b16..ffb94ed7dd7 100644
--- a/src/test/ui/nll/issue-55394.stderr
+++ b/src/test/ui/nll/issue-55394.stderr
@@ -1,12 +1,29 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-55394.rs:11:9
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'s` due to conflicting requirements
+  --> $DIR/issue-55394.rs:9:9
    |
-LL |     fn new(bar: &mut Bar) -> Self {
-   |                 -            ---- return type is Foo<'2>
-   |                 |
-   |                 let's call the lifetime of this reference `'1`
 LL |         Foo { bar }
-   |         ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |         ^^^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
+  --> $DIR/issue-55394.rs:8:5
+   |
+LL | /     fn new(bar: &mut Bar) -> Self {
+LL | |         Foo { bar }
+LL | |     }
+   | |_____^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/issue-55394.rs:9:15
+   |
+LL |         Foo { bar }
+   |               ^^^
+note: but, the lifetime must be valid for the lifetime '_ as defined on the impl at 7:10...
+  --> $DIR/issue-55394.rs:7:10
+   |
+LL | impl Foo<'_> {
+   |          ^^
+   = note: ...so that the expression is assignable:
+           expected Foo<'_>
+              found Foo<'_>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55401.nll.stderr b/src/test/ui/nll/issue-55401.nll.stderr
new file mode 100644
index 00000000000..4f797f26a1a
--- /dev/null
+++ b/src/test/ui/nll/issue-55401.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-55401.rs:3:5
+   |
+LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+   |                                               -- lifetime `'a` defined here
+LL |     let (ref y, _z): (&'a u32, u32) = (&22, 44);
+LL |     *y
+   |     ^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-55401.rs b/src/test/ui/nll/issue-55401.rs
index 2fa23449108..fc45824e903 100644
--- a/src/test/ui/nll/issue-55401.rs
+++ b/src/test/ui/nll/issue-55401.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
     let (ref y, _z): (&'a u32, u32) = (&22, 44);
     *y //~ ERROR
diff --git a/src/test/ui/nll/issue-55401.stderr b/src/test/ui/nll/issue-55401.stderr
index 622bc5a3f34..50debc6386f 100644
--- a/src/test/ui/nll/issue-55401.stderr
+++ b/src/test/ui/nll/issue-55401.stderr
@@ -1,11 +1,15 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-55401.rs:5:5
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/issue-55401.rs:3:5
    |
-LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
-   |                                               -- lifetime `'a` defined here
-LL |     let (ref y, _z): (&'a u32, u32) = (&22, 44);
 LL |     *y
-   |     ^^ returning this value requires that `'a` must outlive `'static`
+   |     ^^
+   |
+   = note: ...the reference is valid for the static lifetime...
+note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 1:47
+  --> $DIR/issue-55401.rs:1:47
+   |
+LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+   |                                               ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-55850.rs b/src/test/ui/nll/issue-55850.rs
index 8a016bf8779..a8f7299f899 100644
--- a/src/test/ui/nll/issue-55850.rs
+++ b/src/test/ui/nll/issue-55850.rs
@@ -25,7 +25,7 @@ where
 fn bug<'a>() -> impl Iterator<Item = &'a str> {
     GenIter(move || {
         let mut s = String::new();
-        yield &s[..] //~ ERROR `s` does not live long enough [E0597]
+        yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515]
         //~| ERROR borrow may still be in use when generator yields
     })
 }
diff --git a/src/test/ui/nll/issue-55850.stderr b/src/test/ui/nll/issue-55850.stderr
index 66c2995efc8..86a8cdc42ff 100644
--- a/src/test/ui/nll/issue-55850.stderr
+++ b/src/test/ui/nll/issue-55850.stderr
@@ -1,11 +1,11 @@
-error[E0597]: `s` does not live long enough
-  --> $DIR/issue-55850.rs:28:16
+error[E0515]: cannot yield value referencing local variable `s`
+  --> $DIR/issue-55850.rs:28:9
    |
 LL |         yield &s[..]
-   |                ^ borrowed value does not live long enough
-LL |
-LL |     })
-   |     - `s` dropped here while still borrowed
+   |         ^^^^^^^-^^^^
+   |         |      |
+   |         |      `s` is borrowed here
+   |         yields a value referencing data owned by the current function
 
 error[E0626]: borrow may still be in use when generator yields
   --> $DIR/issue-55850.rs:28:16
@@ -15,5 +15,5 @@ LL |         yield &s[..]
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0597, E0626.
-For more information about an error, try `rustc --explain E0597`.
+Some errors have detailed explanations: E0515, E0626.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.rs b/src/test/ui/nll/issue-57265-return-type-wf-check.rs
index 24c61a4926f..8fb8351cee2 100644
--- a/src/test/ui/nll/issue-57265-return-type-wf-check.rs
+++ b/src/test/ui/nll/issue-57265-return-type-wf-check.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 use std::any::Any;
 
 #[derive(Debug, Clone)]
diff --git a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr
index db01212597f..20add62b91d 100644
--- a/src/test/ui/nll/issue-57265-return-type-wf-check.stderr
+++ b/src/test/ui/nll/issue-57265-return-type-wf-check.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/issue-57265-return-type-wf-check.rs:22:23
+  --> $DIR/issue-57265-return-type-wf-check.rs:20:23
    |
 LL |     let (_, z) = foo(&"hello".to_string());
    |                  -----^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
diff --git a/src/test/ui/nll/issue-57280-1.rs b/src/test/ui/nll/issue-57280-1.rs
index 356c477f1ba..e02d6a0cb5a 100644
--- a/src/test/ui/nll/issue-57280-1.rs
+++ b/src/test/ui/nll/issue-57280-1.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // compile-pass
 
 trait Foo<'a> {
diff --git a/src/test/ui/nll/issue-57280.rs b/src/test/ui/nll/issue-57280.rs
index 4fe6a96f5dc..776a0d359cd 100644
--- a/src/test/ui/nll/issue-57280.rs
+++ b/src/test/ui/nll/issue-57280.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // compile-pass
 
 trait Foo {
diff --git a/src/test/ui/nll/issue-57989.rs b/src/test/ui/nll/issue-57989.rs
index 4f21cca97cc..c410f0b0bfb 100644
--- a/src/test/ui/nll/issue-57989.rs
+++ b/src/test/ui/nll/issue-57989.rs
@@ -1,7 +1,5 @@
 // Test for ICE from issue 57989
 
-#![feature(nll)]
-
 fn f(x: &i32) {
     let g = &x;
     *x = 0;     //~ ERROR cannot assign to `*x` which is behind a `&` reference
diff --git a/src/test/ui/nll/issue-57989.stderr b/src/test/ui/nll/issue-57989.stderr
index 7367dc095a3..00a9bab4868 100644
--- a/src/test/ui/nll/issue-57989.stderr
+++ b/src/test/ui/nll/issue-57989.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `*x` which is behind a `&` reference
-  --> $DIR/issue-57989.rs:7:5
+  --> $DIR/issue-57989.rs:5:5
    |
 LL | fn f(x: &i32) {
    |         ---- help: consider changing this to be a mutable reference: `&mut i32`
@@ -8,7 +8,7 @@ LL |     *x = 0;
    |     ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written
 
 error[E0506]: cannot assign to `*x` because it is borrowed
-  --> $DIR/issue-57989.rs:7:5
+  --> $DIR/issue-57989.rs:5:5
    |
 LL |     let g = &x;
    |             -- borrow of `*x` occurs here
diff --git a/src/test/ui/nll/issue-58053.rs b/src/test/ui/nll/issue-58053.rs
index d4338905ed2..0992e3a85ae 100644
--- a/src/test/ui/nll/issue-58053.rs
+++ b/src/test/ui/nll/issue-58053.rs
@@ -1,4 +1,3 @@
-#![allow(warnings)]
 #![feature(nll)]
 
 fn main() {
diff --git a/src/test/ui/nll/issue-58053.stderr b/src/test/ui/nll/issue-58053.stderr
index 9048983318b..297681ff403 100644
--- a/src/test/ui/nll/issue-58053.stderr
+++ b/src/test/ui/nll/issue-58053.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-58053.rs:7:33
+  --> $DIR/issue-58053.rs:6:33
    |
 LL |     let f = |x: &i32| -> &i32 { x };
    |                 -        ----   ^ returning this value requires that `'1` must outlive `'2`
@@ -8,7 +8,7 @@ LL |     let f = |x: &i32| -> &i32 { x };
    |                 let's call the lifetime of this reference `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-58053.rs:11:25
+  --> $DIR/issue-58053.rs:10:25
    |
 LL |     let g = |x: &i32| { x };
    |                 -   -   ^ returning this value requires that `'1` must outlive `'2`
diff --git a/src/test/ui/nll/issue-58299.rs b/src/test/ui/nll/issue-58299.rs
index 9267cac5dd3..3277a9db8ec 100644
--- a/src/test/ui/nll/issue-58299.rs
+++ b/src/test/ui/nll/issue-58299.rs
@@ -1,4 +1,3 @@
-#![allow(dead_code)]
 #![feature(nll)]
 
 struct A<'a>(&'a ());
diff --git a/src/test/ui/nll/issue-58299.stderr b/src/test/ui/nll/issue-58299.stderr
index 0c69b70a97c..aba07542d02 100644
--- a/src/test/ui/nll/issue-58299.stderr
+++ b/src/test/ui/nll/issue-58299.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-58299.rs:17:9
+  --> $DIR/issue-58299.rs:16:9
    |
 LL | fn foo<'a>(x: i32) {
    |        -- lifetime `'a` defined here
@@ -8,7 +8,7 @@ LL |         A::<'a>::X..=A::<'static>::X => (),
    |         ^^^^^^^^^^ requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-58299.rs:25:27
+  --> $DIR/issue-58299.rs:24:27
    |
 LL | fn bar<'a>(x: i32) {
    |        -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
index 5b609820a23..1de32ddf531 100644
--- a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
+++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.rs
@@ -1,6 +1,3 @@
-#![allow(warnings)]
-#![feature(nll)]
-
 struct Wrap<'p> { p: &'p mut i32 }
 
 impl<'p> Drop for Wrap<'p> {
diff --git a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
index e7755bdb89c..80e29780746 100644
--- a/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
+++ b/src/test/ui/nll/maybe-initialized-drop-implicit-fragment-drop.stderr
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:20:5
+  --> $DIR/maybe-initialized-drop-implicit-fragment-drop.rs:17:5
    |
 LL |     let wrap = Wrap { p: &mut x };
    |                          ------ borrow of `x` occurs here
diff --git a/src/test/ui/nll/move-errors.rs b/src/test/ui/nll/move-errors.rs
index a3416373709..e0fcd625032 100644
--- a/src/test/ui/nll/move-errors.rs
+++ b/src/test/ui/nll/move-errors.rs
@@ -1,6 +1,3 @@
-#![allow(unused)]
-#![feature(nll)]
-
 struct A(String);
 struct C(D);
 
diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr
index bb30da034af..a4af11e3d40 100644
--- a/src/test/ui/nll/move-errors.stderr
+++ b/src/test/ui/nll/move-errors.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/move-errors.rs:9:13
+  --> $DIR/move-errors.rs:6:13
    |
 LL |     let b = *a;
    |             ^^
@@ -8,7 +8,7 @@ LL |     let b = *a;
    |             help: consider removing the `*`: `a`
 
 error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
-  --> $DIR/move-errors.rs:15:13
+  --> $DIR/move-errors.rs:12:13
    |
 LL |     let b = a[0];
    |             ^^^^
@@ -17,7 +17,7 @@ LL |     let b = a[0];
    |             help: consider borrowing here: `&a[0]`
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/move-errors.rs:22:13
+  --> $DIR/move-errors.rs:19:13
    |
 LL |     let s = **r;
    |             ^^^
@@ -26,7 +26,7 @@ LL |     let s = **r;
    |             help: consider removing the `*`: `*r`
 
 error[E0507]: cannot move out of an `Rc`
-  --> $DIR/move-errors.rs:30:13
+  --> $DIR/move-errors.rs:27:13
    |
 LL |     let s = *r;
    |             ^^
@@ -35,7 +35,7 @@ LL |     let s = *r;
    |             help: consider removing the `*`: `r`
 
 error[E0508]: cannot move out of type `[A; 1]`, a non-copy array
-  --> $DIR/move-errors.rs:35:13
+  --> $DIR/move-errors.rs:32:13
    |
 LL |     let a = [A("".to_string())][0];
    |             ^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     let a = [A("".to_string())][0];
    |             help: consider borrowing here: `&[A("".to_string())][0]`
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/move-errors.rs:41:16
+  --> $DIR/move-errors.rs:38:16
    |
 LL |     let A(s) = *a;
    |           -    ^^
@@ -54,13 +54,13 @@ LL |     let A(s) = *a;
    |           data moved here
    |
 note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
-  --> $DIR/move-errors.rs:41:11
+  --> $DIR/move-errors.rs:38:11
    |
 LL |     let A(s) = *a;
    |           ^
 
 error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
-  --> $DIR/move-errors.rs:47:19
+  --> $DIR/move-errors.rs:44:19
    |
 LL |     let C(D(s)) = c;
    |             -     ^ cannot move out of here
@@ -68,19 +68,19 @@ LL |     let C(D(s)) = c;
    |             data moved here
    |
 note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
-  --> $DIR/move-errors.rs:47:13
+  --> $DIR/move-errors.rs:44:13
    |
 LL |     let C(D(s)) = c;
    |             ^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/move-errors.rs:54:9
+  --> $DIR/move-errors.rs:51:9
    |
 LL |     b = *a;
    |         ^^ cannot move out of borrowed content
 
 error[E0508]: cannot move out of type `[B; 1]`, a non-copy array
-  --> $DIR/move-errors.rs:77:11
+  --> $DIR/move-errors.rs:74:11
    |
 LL |     match x[0] {
    |           ^^^^
@@ -94,7 +94,7 @@ LL |         B::V(s) => (),
    |              - ...and here
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/move-errors.rs:79:14
+  --> $DIR/move-errors.rs:76:14
    |
 LL |         B::U(d) => (),
    |              ^
@@ -102,7 +102,7 @@ LL |         B::V(s) => (),
    |              ^
 
 error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
-  --> $DIR/move-errors.rs:86:11
+  --> $DIR/move-errors.rs:83:11
    |
 LL |     match x {
    |           ^ cannot move out of here
@@ -111,13 +111,13 @@ LL |         B::U(D(s)) => (),
    |                - data moved here
    |
 note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
-  --> $DIR/move-errors.rs:89:16
+  --> $DIR/move-errors.rs:86:16
    |
 LL |         B::U(D(s)) => (),
    |                ^
 
 error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
-  --> $DIR/move-errors.rs:95:11
+  --> $DIR/move-errors.rs:92:11
    |
 LL |     match x {
    |           ^ cannot move out of here
@@ -126,13 +126,13 @@ LL |         (D(s), &t) => (),
    |            - data moved here
    |
 note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
-  --> $DIR/move-errors.rs:98:12
+  --> $DIR/move-errors.rs:95:12
    |
 LL |         (D(s), &t) => (),
    |            ^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/move-errors.rs:95:11
+  --> $DIR/move-errors.rs:92:11
    |
 LL |     match x {
    |           ^ cannot move out of borrowed content
@@ -141,13 +141,13 @@ LL |         (D(s), &t) => (),
    |                 - data moved here
    |
 note: move occurs because `t` has type `std::string::String`, which does not implement the `Copy` trait
-  --> $DIR/move-errors.rs:98:17
+  --> $DIR/move-errors.rs:95:17
    |
 LL |         (D(s), &t) => (),
    |                 ^
 
 error[E0509]: cannot move out of type `F`, which implements the `Drop` trait
-  --> $DIR/move-errors.rs:105:11
+  --> $DIR/move-errors.rs:102:11
    |
 LL |     match x {
    |           ^ cannot move out of here
@@ -158,13 +158,13 @@ LL |         F(s, mut t) => (),
    |           data moved here
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/move-errors.rs:107:11
+  --> $DIR/move-errors.rs:104:11
    |
 LL |         F(s, mut t) => (),
    |           ^  ^^^^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/move-errors.rs:113:11
+  --> $DIR/move-errors.rs:110:11
    |
 LL |     match *x {
    |           ^^
@@ -176,7 +176,7 @@ LL |         Ok(s) | Err(s) => (),
    |            - data moved here
    |
 note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
-  --> $DIR/move-errors.rs:115:12
+  --> $DIR/move-errors.rs:112:12
    |
 LL |         Ok(s) | Err(s) => (),
    |            ^
diff --git a/src/test/ui/nll/move-subpaths-moves-root.rs b/src/test/ui/nll/move-subpaths-moves-root.rs
index 72a36ef22df..e7caf89e783 100644
--- a/src/test/ui/nll/move-subpaths-moves-root.rs
+++ b/src/test/ui/nll/move-subpaths-moves-root.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn main() {
     let x = (vec![1, 2, 3], );
     drop(x.0);
diff --git a/src/test/ui/nll/move-subpaths-moves-root.stderr b/src/test/ui/nll/move-subpaths-moves-root.stderr
index bdbc25e9ee3..7030d5b3305 100644
--- a/src/test/ui/nll/move-subpaths-moves-root.stderr
+++ b/src/test/ui/nll/move-subpaths-moves-root.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/move-subpaths-moves-root.rs:6:10
+  --> $DIR/move-subpaths-moves-root.rs:4:10
    |
 LL |     drop(x.0);
    |          --- value moved here
diff --git a/src/test/ui/nll/normalization-bounds-error.rs b/src/test/ui/nll/normalization-bounds-error.rs
index d6610e15823..b6cfcd98732 100644
--- a/src/test/ui/nll/normalization-bounds-error.rs
+++ b/src/test/ui/nll/normalization-bounds-error.rs
@@ -1,7 +1,6 @@
 // Check that we error when a bound from the impl is not satisfied when
 // normalizing an associated type.
 
-#![feature(nll)]
 trait Visitor<'d> {
     type Value;
 }
diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr
index 8ee00168661..951e73e7fd7 100644
--- a/src/test/ui/nll/normalization-bounds-error.stderr
+++ b/src/test/ui/nll/normalization-bounds-error.stderr
@@ -1,16 +1,16 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
-  --> $DIR/normalization-bounds-error.rs:13:1
+  --> $DIR/normalization-bounds-error.rs:12:1
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime 'd as defined on the function body at 13:14...
-  --> $DIR/normalization-bounds-error.rs:13:14
+note: first, the lifetime cannot outlive the lifetime 'd as defined on the function body at 12:14...
+  --> $DIR/normalization-bounds-error.rs:12:14
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    |              ^^
-note: ...but the lifetime must also be valid for the lifetime 'a as defined on the function body at 13:18...
-  --> $DIR/normalization-bounds-error.rs:13:18
+note: ...but the lifetime must also be valid for the lifetime 'a as defined on the function body at 12:18...
+  --> $DIR/normalization-bounds-error.rs:12:18
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    |                  ^^
diff --git a/src/test/ui/nll/normalization-bounds.rs b/src/test/ui/nll/normalization-bounds.rs
index ebc19d7cc83..5d2825ef2d6 100644
--- a/src/test/ui/nll/normalization-bounds.rs
+++ b/src/test/ui/nll/normalization-bounds.rs
@@ -2,7 +2,6 @@
 
 //run-pass
 
-#![feature(nll)]
 trait Visitor<'d> {
     type Value;
 }
diff --git a/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs b/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
index 061d0d69d09..6d5bdfa4da2 100644
--- a/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
+++ b/src/test/ui/nll/promotable-mutable-zst-doesnt-conflict.rs
@@ -3,8 +3,6 @@
 
 // run-pass
 
-#![feature(nll)]
-
 pub fn main() {
     let mut x: Vec<&[i32; 0]> = Vec::new();
     for i in 0..10 {
diff --git a/src/test/ui/nll/promoted-bounds.rs b/src/test/ui/nll/promoted-bounds.rs
index 59b21cf9ac2..5f95ae13c58 100644
--- a/src/test/ui/nll/promoted-bounds.rs
+++ b/src/test/ui/nll/promoted-bounds.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 fn shorten_lifetime<'a, 'b, 'min>(a: &'a i32, b: &'b i32) -> &'min i32
 where
     'a: 'min,
diff --git a/src/test/ui/nll/promoted-bounds.stderr b/src/test/ui/nll/promoted-bounds.stderr
index de185cc0d29..df347f4e7f0 100644
--- a/src/test/ui/nll/promoted-bounds.stderr
+++ b/src/test/ui/nll/promoted-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `l` does not live long enough
-  --> $DIR/promoted-bounds.rs:21:17
+  --> $DIR/promoted-bounds.rs:19:17
    |
 LL |     let ptr = {
    |         --- borrow later stored here
diff --git a/src/test/ui/nll/promoted-closure-pair.rs b/src/test/ui/nll/promoted-closure-pair.rs
index 7b3bbad4c1e..cc9f17fd4e6 100644
--- a/src/test/ui/nll/promoted-closure-pair.rs
+++ b/src/test/ui/nll/promoted-closure-pair.rs
@@ -1,7 +1,5 @@
 // Check that we handle multiple closures in the same promoted constant.
 
-#![feature(nll)]
-
 fn foo() -> &'static i32 {
     let z = 0;
     let p = &(|y| y, |y| y);
diff --git a/src/test/ui/nll/promoted-closure-pair.stderr b/src/test/ui/nll/promoted-closure-pair.stderr
index b04d1a9ccba..000bdf85804 100644
--- a/src/test/ui/nll/promoted-closure-pair.stderr
+++ b/src/test/ui/nll/promoted-closure-pair.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing local variable `z`
-  --> $DIR/promoted-closure-pair.rs:9:5
+  --> $DIR/promoted-closure-pair.rs:7:5
    |
 LL |     p.1(&z)
    |     ^^^^--^
diff --git a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr
new file mode 100644
index 00000000000..322930984a5
--- /dev/null
+++ b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable
+  --> $DIR/region-ends-after-if-condition.rs:26:9
+   |
+LL |     let value = &my_struct.field;
+   |                 ---------------- immutable borrow occurs here
+LL |     if value.is_empty() {
+LL |         my_struct.field.push_str("Hello, world!");
+   |         ^^^^^^^^^^^^^^^ mutable borrow occurs here
+...
+LL |     drop(value);
+   |          ----- immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/nll/relate_tys/issue-48071.rs b/src/test/ui/nll/relate_tys/issue-48071.rs
index 9b8ac167466..72987629848 100644
--- a/src/test/ui/nll/relate_tys/issue-48071.rs
+++ b/src/test/ui/nll/relate_tys/issue-48071.rs
@@ -6,10 +6,6 @@
 //
 // compile-pass
 
-#![allow(warnings)]
-#![feature(dyn_trait)]
-#![feature(nll)]
-
 trait Foo {
     fn foo(&self) { }
 }
diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.rs b/src/test/ui/nll/relate_tys/var-appears-twice.rs
index 2f227c87259..77129f4468f 100644
--- a/src/test/ui/nll/relate_tys/var-appears-twice.rs
+++ b/src/test/ui/nll/relate_tys/var-appears-twice.rs
@@ -2,9 +2,6 @@
 // function returning always its first argument can be upcast to one
 // that returns either first or second argument.
 
-#![feature(nll)]
-#![allow(warnings)]
-
 use std::cell::Cell;
 
 type DoubleCell<A> = Cell<(A, A)>;
diff --git a/src/test/ui/nll/relate_tys/var-appears-twice.stderr b/src/test/ui/nll/relate_tys/var-appears-twice.stderr
index 7c078d226dc..d032ce6f213 100644
--- a/src/test/ui/nll/relate_tys/var-appears-twice.stderr
+++ b/src/test/ui/nll/relate_tys/var-appears-twice.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `b` does not live long enough
-  --> $DIR/var-appears-twice.rs:23:38
+  --> $DIR/var-appears-twice.rs:20:38
    |
 LL |     let x: DoubleCell<_> = make_cell(&b);
    |            -------------             ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.rs b/src/test/ui/nll/return-ref-mut-issue-46557.rs
index b535ab1f5e1..dca61d39dfe 100644
--- a/src/test/ui/nll/return-ref-mut-issue-46557.rs
+++ b/src/test/ui/nll/return-ref-mut-issue-46557.rs
@@ -1,8 +1,5 @@
 // Regression test for issue #46557
 
-#![feature(nll)]
-#![allow(dead_code)]
-
 fn gimme_static_mut() -> &'static mut u32 {
     let ref mut x = 1234543;
     x //~ ERROR cannot return value referencing temporary value [E0515]
diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.stderr
index cc201136ff2..720440a0ae5 100644
--- a/src/test/ui/nll/return-ref-mut-issue-46557.stderr
+++ b/src/test/ui/nll/return-ref-mut-issue-46557.stderr
@@ -1,5 +1,5 @@
 error[E0515]: cannot return value referencing temporary value
-  --> $DIR/return-ref-mut-issue-46557.rs:8:5
+  --> $DIR/return-ref-mut-issue-46557.rs:5:5
    |
 LL |     let ref mut x = 1234543;
    |                     ------- temporary value created here
diff --git a/src/test/ui/nll/ty-outlives/issue-53789-1.rs b/src/test/ui/nll/ty-outlives/issue-53789-1.rs
index 586f076c8ca..dc67c1a68aa 100644
--- a/src/test/ui/nll/ty-outlives/issue-53789-1.rs
+++ b/src/test/ui/nll/ty-outlives/issue-53789-1.rs
@@ -2,9 +2,6 @@
 //
 // compile-pass
 
-#![feature(nll)]
-#![allow(unused_variables)]
-
 use std::collections::BTreeMap;
 
 trait ValueTree {
diff --git a/src/test/ui/nll/ty-outlives/issue-53789-2.rs b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
index de8b05aeed7..1b80be2eaff 100644
--- a/src/test/ui/nll/ty-outlives/issue-53789-2.rs
+++ b/src/test/ui/nll/ty-outlives/issue-53789-2.rs
@@ -2,9 +2,6 @@
 //
 // compile-pass
 
-#![feature(nll)]
-#![allow(unused_variables)]
-
 use std::collections::BTreeMap;
 use std::ops::Range;
 use std::cmp::Ord;
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr
new file mode 100644
index 00000000000..3a84cbfbedc
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.nll.stderr
@@ -0,0 +1,11 @@
+error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+  --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5
+   |
+LL |     bar::<T::Output>()
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
index 9c2cbfd4a45..dce88b88c75 100644
--- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // Test that we are able to establish that `<T as
 // MyTrait<'a>>::Output` outlives `'b` here. We need to prove however
 // that `<T as MyTrait<'a>>::Output` outlives `'a`, so we also have to
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
index 1aed0a545b4..1a5a3719fd8 100644
--- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
@@ -1,10 +1,15 @@
-error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
-  --> $DIR/projection-where-clause-env-wrong-bound.rs:17:5
+error[E0309]: the associated type `<T as MyTrait<'a>>::Output` may not live long enough
+  --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5
    |
 LL |     bar::<T::Output>()
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+   = help: consider adding an explicit lifetime bound `<T as MyTrait<'a>>::Output: 'a`...
+note: ...so that the type `<T as MyTrait<'a>>::Output` will meet its required lifetime bounds
+  --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5
+   |
+LL |     bar::<T::Output>()
+   |     ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr
new file mode 100644
index 00000000000..58bfb600452
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.nll.stderr
@@ -0,0 +1,11 @@
+error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long enough
+  --> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5
+   |
+LL |     bar::<<T as MyTrait<'a>>::Output>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs b/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
index c6935badf54..73147666111 100644
--- a/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // Test that when we have a `<T as MyTrait<'a>>::Output: 'a`
 // relationship in the environment we take advantage of it.  In this
 // case, that means we **don't** have to prove that `T: 'a`.
diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs
deleted file mode 100644
index ec559437570..00000000000
--- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Test that we assume that universal types like `T` outlive the
-// function body. Same as ty-param-fn-body, but uses `feature(nll)`,
-// which affects error reporting.
-
-#![feature(nll)]
-
-#![allow(warnings)]
-
-use std::cell::Cell;
-
-// No errors here, because `'a` is local to the body.
-fn region_within_body<T>(t: T) {
-    let some_int = 22;
-    let cell = Cell::new(&some_int);
-    outlives(cell, t)
-}
-
-// Error here, because T: 'a is not satisfied.
-fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
-    outlives(cell, t)
-    //~^ ERROR the parameter type `T` may not live long enough
-}
-
-fn outlives<'a, T>(x: Cell<&'a usize>, y: T)
-where
-    T: 'a,
-{
-}
-
-fn main() {}
diff --git a/src/test/ui/nll/type-alias-free-regions.nll.stderr b/src/test/ui/nll/type-alias-free-regions.nll.stderr
new file mode 100644
index 00000000000..235bf4167d5
--- /dev/null
+++ b/src/test/ui/nll/type-alias-free-regions.nll.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+  --> $DIR/type-alias-free-regions.rs:17:9
+   |
+LL | impl<'a> FromBox<'a> for C<'a> {
+   |      -- lifetime `'a` defined here
+LL |     fn from_box(b: Box<B>) -> Self {
+   |                 - has type `std::boxed::Box<std::boxed::Box<&'1 isize>>`
+LL |         C { f: b }
+   |         ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/type-alias-free-regions.rs:27:9
+   |
+LL | impl<'a> FromTuple<'a> for C<'a> {
+   |      -- lifetime `'a` defined here
+LL |     fn from_tuple(b: (B,)) -> Self {
+   |                   - has type `(std::boxed::Box<&'1 isize>,)`
+LL |         C { f: Box::new(b.0) }
+   |         ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/nll/type-alias-free-regions.rs b/src/test/ui/nll/type-alias-free-regions.rs
index ebe6b9d2073..fd5566f35d5 100644
--- a/src/test/ui/nll/type-alias-free-regions.rs
+++ b/src/test/ui/nll/type-alias-free-regions.rs
@@ -1,8 +1,6 @@
 // Test that we don't assume that type aliases have the same type parameters
 // as the type they alias and then panic when we see this.
 
-#![feature(nll)]
-
 type A<'a> = &'a isize;
 type B<'a> = Box<A<'a>>;
 
diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr
index 4facc2d0da0..00d58d34362 100644
--- a/src/test/ui/nll/type-alias-free-regions.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.stderr
@@ -1,22 +1,52 @@
-error: lifetime may not live long enough
-  --> $DIR/type-alias-free-regions.rs:19:9
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/type-alias-free-regions.rs:17:9
    |
-LL | impl<'a> FromBox<'a> for C<'a> {
-   |      -- lifetime `'a` defined here
-LL |     fn from_box(b: Box<B>) -> Self {
-   |                 - has type `std::boxed::Box<std::boxed::Box<&'1 isize>>`
 LL |         C { f: b }
-   |         ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`
+   |         ^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 16:5...
+  --> $DIR/type-alias-free-regions.rs:16:5
+   |
+LL | /     fn from_box(b: Box<B>) -> Self {
+LL | |         C { f: b }
+LL | |     }
+   | |_____^
+   = note: ...so that the expression is assignable:
+           expected std::boxed::Box<std::boxed::Box<&isize>>
+              found std::boxed::Box<std::boxed::Box<&isize>>
+note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 15:6...
+  --> $DIR/type-alias-free-regions.rs:15:6
+   |
+LL | impl<'a> FromBox<'a> for C<'a> {
+   |      ^^
+   = note: ...so that the expression is assignable:
+           expected C<'a>
+              found C<'_>
 
-error: lifetime may not live long enough
-  --> $DIR/type-alias-free-regions.rs:29:9
+error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+  --> $DIR/type-alias-free-regions.rs:27:16
    |
-LL | impl<'a> FromTuple<'a> for C<'a> {
-   |      -- lifetime `'a` defined here
-LL |     fn from_tuple(b: (B,)) -> Self {
-   |                   - has type `(std::boxed::Box<&'1 isize>,)`
 LL |         C { f: Box::new(b.0) }
-   |         ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`
+   |                ^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 26:5...
+  --> $DIR/type-alias-free-regions.rs:26:5
+   |
+LL | /     fn from_tuple(b: (B,)) -> Self {
+LL | |         C { f: Box::new(b.0) }
+LL | |     }
+   | |_____^
+   = note: ...so that the expression is assignable:
+           expected std::boxed::Box<&isize>
+              found std::boxed::Box<&isize>
+note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 25:6...
+  --> $DIR/type-alias-free-regions.rs:25:6
+   |
+LL | impl<'a> FromTuple<'a> for C<'a> {
+   |      ^^
+   = note: ...so that the expression is assignable:
+           expected C<'a>
+              found C<'_>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/unused-mut-issue-50343.rs b/src/test/ui/nll/unused-mut-issue-50343.rs
index 06dbc473557..da0d9229c12 100644
--- a/src/test/ui/nll/unused-mut-issue-50343.rs
+++ b/src/test/ui/nll/unused-mut-issue-50343.rs
@@ -1,4 +1,3 @@
-#![feature(nll)]
 #![deny(unused_mut)]
 
 fn main() {
diff --git a/src/test/ui/nll/unused-mut-issue-50343.stderr b/src/test/ui/nll/unused-mut-issue-50343.stderr
index ef31dd7b29a..261d678db67 100644
--- a/src/test/ui/nll/unused-mut-issue-50343.stderr
+++ b/src/test/ui/nll/unused-mut-issue-50343.stderr
@@ -1,5 +1,5 @@
 error: variable does not need to be mutable
-  --> $DIR/unused-mut-issue-50343.rs:5:33
+  --> $DIR/unused-mut-issue-50343.rs:4:33
    |
 LL |     vec![(42, 22)].iter().map(|(mut x, _y)| ()).count();
    |                                 ----^
@@ -7,7 +7,7 @@ LL |     vec![(42, 22)].iter().map(|(mut x, _y)| ()).count();
    |                                 help: remove this `mut`
    |
 note: lint level defined here
-  --> $DIR/unused-mut-issue-50343.rs:2:9
+  --> $DIR/unused-mut-issue-50343.rs:1:9
    |
 LL | #![deny(unused_mut)]
    |         ^^^^^^^^^^
diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.rs b/src/test/ui/nll/user-annotations/adt-brace-enums.rs
index 842ebae2618..0d9828342d8 100644
--- a/src/test/ui/nll/user-annotations/adt-brace-enums.rs
+++ b/src/test/ui/nll/user-annotations/adt-brace-enums.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 enum SomeEnum<T> {
     SomeVariant { t: T }
 }
diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
index 38f068746a6..e38b77fdcea 100644
--- a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-brace-enums.rs:27:48
+  --> $DIR/adt-brace-enums.rs:25:48
    |
 LL |     SomeEnum::SomeVariant::<&'static u32> { t: &c };
    |                                                ^^
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-brace-enums.rs:32:43
+  --> $DIR/adt-brace-enums.rs:30:43
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-brace-enums.rs:42:47
+  --> $DIR/adt-brace-enums.rs:40:47
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.rs b/src/test/ui/nll/user-annotations/adt-brace-structs.rs
index d7ebbe8eb5f..bdbfd87d584 100644
--- a/src/test/ui/nll/user-annotations/adt-brace-structs.rs
+++ b/src/test/ui/nll/user-annotations/adt-brace-structs.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 struct SomeStruct<T> { t: T }
 
 fn no_annot() {
diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
index 25a9de480b2..3c3003477c2 100644
--- a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
+++ b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-brace-structs.rs:25:37
+  --> $DIR/adt-brace-structs.rs:23:37
    |
 LL |     SomeStruct::<&'static u32> { t: &c };
    |                                     ^^
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-brace-structs.rs:30:32
+  --> $DIR/adt-brace-structs.rs:28:32
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-brace-structs.rs:40:36
+  --> $DIR/adt-brace-structs.rs:38:36
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.rs b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs
index 7a8f55a800b..53853668d19 100644
--- a/src/test/ui/nll/user-annotations/adt-nullary-enums.rs
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs
@@ -1,7 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
 #![allow(warnings)]
 
 use std::cell::Cell;
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
index 1afbac7c4b2..bb703412228 100644
--- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-nullary-enums.rs:34:41
+  --> $DIR/adt-nullary-enums.rs:33:41
    |
 LL |         SomeEnum::SomeVariant(Cell::new(&c)),
    |                               ----------^^-
@@ -11,7 +11,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-nullary-enums.rs:42:41
+  --> $DIR/adt-nullary-enums.rs:41:41
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -26,7 +26,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-nullary-enums.rs:55:45
+  --> $DIR/adt-nullary-enums.rs:54:45
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.rs b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs
index 085596ecc53..efe8dfda191 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-enums.rs
+++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs
@@ -1,7 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
 #![allow(warnings)]
 
 enum SomeEnum<T> {
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
index cd625653ace..810912bf886 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-tuple-enums.rs:29:43
+  --> $DIR/adt-tuple-enums.rs:28:43
    |
 LL |     SomeEnum::SomeVariant::<&'static u32>(&c);
    |                                           ^^
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-tuple-enums.rs:34:38
+  --> $DIR/adt-tuple-enums.rs:33:38
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-tuple-enums.rs:44:42
+  --> $DIR/adt-tuple-enums.rs:43:42
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.rs b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs
index ebbe3cd2c89..37284e1fda8 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-struct.rs
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 struct SomeStruct<T>(T);
 
 fn no_annot() {
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
index 2bb58bb2590..4d2140eca1b 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-tuple-struct.rs:25:32
+  --> $DIR/adt-tuple-struct.rs:23:32
    |
 LL |     SomeStruct::<&'static u32>(&c);
    |                                ^^
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-tuple-struct.rs:30:27
+  --> $DIR/adt-tuple-struct.rs:28:27
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/adt-tuple-struct.rs:40:31
+  --> $DIR/adt-tuple-struct.rs:38:31
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs
index 4756c771f6e..bb6129dacda 100644
--- a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs
+++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs
@@ -1,5 +1,4 @@
 #![allow(warnings)]
-#![feature(nll)]
 
 fn main() {
     let x = 22_u32;
diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
index 0228b56d761..4599d04e7e2 100644
--- a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
+++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/cast_static_lifetime.rs:6:19
+  --> $DIR/cast_static_lifetime.rs:5:19
    |
 LL |     let y: &u32 = (&x) as &'static u32;
    |                   ^^^^----------------
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr
new file mode 100644
index 00000000000..c39301588ac
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/constant-in-expr-inherent-1.rs:8:5
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <Foo<'a>>::C
+   |     ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
index 9f0c60967ef..e3a8a5f58df 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Foo<'a> { x: &'a u32 }
 
 impl<'a> Foo<'a> {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
index 9a28fbd1133..77e1339dc16 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -1,10 +1,23 @@
-error: lifetime may not live long enough
-  --> $DIR/constant-in-expr-inherent-1.rs:10:5
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/constant-in-expr-inherent-1.rs:8:5
+   |
+LL |     <Foo<'a>>::C
+   |     ^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 7:8...
+  --> $DIR/constant-in-expr-inherent-1.rs:7:8
    |
 LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
-   |        -- lifetime `'a` defined here
+   |        ^^
+   = note: ...so that the types are compatible:
+           expected Foo<'_>
+              found Foo<'a>
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/constant-in-expr-inherent-1.rs:8:5
+   |
 LL |     <Foo<'a>>::C
-   |     ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |     ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
index 123be6b3e40..90696d4b17d 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
@@ -1,8 +1,6 @@
 // Test that we still check constants are well-formed, even when we there's no
 // type annotation to check.
 
-#![feature(nll)]
-
 const FUN: fn(&'static ()) = |_| {};
 struct A;
 impl A {
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
index 07e2e1e85cb..12065a85aa4 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/constant-in-expr-inherent-2.rs:25:9
+  --> $DIR/constant-in-expr-inherent-2.rs:23:9
    |
 LL |     FUN(&x);
    |     ----^^-
@@ -11,7 +11,7 @@ LL | }
    | - `x` dropped here while still borrowed
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/constant-in-expr-inherent-2.rs:26:23
+  --> $DIR/constant-in-expr-inherent-2.rs:24:23
    |
 LL |     A::ASSOCIATED_FUN(&x);
    |     ------------------^^-
@@ -23,7 +23,7 @@ LL | }
    | - `x` dropped here while still borrowed
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/constant-in-expr-inherent-2.rs:27:28
+  --> $DIR/constant-in-expr-inherent-2.rs:25:28
    |
 LL |     B::ALSO_ASSOCIATED_FUN(&x);
    |     -----------------------^^-
@@ -35,7 +35,7 @@ LL | }
    | - `x` dropped here while still borrowed
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/constant-in-expr-inherent-2.rs:28:31
+  --> $DIR/constant-in-expr-inherent-2.rs:26:31
    |
 LL |     <_>::TRAIT_ASSOCIATED_FUN(&x);
    |     --------------------------^^-
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr
new file mode 100644
index 00000000000..541a2cfaf29
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/constant-in-expr-normalize.rs:18:5
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <() as Foo<'a>>::C
+   |     ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs
index 4292fc710e9..b7095430d8b 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 trait Mirror {
     type Me;
 }
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
index 5e66a30d7c3..f49d68458be 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
@@ -1,10 +1,15 @@
-error: lifetime may not live long enough
-  --> $DIR/constant-in-expr-normalize.rs:20:5
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/constant-in-expr-normalize.rs:18:5
    |
-LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
-   |        -- lifetime `'a` defined here
 LL |     <() as Foo<'a>>::C
-   |     ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...the reference is valid for the static lifetime...
+note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 17:8
+  --> $DIR/constant-in-expr-normalize.rs:17:8
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr
new file mode 100644
index 00000000000..ea0fcb6d634
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/constant-in-expr-trait-item-1.rs:10:5
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <() as Foo<'a>>::C
+   |     ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
index daa0d7bc241..e0400b2cc02 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 trait Foo<'a> {
     const C: &'a u32;
 }
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
index c96838f259a..451bcf41e42 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
@@ -1,10 +1,15 @@
-error: lifetime may not live long enough
-  --> $DIR/constant-in-expr-trait-item-1.rs:12:5
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/constant-in-expr-trait-item-1.rs:10:5
    |
-LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
-   |        -- lifetime `'a` defined here
 LL |     <() as Foo<'a>>::C
-   |     ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...the reference is valid for the static lifetime...
+note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 9:8
+  --> $DIR/constant-in-expr-trait-item-1.rs:9:8
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr
new file mode 100644
index 00000000000..ff549f1d88b
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/constant-in-expr-trait-item-2.rs:10:5
+   |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <T as Foo<'a>>::C
+   |     ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
index cd66e7a49cb..73c4e577b05 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 trait Foo<'a> {
     const C: &'a u32;
 }
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
index fcc3c40e43f..d129e55e1e6 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
@@ -1,10 +1,15 @@
-error: lifetime may not live long enough
-  --> $DIR/constant-in-expr-trait-item-2.rs:12:5
+error[E0312]: lifetime of reference outlives lifetime of borrowed content...
+  --> $DIR/constant-in-expr-trait-item-2.rs:10:5
    |
-LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
-   |        -- lifetime `'a` defined here
 LL |     <T as Foo<'a>>::C
-   |     ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: ...the reference is valid for the static lifetime...
+note: ...but the borrowed content is only valid for the lifetime 'a as defined on the function body at 9:8
+  --> $DIR/constant-in-expr-trait-item-2.rs:9:8
+   |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+   |        ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr
new file mode 100644
index 00000000000..7f160d8e398
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/constant-in-expr-trait-item-3.rs:10:5
+   |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     T::C
+   |     ^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
index f83ae2438e6..567e31ef936 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 trait Foo<'a> {
     const C: &'a u32;
 }
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
index c91370c810c..77655fe091b 100644
--- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -1,10 +1,23 @@
-error: lifetime may not live long enough
-  --> $DIR/constant-in-expr-trait-item-3.rs:12:5
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/constant-in-expr-trait-item-3.rs:10:5
+   |
+LL |     T::C
+   |     ^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 9:8...
+  --> $DIR/constant-in-expr-trait-item-3.rs:9:8
    |
 LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
-   |        -- lifetime `'a` defined here
+   |        ^^
+   = note: ...so that the types are compatible:
+           expected Foo<'_>
+              found Foo<'a>
+   = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/constant-in-expr-trait-item-3.rs:10:5
+   |
 LL |     T::C
-   |     ^^^^ returning this value requires that `'a` must outlive `'static`
+   |     ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/fns.rs b/src/test/ui/nll/user-annotations/fns.rs
index 1e5e9340bef..38db6d1c4c5 100644
--- a/src/test/ui/nll/user-annotations/fns.rs
+++ b/src/test/ui/nll/user-annotations/fns.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 fn some_fn<T>(arg: T) { }
 
 fn no_annot() {
diff --git a/src/test/ui/nll/user-annotations/fns.stderr b/src/test/ui/nll/user-annotations/fns.stderr
index dadce24159e..e0640da39e2 100644
--- a/src/test/ui/nll/user-annotations/fns.stderr
+++ b/src/test/ui/nll/user-annotations/fns.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/fns.rs:25:29
+  --> $DIR/fns.rs:23:29
    |
 LL |     some_fn::<&'static u32>(&c);
    |     ------------------------^^-
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/fns.rs:30:24
+  --> $DIR/fns.rs:28:24
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/fns.rs:40:28
+  --> $DIR/fns.rs:38:28
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs b/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs
index 0a8a6793dc7..6b9d30f5ab4 100644
--- a/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs
+++ b/src/test/ui/nll/user-annotations/issue-54570-bootstrapping.rs
@@ -1,5 +1,4 @@
 // compile-pass
-#![feature(nll)]
 
 // This test is reduced from a scenario pnkfelix encountered while
 // bootstrapping the compiler.
diff --git a/src/test/ui/nll/user-annotations/issue-55219.rs b/src/test/ui/nll/user-annotations/issue-55219.rs
index 7daa5a59b99..4d18e96cc15 100644
--- a/src/test/ui/nll/user-annotations/issue-55219.rs
+++ b/src/test/ui/nll/user-annotations/issue-55219.rs
@@ -5,8 +5,6 @@
 //
 // run-pass
 
-#![feature(nll)]
-
 pub struct Foo<T>(T);
 
 impl<T> Foo<T> {
diff --git a/src/test/ui/nll/user-annotations/issue-55241.rs b/src/test/ui/nll/user-annotations/issue-55241.rs
index d7686b9dc94..29969c7b4c6 100644
--- a/src/test/ui/nll/user-annotations/issue-55241.rs
+++ b/src/test/ui/nll/user-annotations/issue-55241.rs
@@ -7,8 +7,6 @@
 //
 // run-pass
 
-#![feature(nll)]
-
 pub trait Hasher {
     type Out: Eq;
 }
diff --git a/src/test/ui/nll/user-annotations/method-call.rs b/src/test/ui/nll/user-annotations/method-call.rs
index 59d1513c4c3..beafc597ac1 100644
--- a/src/test/ui/nll/user-annotations/method-call.rs
+++ b/src/test/ui/nll/user-annotations/method-call.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 trait Bazoom<T> {
     fn method<U>(&self, arg: T, arg2: U) { }
 }
diff --git a/src/test/ui/nll/user-annotations/method-call.stderr b/src/test/ui/nll/user-annotations/method-call.stderr
index 7e5314614f3..10447e45a6d 100644
--- a/src/test/ui/nll/user-annotations/method-call.stderr
+++ b/src/test/ui/nll/user-annotations/method-call.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/method-call.rs:38:34
+  --> $DIR/method-call.rs:36:34
    |
 LL |     a.method::<&'static u32>(b,  &c);
    |     -----------------------------^^-
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/method-call.rs:45:29
+  --> $DIR/method-call.rs:43:29
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/method-call.rs:59:33
+  --> $DIR/method-call.rs:57:33
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-1.rs
index 7968a9f6c4f..950771f35e4 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-1.rs
+++ b/src/test/ui/nll/user-annotations/method-ufcs-1.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 trait Bazoom<T>: Sized {
     fn method<U>(self, arg: T, arg2: U) { }
 }
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr
index 12b02ba33f7..962ddfd2bd1 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-1.stderr
+++ b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `a` does not live long enough
-  --> $DIR/method-ufcs-1.rs:32:7
+  --> $DIR/method-ufcs-1.rs:30:7
    |
 LL |     x(&a, b, c);
    |     --^^-------
@@ -10,7 +10,7 @@ LL | }
    | - `a` dropped here while still borrowed
 
 error[E0597]: `a` does not live long enough
-  --> $DIR/method-ufcs-1.rs:39:36
+  --> $DIR/method-ufcs-1.rs:37:36
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `a` dropped here while still borrowed
 
 error[E0597]: `a` does not live long enough
-  --> $DIR/method-ufcs-1.rs:53:41
+  --> $DIR/method-ufcs-1.rs:51:41
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-2.rs
index a1d0e7b4c92..7dc0f0c12a4 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-2.rs
+++ b/src/test/ui/nll/user-annotations/method-ufcs-2.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 trait Bazoom<T>: Sized {
     fn method<U>(self, arg: T, arg2: U) { }
 }
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr
index a55ed1aa272..63d59905e1c 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-2.stderr
+++ b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `a` does not live long enough
-  --> $DIR/method-ufcs-2.rs:32:7
+  --> $DIR/method-ufcs-2.rs:30:7
    |
 LL |     x(&a, b, c);
    |     --^^-------
@@ -10,7 +10,7 @@ LL | }
    | - `a` dropped here while still borrowed
 
 error[E0597]: `b` does not live long enough
-  --> $DIR/method-ufcs-2.rs:39:39
+  --> $DIR/method-ufcs-2.rs:37:39
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `b` dropped here while still borrowed
 
 error[E0597]: `b` does not live long enough
-  --> $DIR/method-ufcs-2.rs:53:44
+  --> $DIR/method-ufcs-2.rs:51:44
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-3.rs
index ea480c03c35..59d2009d14b 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-3.rs
+++ b/src/test/ui/nll/user-annotations/method-ufcs-3.rs
@@ -1,8 +1,6 @@
 // Unit test for the "user substitutions" that are annotated on each
 // node.
 
-#![feature(nll)]
-
 trait Bazoom<T> {
     fn method<U>(&self, arg: T, arg2: U) { }
 }
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
index 140bda2df41..e7851833e93 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
+++ b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `c` does not live long enough
-  --> $DIR/method-ufcs-3.rs:38:53
+  --> $DIR/method-ufcs-3.rs:36:53
    |
 LL |     <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c);
    |     ------------------------------------------------^^-
@@ -10,7 +10,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/method-ufcs-3.rs:45:48
+  --> $DIR/method-ufcs-3.rs:43:48
    |
 LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
    |                                   -- lifetime `'a` defined here
@@ -24,7 +24,7 @@ LL | }
    | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
-  --> $DIR/method-ufcs-3.rs:59:52
+  --> $DIR/method-ufcs-3.rs:57:52
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
index a77d6af5323..cfbc0bcf6b0 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // Check that substitutions given on the self type (here, `A`) can be
 // used in combination with annotations given for method arguments.
 
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
index 4dc534b2e77..06f20d9b235 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `v` does not live long enough
-  --> $DIR/method-ufcs-inherent-2.rs:16:37
+  --> $DIR/method-ufcs-inherent-2.rs:14:37
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
@@ -14,7 +14,7 @@ LL | }
    | - `v` dropped here while still borrowed
 
 error[E0597]: `v` does not live long enough
-  --> $DIR/method-ufcs-inherent-2.rs:16:41
+  --> $DIR/method-ufcs-inherent-2.rs:14:41
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
index 3f88c3df48e..85e7597390d 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 // Check that inherent methods invoked with `<T>::new` style
 // carry their annotations through to NLL in connection with
 // method type parameters.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
index a41cf50465e..0f83e99cdfb 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `v` does not live long enough
-  --> $DIR/method-ufcs-inherent-4.rs:17:37
+  --> $DIR/method-ufcs-inherent-4.rs:15:37
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
@@ -14,7 +14,7 @@ LL | }
    | - `v` dropped here while still borrowed
 
 error[E0597]: `v` does not live long enough
-  --> $DIR/method-ufcs-inherent-4.rs:17:41
+  --> $DIR/method-ufcs-inherent-4.rs:15:41
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/normalization.rs b/src/test/ui/nll/user-annotations/normalization.rs
index e0af2e67e18..870e3d8110c 100644
--- a/src/test/ui/nll/user-annotations/normalization.rs
+++ b/src/test/ui/nll/user-annotations/normalization.rs
@@ -1,8 +1,6 @@
 // Test that we enforce a `&'static` requirement that is only visible
 // after normalization.
 
-#![feature(nll)]
-
 trait Foo { type Out; }
 impl Foo for () { type Out = &'static u32; }
 
diff --git a/src/test/ui/nll/user-annotations/normalization.stderr b/src/test/ui/nll/user-annotations/normalization.stderr
index fe93c3edba8..4c7893789a5 100644
--- a/src/test/ui/nll/user-annotations/normalization.stderr
+++ b/src/test/ui/nll/user-annotations/normalization.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `a` does not live long enough
-  --> $DIR/normalization.rs:11:31
+  --> $DIR/normalization.rs:9:31
    |
 LL |     let b: <() as Foo>::Out = &a;
    |            ----------------   ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/user-annotations/normalize-self-ty.rs b/src/test/ui/nll/user-annotations/normalize-self-ty.rs
index d97cc88dd9a..a06229a0203 100644
--- a/src/test/ui/nll/user-annotations/normalize-self-ty.rs
+++ b/src/test/ui/nll/user-annotations/normalize-self-ty.rs
@@ -4,8 +4,6 @@
 //
 // run-pass
 
-#![feature(nll)]
-
 trait Mirror {
     type Me;
 }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
index 526134b6e4b..59cd69c0ca5 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 enum Foo<'a> {
     Bar { field: &'a u32 }
 }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
index b483f219c90..a97e7a9fd46 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_brace_enum_variant.rs:9:33
+  --> $DIR/pattern_substs_on_brace_enum_variant.rs:7:33
    |
 LL |     let foo = Foo::Bar { field: &y };
    |                                 ^^ borrowed value does not live long enough
@@ -10,7 +10,7 @@ LL | }
    | - `y` dropped here while still borrowed
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_brace_enum_variant.rs:16:33
+  --> $DIR/pattern_substs_on_brace_enum_variant.rs:14:33
    |
 LL |     let foo = Foo::Bar { field: &y };
    |                                 ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
index 1c92858eb3a..1586c4ea30c 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Foo<'a> { field: &'a u32 }
 
 fn in_let() {
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
index 9c888b0bffe..408d7c2a5e2 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_brace_struct.rs:7:28
+  --> $DIR/pattern_substs_on_brace_struct.rs:5:28
    |
 LL |     let foo = Foo { field: &y };
    |                            ^^ borrowed value does not live long enough
@@ -10,7 +10,7 @@ LL | }
    | - `y` dropped here while still borrowed
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_brace_struct.rs:14:28
+  --> $DIR/pattern_substs_on_brace_struct.rs:12:28
    |
 LL |     let foo = Foo { field: &y };
    |                            ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
index d6c364f8e3f..6fa59fdd8d8 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 enum Foo<'a> {
     Bar(&'a u32)
 }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
index 698cff51126..920c906f63a 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_tuple_enum_variant.rs:9:24
+  --> $DIR/pattern_substs_on_tuple_enum_variant.rs:7:24
    |
 LL |     let foo = Foo::Bar(&y);
    |                        ^^ borrowed value does not live long enough
@@ -10,7 +10,7 @@ LL | }
    | - `y` dropped here while still borrowed
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_tuple_enum_variant.rs:16:24
+  --> $DIR/pattern_substs_on_tuple_enum_variant.rs:14:24
    |
 LL |     let foo = Foo::Bar(&y);
    |                        ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
index 626ca908797..7486aab0e08 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct Foo<'a>(&'a u32);
 
 fn in_let() {
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
index b5f2cb8e321..3f01638d847 100644
--- a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_tuple_struct.rs:7:19
+  --> $DIR/pattern_substs_on_tuple_struct.rs:5:19
    |
 LL |     let foo = Foo(&y);
    |                   ^^ borrowed value does not live long enough
@@ -10,7 +10,7 @@ LL | }
    | - `y` dropped here while still borrowed
 
 error[E0597]: `y` does not live long enough
-  --> $DIR/pattern_substs_on_tuple_struct.rs:14:19
+  --> $DIR/pattern_substs_on_tuple_struct.rs:12:19
    |
 LL |     let foo = Foo(&y);
    |                   ^^ borrowed value does not live long enough
diff --git a/src/test/ui/nll/user-annotations/promoted-annotation.rs b/src/test/ui/nll/user-annotations/promoted-annotation.rs
index fa2d2fb8118..b92f8bfd23b 100644
--- a/src/test/ui/nll/user-annotations/promoted-annotation.rs
+++ b/src/test/ui/nll/user-annotations/promoted-annotation.rs
@@ -1,7 +1,5 @@
 // Test that type annotations are checked in promoted constants correctly.
 
-#![feature(nll)]
-
 fn foo<'a>() {
     let x = 0;
     let f = &drop::<&'a i32>;
diff --git a/src/test/ui/nll/user-annotations/promoted-annotation.stderr b/src/test/ui/nll/user-annotations/promoted-annotation.stderr
index d8b01f22145..cb99a6a369d 100644
--- a/src/test/ui/nll/user-annotations/promoted-annotation.stderr
+++ b/src/test/ui/nll/user-annotations/promoted-annotation.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/promoted-annotation.rs:8:7
+  --> $DIR/promoted-annotation.rs:6:7
    |
 LL | fn foo<'a>() {
    |        -- lifetime `'a` defined here
diff --git a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs
index 362fe51c3ea..101b5cfabb3 100644
--- a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs
+++ b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.rs
@@ -1,5 +1,4 @@
 #![allow(warnings)]
-#![feature(nll)]
 #![feature(type_ascription)]
 
 fn main() {
diff --git a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
index 93dbf7cb1b3..133bbef5231 100644
--- a/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
+++ b/src/test/ui/nll/user-annotations/type_ascription_static_lifetime.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `x` does not live long enough
-  --> $DIR/type_ascription_static_lifetime.rs:7:19
+  --> $DIR/type_ascription_static_lifetime.rs:6:19
    |
 LL |     let y: &u32 = &x: &'static u32;
    |                   ^^--------------
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
new file mode 100644
index 00000000000..19cdd66ef75
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-elision.rs:71:5
+   |
+LL | fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |     ss
+   |     ^^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr
new file mode 100644
index 00000000000..9e68647214c
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr
@@ -0,0 +1,28 @@
+error[E0621]: explicit lifetime required in the type of `ss`
+  --> $DIR/object-lifetime-default-from-box-error.rs:18:5
+   |
+LL | fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
+   |             --------------- help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>`
+...
+LL |     ss.r
+   |     ^^^^ lifetime `'static` required
+
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/object-lifetime-default-from-box-error.rs:18:5
+   |
+LL |     ss.r
+   |     ^^^^ cannot move out of borrowed content
+
+error[E0621]: explicit lifetime required in the type of `ss`
+  --> $DIR/object-lifetime-default-from-box-error.rs:31:5
+   |
+LL | fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
+   |                   --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>`
+...
+LL |     ss.r = b;
+   |     ^^^^ lifetime `'b` required
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0507, E0621.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr
new file mode 100644
index 00000000000..6d183ddf22d
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-from-rptr-box-error.rs:15:5
+   |
+LL | fn c<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
+   |      -- lifetime `'a` defined here
+LL |     ss.t = t;
+   |     ^^^^^^^^ assignment requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr
new file mode 100644
index 00000000000..fe3b21fa39c
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:21:5
+   |
+LL | fn c<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
+   |      -- lifetime `'a` defined here
+LL |     ss.t = t;
+   |     ^^^^^^^^ assignment requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr
new file mode 100644
index 00000000000..448fe9e5510
--- /dev/null
+++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr
@@ -0,0 +1,21 @@
+error: lifetime may not live long enough
+  --> $DIR/object-lifetime-default-mybox.rs:27:5
+   |
+LL | fn load1<'a,'b>(a: &'a MyBox<SomeTrait>,
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+...
+LL |     a
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/object-lifetime-default-mybox.rs:31:5
+   |
+LL | fn load2<'a>(ss: &MyBox<SomeTrait+'a>) -> MyBox<SomeTrait+'a> {
+   |              -- `ss` is a reference that is only valid in the function body
+LL |     load0(ss)
+   |     ^^^^^^^^^ `ss` escapes the function body here
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
index 7e1174a2734..c2deeb7dfd4 100644
--- a/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
+++ b/src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
@@ -2,6 +2,7 @@
 // ignore-musl - no dylibs here
 // ignore-cloudabi
 // ignore-emscripten
+// ignore-sgx no dynamic lib support
 // error-pattern:`panic_unwind` is not compiled with this crate's panic strategy
 
 // This is a test where the local crate, compiled with `panic=abort`, links to
diff --git a/src/test/ui/parser/attr-bad-meta-2.stderr b/src/test/ui/parser/attr-bad-meta-2.stderr
index ffbfc583e8a..2d772dae691 100644
--- a/src/test/ui/parser/attr-bad-meta-2.stderr
+++ b/src/test/ui/parser/attr-bad-meta-2.stderr
@@ -1,8 +1,8 @@
 error: unexpected token: `]`
-  --> $DIR/attr-bad-meta-2.rs:1:8
+  --> $DIR/attr-bad-meta-2.rs:1:9
    |
 LL | #[path =]
-   |        ^
+   |         ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr
index 61ae40b355d..f9832214c68 100644
--- a/src/test/ui/parser/pat-tuple-5.stderr
+++ b/src/test/ui/parser/pat-tuple-5.stderr
@@ -1,8 +1,8 @@
 error: unexpected token: `)`
-  --> $DIR/pat-tuple-5.rs:3:14
+  --> $DIR/pat-tuple-5.rs:3:16
    |
 LL |         (pat ..) => {}
-   |              ^^
+   |                ^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr
index 261e95229a7..260c2e04d74 100644
--- a/src/test/ui/pattern/const-pat-ice.stderr
+++ b/src/test/ui/pattern/const-pat-ice.stderr
@@ -1,4 +1,4 @@
-thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1071:5
+thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5
 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
 
 error: internal compiler error: unexpected panic
diff --git a/src/test/ui/pattern/pattern-bindings-after-at.nll.stderr b/src/test/ui/pattern/pattern-bindings-after-at.nll.stderr
new file mode 100644
index 00000000000..35ee7877f2f
--- /dev/null
+++ b/src/test/ui/pattern/pattern-bindings-after-at.nll.stderr
@@ -0,0 +1,22 @@
+error[E0303]: pattern bindings are not allowed after an `@`
+  --> $DIR/pattern-bindings-after-at.rs:8:31
+   |
+LL |         ref mut z @ &mut Some(ref a) => {
+   |                               ^^^^^ not allowed after `@`
+
+error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable
+  --> $DIR/pattern-bindings-after-at.rs:8:31
+   |
+LL |         ref mut z @ &mut Some(ref a) => {
+   |         ----------------------^^^^^-
+   |         |                     |
+   |         |                     immutable borrow occurs here
+   |         mutable borrow occurs here
+...
+LL |             **z = None;
+   |             ---------- mutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0303, E0502.
+For more information about an error, try `rustc --explain E0303`.
diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs
index bed1e32a601..0127261b2b7 100644
--- a/src/test/ui/print_type_sizes/niche-filling.rs
+++ b/src/test/ui/print_type_sizes/niche-filling.rs
@@ -57,6 +57,15 @@ pub enum Enum4<A, B, C, D> {
     Four(D)
 }
 
+pub union Union1<A: Copy> {
+    a: A,
+}
+
+pub union Union2<A: Copy, B: Copy> {
+    a: A,
+    b: B,
+}
+
 #[start]
 fn start(_: isize, _: *const *const u8) -> isize {
     let _x: MyOption<NonZeroU32> = Default::default();
@@ -69,5 +78,13 @@ fn start(_: isize, _: *const *const u8) -> isize {
     let _e: Enum4<(), char, (), ()> = Enum4::One(());
     let _f: Enum4<(), (), bool, ()> = Enum4::One(());
     let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(());
+
+    // Unions do not currently participate in niche filling.
+    let _h: MyOption<Union2<NonZeroU32, u32>> = Default::default();
+
+    // ...even when theoretically possible.
+    let _i: MyOption<Union1<NonZeroU32>> = Default::default();
+    let _j: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
+
     0
 }
diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout
index 9cdb2ae4f57..301edc0d086 100644
--- a/src/test/ui/print_type_sizes/niche-filling.stdout
+++ b/src/test/ui/print_type_sizes/niche-filling.stdout
@@ -14,6 +14,21 @@ print-type-size         field `.post`: 2 bytes
 print-type-size         field `.pre`: 1 bytes
 print-type-size     variant `None`: 0 bytes
 print-type-size     end padding: 1 bytes
+print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `None`: 0 bytes
+print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `None`: 0 bytes
+print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size     variant `None`: 0 bytes
 print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes
 print-type-size     field `.val`: 4 bytes
 print-type-size     field `.post`: 2 bytes
@@ -36,6 +51,17 @@ print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 by
 print-type-size     variant `Some`: 4 bytes
 print-type-size         field `.0`: 4 bytes
 print-type-size     variant `None`: 0 bytes
+print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Union1`: 4 bytes
+print-type-size         field `.a`: 4 bytes
+print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Union2`: 4 bytes
+print-type-size         field `.a`: 4 bytes
+print-type-size         field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
+print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Union2`: 4 bytes
+print-type-size         field `.a`: 4 bytes
+print-type-size         field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
 print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes
 print-type-size     field `.0`: 4 bytes
 print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes
diff --git a/src/test/ui/proc-macro/no-missing-docs.rs b/src/test/ui/proc-macro/no-missing-docs.rs
new file mode 100644
index 00000000000..e5a5f8beb45
--- /dev/null
+++ b/src/test/ui/proc-macro/no-missing-docs.rs
@@ -0,0 +1,16 @@
+//! Verify that the `decls` module implicitly added by the compiler does not cause `missing_docs`
+//! warnings.
+
+// compile-pass
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![deny(missing_docs)]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+/// Foo1.
+#[proc_macro]
+pub fn foo1(input: TokenStream) -> TokenStream { input }
diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs
index ed43bd8c689..a3d54892de5 100644
--- a/src/test/ui/reachable/expr_if.rs
+++ b/src/test/ui/reachable/expr_if.rs
@@ -4,7 +4,7 @@
 #![deny(unreachable_code)]
 
 fn foo() {
-    if {return} {
+    if {return} { //~ ERROR unreachable block in `if` expression
         println!("Hello, world!");
     }
 }
diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr
index d11471da1a6..f1690e595e5 100644
--- a/src/test/ui/reachable/expr_if.stderr
+++ b/src/test/ui/reachable/expr_if.stderr
@@ -1,15 +1,25 @@
-error: unreachable statement
-  --> $DIR/expr_if.rs:27:5
+error: unreachable block in `if` expression
+  --> $DIR/expr_if.rs:7:17
    |
-LL |     println!("But I am.");
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |       if {return} {
+   |  _________________^
+LL | |         println!("Hello, world!");
+LL | |     }
+   | |_____^
    |
 note: lint level defined here
   --> $DIR/expr_if.rs:4:9
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
+
+error: unreachable statement
+  --> $DIR/expr_if.rs:27:5
+   |
+LL |     println!("But I am.");
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr b/src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr
new file mode 100644
index 00000000000..eee331d95b9
--- /dev/null
+++ b/src/test/ui/recursion/recursive-types-are-not-uninhabited.nll.stderr
@@ -0,0 +1,16 @@
+error[E0005]: refutable pattern in local binding: `Err(_)` not covered
+  --> $DIR/recursive-types-are-not-uninhabited.rs:6:9
+   |
+LL |     let Ok(x) = res;
+   |         ^^^^^ pattern `Err(_)` not covered
+
+error[E0381]: use of possibly uninitialized variable: `x`
+  --> $DIR/recursive-types-are-not-uninhabited.rs:8:5
+   |
+LL |     x
+   |     ^ use of possibly uninitialized `x`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0005, E0381.
+For more information about an error, try `rustc --explain E0005`.
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
new file mode 100644
index 00000000000..76129b4d188
--- /dev/null
+++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
@@ -0,0 +1,11 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/region-invariant-static-error-reporting.rs:15:9
+   |
+LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
+   |              - `x` is a reference that is only valid in the function body
+LL |     let bad = if x.is_some() {
+LL |         x.unwrap()
+   |         ^^^^^^^^^^ `x` escapes the function body here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
new file mode 100644
index 00000000000..24c9a315bad
--- /dev/null
+++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
+   |
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |                                           ^ expected concrete lifetime, found bound lifetime parameter
+   |
+   = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
+              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
new file mode 100644
index 00000000000..6d031e9ac3b
--- /dev/null
+++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
+   |
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |                                                        ^ expected concrete lifetime, found bound lifetime parameter
+   |
+   = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
+              found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-object-lifetime-2.nll.stderr b/src/test/ui/regions/region-object-lifetime-2.nll.stderr
new file mode 100644
index 00000000000..56e8c40c99f
--- /dev/null
+++ b/src/test/ui/regions/region-object-lifetime-2.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/region-object-lifetime-2.rs:10:5
+   |
+LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
+   |                                          -- -- lifetime `'b` defined here
+   |                                          |
+   |                                          lifetime `'a` defined here
+LL |     x.borrowed()
+   |     ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/region-object-lifetime-4.nll.stderr b/src/test/ui/regions/region-object-lifetime-4.nll.stderr
new file mode 100644
index 00000000000..aa91c371f41
--- /dev/null
+++ b/src/test/ui/regions/region-object-lifetime-4.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/region-object-lifetime-4.rs:12:5
+   |
+LL | fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () {
+   |                                         -- -- lifetime `'b` defined here
+   |                                         |
+   |                                         lifetime `'a` defined here
+LL |     x.borrowed()
+   |     ^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
new file mode 100644
index 00000000000..a54f8f5faab
--- /dev/null
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
@@ -0,0 +1,38 @@
+error[E0621]: explicit lifetime required in the type of `v`
+  --> $DIR/region-object-lifetime-in-coercion.rs:8:12
+   |
+LL | fn a(v: &[u8]) -> Box<Foo + 'static> {
+   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+LL |     let x: Box<Foo + 'static> = Box::new(v);
+   |            ^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `v`
+  --> $DIR/region-object-lifetime-in-coercion.rs:14:5
+   |
+LL | fn b(v: &[u8]) -> Box<Foo + 'static> {
+   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `v`
+  --> $DIR/region-object-lifetime-in-coercion.rs:21:5
+   |
+LL | fn c(v: &[u8]) -> Box<Foo> {
+   |         ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]`
+...
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ lifetime `'static` required
+
+error: lifetime may not live long enough
+  --> $DIR/region-object-lifetime-in-coercion.rs:26:5
+   |
+LL | fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/regions/regions-addr-of-self.nll.stderr b/src/test/ui/regions/regions-addr-of-self.nll.stderr
new file mode 100644
index 00000000000..3d7aac74bd4
--- /dev/null
+++ b/src/test/ui/regions/regions-addr-of-self.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-addr-of-self.rs:7:16
+   |
+LL |     pub fn chase_cat(&mut self) {
+   |                      - let's call the lifetime of this reference `'1`
+LL |         let p: &'static mut usize = &mut self.cats_chased;
+   |                ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
new file mode 100644
index 00000000000..345e617a7a3
--- /dev/null
+++ b/src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
@@ -0,0 +1,35 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-addr-of-upvar-self.rs:10:20
+   |
+LL |         let _f = || {
+   |                  -- lifetime `'1` represents this closure's body
+LL |             let p: &'static mut usize = &mut self.food;
+   |                    ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
+   |
+   = note: closure implements `FnMut`, so references to captured variables can't escape the closure
+
+error: lifetime may not live long enough
+  --> $DIR/regions-addr-of-upvar-self.rs:10:20
+   |
+LL |     pub fn chase_cat(&mut self) {
+   |                      - let's call the lifetime of this reference `'1`
+LL |         let _f = || {
+LL |             let p: &'static mut usize = &mut self.food;
+   |                    ^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
+
+error[E0597]: `self` does not live long enough
+  --> $DIR/regions-addr-of-upvar-self.rs:10:46
+   |
+LL |         let _f = || {
+   |                  -- value captured here
+LL |             let p: &'static mut usize = &mut self.food;
+   |                    ------------------        ^^^^ borrowed value does not live long enough
+   |                    |
+   |                    type annotation requires that `self` is borrowed for `'static`
+...
+LL |     }
+   |      - `self` dropped here while still borrowed
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr
new file mode 100644
index 00000000000..867eafe2529
--- /dev/null
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.migrate.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:43:12
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr
new file mode 100644
index 00000000000..86bd100538d
--- /dev/null
+++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr
@@ -0,0 +1,50 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:22:5
+   |
+LL | fn param_not_ok<'a>(x: &'a isize) {
+   |                 -- lifetime `'a` defined here
+LL |     assert_send::<&'a isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5
+   |
+LL | fn param_not_ok1<'a>(_: &'a isize) {
+   |                  -- lifetime `'a` defined here
+LL |     assert_send::<&'a str>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5
+   |
+LL | fn param_not_ok2<'a>(_: &'a isize) {
+   |                  -- lifetime `'a` defined here
+LL |     assert_send::<&'a [isize]>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5
+   |
+LL | fn box_with_region_not_ok<'a>() {
+   |                           -- lifetime `'a` defined here
+LL |     assert_send::<Box<&'a isize>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5
+   |
+LL | fn unsafe_ok2<'a>(_: &'a isize) {
+   |               -- lifetime `'a` defined here
+LL |     assert_send::<*const &'a isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5
+   |
+LL | fn unsafe_ok3<'a>(_: &'a isize) {
+   |               -- lifetime `'a` defined here
+LL |     assert_send::<*mut &'a isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr
new file mode 100644
index 00000000000..a8ab92d75c0
--- /dev/null
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters-cross-crate.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-method-type-parameters-cross-crate.rs:20:5
+   |
+LL | fn call_bigger_region<'x, 'y>(a: Inv<'x>, b: Inv<'y>) {
+   |                       --  -- lifetime `'y` defined here
+   |                       |
+   |                       lifetime `'x` defined here
+LL |     // Here the value provided for 'y is 'y, and hence 'y:'x does not hold.
+LL |     a.bigger_region(b)
+   |     ^^^^^^^^^^^^^^^^^^ argument requires that `'y` must outlive `'x`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
new file mode 100644
index 00000000000..52ad2d9daeb
--- /dev/null
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
@@ -0,0 +1,13 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5
+   |
+LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
+   |                             -           - `b` is a reference that is only valid in the function body
+   |                             |
+   |                             `a` is declared here, outside of the function body
+LL |     // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
+LL |     f.method(b);
+   |     ^^^^^^^^^^^ `b` escapes the function body here
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr
new file mode 100644
index 00000000000..b6d7b8aac5f
--- /dev/null
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-bounded-method-type-parameters.rs:12:9
+   |
+LL | fn caller<'a>(x: &isize) {
+   |           -- lifetime `'a` defined here
+LL |     Foo.some_method::<&'a isize>();
+   |         ^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-bounds.nll.stderr b/src/test/ui/regions/regions-bounds.nll.stderr
new file mode 100644
index 00000000000..3345946bfdd
--- /dev/null
+++ b/src/test/ui/regions/regions-bounds.nll.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-bounds.rs:9:12
+   |
+LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     return e;
+   |            ^ returning this value requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-bounds.rs:13:12
+   |
+LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
+   |          -- -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     return e;
+   |            ^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr
new file mode 100644
index 00000000000..92c4956da02
--- /dev/null
+++ b/src/test/ui/regions/regions-close-associated-type-into-object.nll.stderr
@@ -0,0 +1,36 @@
+error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:15:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+
+error[E0310]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:22:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'static`...
+
+error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:28:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+
+error[E0309]: the associated type `<T as Iter>::Item` may not live long enough
+  --> $DIR/regions-close-associated-type-into-object.rs:35:5
+   |
+LL |     Box::new(item)
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as Iter>::Item: 'a`...
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
new file mode 100644
index 00000000000..42df9b1c49f
--- /dev/null
+++ b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-close-object-into-object-2.rs:10:5
+   |
+LL | fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
+   |      -- lifetime `'a` defined here
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error[E0515]: cannot return value referencing local data `*v`
+  --> $DIR/regions-close-object-into-object-2.rs:10:5
+   |
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^---^^^^^^^^^^^
+   |     |     |
+   |     |     `*v` is borrowed here
+   |     returns a value referencing data owned by the current function
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
new file mode 100644
index 00000000000..8af94fa7e79
--- /dev/null
+++ b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
@@ -0,0 +1,37 @@
+error[E0310]: the parameter type `U` may not live long enough
+  --> $DIR/regions-close-object-into-object-4.rs:10:5
+   |
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `U: 'static`...
+
+error: lifetime may not live long enough
+  --> $DIR/regions-close-object-into-object-4.rs:10:5
+   |
+LL | fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
+   |      -- lifetime `'a` defined here
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error[E0515]: cannot return value referencing local data `*v`
+  --> $DIR/regions-close-object-into-object-4.rs:10:5
+   |
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^---^^^^^^^^^^^
+   |     |     |
+   |     |     `*v` is borrowed here
+   |     returns a value referencing data owned by the current function
+
+error[E0310]: the parameter type `U` may not live long enough
+  --> $DIR/regions-close-object-into-object-4.rs:10:9
+   |
+LL |     box B(&*v) as Box<X>
+   |         ^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `U: 'static`...
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0310, E0515.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
new file mode 100644
index 00000000000..08ba1b17b56
--- /dev/null
+++ b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
@@ -0,0 +1,29 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:17:5
+   |
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0515]: cannot return value referencing local data `*v`
+  --> $DIR/regions-close-object-into-object-5.rs:17:5
+   |
+LL |     box B(&*v) as Box<X>
+   |     ^^^^^^---^^^^^^^^^^^
+   |     |     |
+   |     |     `*v` is borrowed here
+   |     returns a value referencing data owned by the current function
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:17:9
+   |
+LL |     box B(&*v) as Box<X>
+   |         ^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0310, E0515.
+For more information about an error, try `rustc --explain E0310`.
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
new file mode 100644
index 00000000000..30fdb820e36
--- /dev/null
+++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
@@ -0,0 +1,20 @@
+error[E0310]: the parameter type `A` may not live long enough
+  --> $DIR/regions-close-over-type-parameter-1.rs:10:5
+   |
+LL |     box v as Box<SomeTrait+'static>
+   |     ^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `A: 'static`...
+
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-close-over-type-parameter-1.rs:20:5
+   |
+LL |     box v as Box<SomeTrait+'b>
+   |     ^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `A: 'b`...
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
new file mode 100644
index 00000000000..001ed7fe4c5
--- /dev/null
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
+   |
+LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
+   |                    --    -- lifetime `'c` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     // A outlives 'a AND 'b...but not 'c.
+LL |     box v as Box<SomeTrait+'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-close-param-into-object.nll.stderr b/src/test/ui/regions/regions-close-param-into-object.nll.stderr
new file mode 100644
index 00000000000..7bd7824f00a
--- /dev/null
+++ b/src/test/ui/regions/regions-close-param-into-object.nll.stderr
@@ -0,0 +1,36 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:6:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:12:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:18:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'a`...
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-param-into-object.rs:24:5
+   |
+LL |     Box::new(v)
+   |     ^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'a`...
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0309, E0310.
+For more information about an error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-creating-enums3.nll.stderr b/src/test/ui/regions/regions-creating-enums3.nll.stderr
new file mode 100644
index 00000000000..e35a878fce1
--- /dev/null
+++ b/src/test/ui/regions/regions-creating-enums3.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-creating-enums3.rs:7:5
+   |
+LL | fn mk_add_bad1<'a,'b>(x: &'a Ast<'a>, y: &'b Ast<'b>) -> Ast<'a> {
+   |                -- -- lifetime `'b` defined here
+   |                |
+   |                lifetime `'a` defined here
+LL |     Ast::Add(x, y)
+   |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-creating-enums4.nll.stderr b/src/test/ui/regions/regions-creating-enums4.nll.stderr
new file mode 100644
index 00000000000..4eac457feda
--- /dev/null
+++ b/src/test/ui/regions/regions-creating-enums4.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-creating-enums4.rs:7:5
+   |
+LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
+   |                -- -- lifetime `'b` defined here
+   |                |
+   |                lifetime `'a` defined here
+LL |     Ast::Add(x, y)
+   |     ^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-early-bound-error-method.nll.stderr b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr
new file mode 100644
index 00000000000..1540a7bacd7
--- /dev/null
+++ b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-early-bound-error-method.rs:20:9
+   |
+LL | impl<'a> Box<'a> {
+   |      -- lifetime `'a` defined here
+LL |     fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
+   |           -- lifetime `'b` defined here
+LL |         g2.get()
+   |         ^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-early-bound-error.nll.stderr b/src/test/ui/regions/regions-early-bound-error.nll.stderr
new file mode 100644
index 00000000000..7836291a7ca
--- /dev/null
+++ b/src/test/ui/regions/regions-early-bound-error.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-early-bound-error.rs:19:5
+   |
+LL | fn get<'a,'b,G:GetRef<'a, isize>>(g1: G, b: &'b isize) -> &'b isize {
+   |        -- -- lifetime `'b` defined here
+   |        |
+   |        lifetime `'a` defined here
+LL |     g1.get()
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-escape-method.nll.stderr b/src/test/ui/regions/regions-escape-method.nll.stderr
new file mode 100644
index 00000000000..9f425125b98
--- /dev/null
+++ b/src/test/ui/regions/regions-escape-method.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-escape-method.rs:15:13
+   |
+LL |     s.f(|p| p)
+   |          -- ^ returning this value requires that `'1` must outlive `'2`
+   |          ||
+   |          |return type of closure is &'2 i32
+   |          has type `&'1 i32`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr
new file mode 100644
index 00000000000..cae6c33ac6e
--- /dev/null
+++ b/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-escape-via-trait-or-not.rs:18:14
+   |
+LL |     with(|o| o)
+   |           -- ^ returning this value requires that `'1` must outlive `'2`
+   |           ||
+   |           |return type of closure is &'2 isize
+   |           has type `&'1 isize`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr
new file mode 100644
index 00000000000..9ae484eaf45
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-ordering-callee.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-callee.rs:13:5
+   |
+LL | fn ordering2<'a, 'b>(x: &'a &'b usize, y: &'a usize) -> &'b usize {
+   |              --  -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+LL |     // However, it is not safe to assume that 'b <= 'a
+LL |     &*y
+   |     ^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-callee.rs:18:12
+   |
+LL | fn ordering3<'a, 'b>(x: &'a usize, y: &'b usize) -> &'a &'b usize {
+   |              --  -- lifetime `'b` defined here
+   |              |
+   |              lifetime `'a` defined here
+LL |     // Do not infer an ordering from the return value.
+LL |     let z: &'b usize = &*x;
+   |            ^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr
new file mode 100644
index 00000000000..16eda2844c6
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.nll.stderr
@@ -0,0 +1,33 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-caller.rs:11:12
+   |
+LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let z: Option<&'b &'a usize> = None;
+   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-caller.rs:17:12
+   |
+LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let y: Paramd<'a> = Paramd { x: a };
+LL |     let z: Option<&'b Paramd<'a>> = None;
+   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-caller.rs:22:12
+   |
+LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let z: Option<&'a &'b usize> = None;
+   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr
new file mode 100644
index 00000000000..480a81d33f6
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-incorrect.rs:15:9
+   |
+LL |   impl<'b, T> Node<'b, T> {
+   |        -- lifetime `'b` defined here
+LL |       fn get<'a>(&'a self) -> &'b T {
+   |              -- lifetime `'a` defined here
+LL | /         match self.next {
+LL | |             Some(ref next) => next.get(),
+LL | |             None => &self.val
+LL | |         }
+   | |_________^ returning this value requires that `'a` must outlive `'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
index b3c02f7f429..0f0f86dfcdd 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr
@@ -1,10 +1,10 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/ty-param-fn-body-nll-feature.rs:20:5
+  --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:5
    |
-LL |     outlives(cell, t)
-   |     ^^^^^^^^^^^^^^^^^
+LL |     wf::<&'x T>();
+   |     ^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `T: 'a`...
+   = help: consider adding an explicit lifetime bound `T: 'x`...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr b/src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr
new file mode 100644
index 00000000000..0651e305cde
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-bound-from-trait-self.nll.stderr
@@ -0,0 +1,11 @@
+error[E0309]: the parameter type `Self` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait-self.rs:46:9
+   |
+LL |         check_bound(x, self)
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `Self: 'a`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr
new file mode 100644
index 00000000000..1f7b34fc699
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr
@@ -0,0 +1,19 @@
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait.rs:33:5
+   |
+LL |     check_bound(x, a)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `A: 'a`...
+
+error[E0309]: the parameter type `A` may not live long enough
+  --> $DIR/regions-infer-bound-from-trait.rs:37:5
+   |
+LL |     check_bound(x, a)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `A: 'a`...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/regions/regions-infer-call-3.nll.stderr b/src/test/ui/regions/regions-infer-call-3.nll.stderr
new file mode 100644
index 00000000000..ca51555a077
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-call-3.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-call-3.rs:8:24
+   |
+LL |     let z = with(|y| { select(x, y) });
+   |                   --   ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |                   ||
+   |                   |return type of closure is &'2 isize
+   |                   has type `&'1 isize`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr
new file mode 100644
index 00000000000..cefeecf16e2
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-contravariance-due-to-decl.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-contravariance-due-to-decl.rs:25:12
+   |
+LL | fn use_<'short,'long>(c: Contravariant<'short>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: Contravariant<'long> = c;
+   |            ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr
new file mode 100644
index 00000000000..1bddecba50a
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-covariance-due-to-decl.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-covariance-due-to-decl.rs:22:12
+   |
+LL | fn use_<'short,'long>(c: Covariant<'long>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: Covariant<'short> = c;
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr
new file mode 100644
index 00000000000..0c1e3989b23
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-invariance-due-to-decl.rs:12:5
+   |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+   |                       -- lifetime `'r` defined here
+LL |     b_isize
+   |     ^^^^^^^ returning this value requires that `'r` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr
new file mode 100644
index 00000000000..0edeb272399
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-invariance-due-to-mutability-3.rs:10:5
+   |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+   |                       -- lifetime `'r` defined here
+LL |     b_isize
+   |     ^^^^^^^ returning this value requires that `'r` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr
new file mode 100644
index 00000000000..724dd7e3f6d
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr
@@ -0,0 +1,10 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-invariance-due-to-mutability-4.rs:10:5
+   |
+LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> {
+   |                       -- lifetime `'r` defined here
+LL |     b_isize
+   |     ^^^^^^^ returning this value requires that `'r` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-infer-not-param.nll.stderr b/src/test/ui/regions/regions-infer-not-param.nll.stderr
new file mode 100644
index 00000000000..2064b060ec4
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-not-param.nll.stderr
@@ -0,0 +1,26 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-not-param.rs:15:54
+   |
+LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
+   |                -- -- lifetime `'b` defined here      ^ returning this value requires that `'a` must outlive `'b`
+   |                |
+   |                lifetime `'a` defined here
+
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-not-param.rs:19:63
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                   -- -- lifetime `'b` defined here            ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+   |                   |
+   |                   lifetime `'a` defined here
+
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-not-param.rs:19:63
+   |
+LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
+   |                   -- -- lifetime `'b` defined here            ^ returning this value requires that `'a` must outlive `'b`
+   |                   |
+   |                   lifetime `'a` defined here
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr
new file mode 100644
index 00000000000..a86e6ccdc5e
--- /dev/null
+++ b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-infer-paramd-indirect.rs:22:9
+   |
+LL | impl<'a> SetF<'a> for C<'a> {
+   |      -- lifetime `'a` defined here
+...
+LL |     fn set_f_bad(&mut self, b: Box<B>) {
+   |                             - has type `std::boxed::Box<std::boxed::Box<&'1 isize>>`
+LL |         self.f = b;
+   |         ^^^^^^ assignment requires that `'1` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
new file mode 100644
index 00000000000..e1f14fc0cd9
--- /dev/null
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
+   |
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |                                           ^ expected concrete lifetime, found bound lifetime parameter
+   |
+   = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
+              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-nested-fns.nll.stderr b/src/test/ui/regions/regions-nested-fns.nll.stderr
new file mode 100644
index 00000000000..c11c09b6d0d
--- /dev/null
+++ b/src/test/ui/regions/regions-nested-fns.nll.stderr
@@ -0,0 +1,51 @@
+error[E0521]: borrowed data escapes outside of closure
+  --> $DIR/regions-nested-fns.rs:10:9
+   |
+LL |     let mut ay = &y;
+   |         ------ `ay` is declared here, outside of the closure body
+LL | 
+LL |     ignore::<Box<for<'z> FnMut(&'z isize)>>(Box::new(|z| {
+   |                                                       - `z` is a reference that is only valid in the closure body
+...
+LL |         ay = z;
+   |         ^^^^^^ `z` escapes the closure body here
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/regions-nested-fns.rs:5:18
+   |
+LL |     let mut ay = &y;
+   |                  ^^ borrowed value does not live long enough
+...
+LL |         if false { return ay; }
+   |                           -- returning this value requires that `y` is borrowed for `'static`
+...
+LL | }
+   | - `y` dropped here while still borrowed
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/regions-nested-fns.rs:9:15
+   |
+LL |     ignore::<Box<for<'z> FnMut(&'z isize)>>(Box::new(|z| {
+   |                                                      --- value captured here
+LL |         ay = x;
+LL |         ay = &y;
+   |               ^ borrowed value does not live long enough
+...
+LL |         if false { return ay; }
+   |                           -- returning this value requires that `y` is borrowed for `'static`
+...
+LL | }
+   | - `y` dropped here while still borrowed
+
+error: lifetime may not live long enough
+  --> $DIR/regions-nested-fns.rs:14:27
+   |
+LL | fn nested<'x>(x: &'x isize) {
+   |           -- lifetime `'x` defined here
+...
+LL |         if false { return x; }
+   |                           ^ returning this value requires that `'x` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr
new file mode 100644
index 00000000000..5028663ba6d
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.migrate.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _: &'a WithHrAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:57:12
+   |
+LL | fn with_assoc_sub<'a,'b>() {
+   |                   -- -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr
new file mode 100644
index 00000000000..880fe17b740
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.migrate.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container-wc.rs:37:12
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-outlives-projection-container.nll.stderr b/src/test/ui/regions/regions-outlives-projection-container.nll.stderr
new file mode 100644
index 00000000000..ef87d02ec08
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container.nll.stderr
@@ -0,0 +1,46 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container.rs:40:13
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container.rs:58:13
+   |
+LL | fn without_assoc<'a,'b>() {
+   |                  -- -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+...
+LL |     let _x: &'a WithoutAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container.rs:67:5
+   |
+LL | fn call_with_assoc<'a,'b>() {
+   |                    -- -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+...
+LL |     call::<&'a WithAssoc<TheType<'b>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container.rs:74:5
+   |
+LL | fn call_without_assoc<'a,'b>() {
+   |                       -- -- lifetime `'b` defined here
+   |                       |
+   |                       lifetime `'a` defined here
+...
+LL |     call::<&'a WithoutAssoc<TheType<'b>>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr
new file mode 100644
index 00000000000..c8582f8bfe7
--- /dev/null
+++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref-mut-ref.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-reborrow-from-shorter-mut-ref-mut-ref.rs:4:5
+   |
+LL | fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut isize) -> &'b mut isize {
+   |                      --  -- lifetime `'b` defined here
+   |                      |
+   |                      lifetime `'a` defined here
+LL |     &mut ***p
+   |     ^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr
new file mode 100644
index 00000000000..5946e7bf849
--- /dev/null
+++ b/src/test/ui/regions/regions-reborrow-from-shorter-mut-ref.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-reborrow-from-shorter-mut-ref.rs:6:5
+   |
+LL | fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut isize) -> &'b mut isize {
+   |                      --  -- lifetime `'b` defined here
+   |                      |
+   |                      lifetime `'a` defined here
+LL |     &mut **p
+   |     ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-ret-borrowed-1.nll.stderr b/src/test/ui/regions/regions-ret-borrowed-1.nll.stderr
new file mode 100644
index 00000000000..0784e894ea9
--- /dev/null
+++ b/src/test/ui/regions/regions-ret-borrowed-1.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-ret-borrowed-1.rs:10:14
+   |
+LL |     with(|o| o)
+   |           -- ^ returning this value requires that `'1` must outlive `'2`
+   |           ||
+   |           |return type of closure is &'2 isize
+   |           has type `&'1 isize`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-ret-borrowed.nll.stderr b/src/test/ui/regions/regions-ret-borrowed.nll.stderr
new file mode 100644
index 00000000000..d9be5ef89cc
--- /dev/null
+++ b/src/test/ui/regions/regions-ret-borrowed.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-ret-borrowed.rs:13:14
+   |
+LL |     with(|o| o)
+   |           -- ^ returning this value requires that `'1` must outlive `'2`
+   |           ||
+   |           |return type of closure is &'2 isize
+   |           has type `&'1 isize`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
new file mode 100644
index 00000000000..4c275b19492
--- /dev/null
+++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr
@@ -0,0 +1,13 @@
+error: captured variable cannot escape `FnMut` closure body
+  --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
+   |
+LL |         let mut f = || &mut x;
+   |                      - ^^^^^^ returns a reference to a captured variable which escapes the closure body
+   |                      |
+   |                      inferred to be a `FnMut` closure
+   |
+   = note: `FnMut` closures only have access to their captured variables while they are executing...
+   = note: ...therefore, they cannot allow references to captured variables to escape
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-static-bound.ll.nll.stderr b/src/test/ui/regions/regions-static-bound.ll.nll.stderr
new file mode 100644
index 00000000000..d6cec03e0ff
--- /dev/null
+++ b/src/test/ui/regions/regions-static-bound.ll.nll.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-static-bound.rs:9:5
+   |
+LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
+   |                        -- lifetime `'a` defined here
+LL |     t //[ll]~ ERROR E0312
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error[E0621]: explicit lifetime required in the type of `u`
+  --> $DIR/regions-static-bound.rs:14:5
+   |
+LL | fn error(u: &(), v: &()) {
+   |             --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()`
+LL |     static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
+   |     ^^^^^^^^^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `v`
+  --> $DIR/regions-static-bound.rs:16:5
+   |
+LL | fn error(u: &(), v: &()) {
+   |                     --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`
+...
+LL |     static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
+   |     ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/regions/regions-static-bound.migrate.nll.stderr b/src/test/ui/regions/regions-static-bound.migrate.nll.stderr
new file mode 100644
index 00000000000..b5f3e6cfaba
--- /dev/null
+++ b/src/test/ui/regions/regions-static-bound.migrate.nll.stderr
@@ -0,0 +1,28 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-static-bound.rs:9:5
+   |
+LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
+   |                        -- lifetime `'a` defined here
+LL |     t
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error[E0621]: explicit lifetime required in the type of `u`
+  --> $DIR/regions-static-bound.rs:14:5
+   |
+LL | fn error(u: &(), v: &()) {
+   |             --- help: add explicit lifetime `'static` to the type of `u`: `&'static ()`
+LL |     static_id(&u);
+   |     ^^^^^^^^^^^^^ lifetime `'static` required
+
+error[E0621]: explicit lifetime required in the type of `v`
+  --> $DIR/regions-static-bound.rs:16:5
+   |
+LL | fn error(u: &(), v: &()) {
+   |                     --- help: add explicit lifetime `'static` to the type of `v`: `&'static ()`
+...
+LL |     static_id_indirect(&v);
+   |     ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
new file mode 100644
index 00000000000..eccf1b5e8cf
--- /dev/null
+++ b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-trait-object-subtyping.rs:15:5
+   |
+LL | fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
+   |         -- -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     // Without knowing 'a:'b, we can't coerce
+LL |     x
+   |     ^ returning this value requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-trait-object-subtyping.rs:22:5
+   |
+LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut Dummy>) -> Wrapper<&'b mut Dummy> {
+   |         --    -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     // We can't coerce because it is packed in `Wrapper`
+LL |     x
+   |     ^ returning this value requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr
new file mode 100644
index 00000000000..f5b96f314c5
--- /dev/null
+++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant-in-second-position.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-variance-contravariant-use-covariant-in-second-position.rs:25:12
+   |
+LL | fn use_<'short,'long>(c: S<'long, 'short>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: S<'long, 'long> = c;
+   |            ^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr
new file mode 100644
index 00000000000..372510a2f7e
--- /dev/null
+++ b/src/test/ui/regions/regions-variance-contravariant-use-covariant.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-variance-contravariant-use-covariant.rs:23:12
+   |
+LL | fn use_<'short,'long>(c: Contravariant<'short>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: Contravariant<'long> = c;
+   |            ^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr
new file mode 100644
index 00000000000..e87e914727c
--- /dev/null
+++ b/src/test/ui/regions/regions-variance-covariant-use-contravariant.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-variance-covariant-use-contravariant.rs:23:12
+   |
+LL | fn use_<'short,'long>(c: Covariant<'long>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: Covariant<'short> = c;
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
new file mode 100644
index 00000000000..adee33bfc7e
--- /dev/null
+++ b/src/test/ui/regions/regions-variance-invariant-use-contravariant.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-variance-invariant-use-contravariant.rs:20:12
+   |
+LL | fn use_<'short,'long>(c: Invariant<'long>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: Invariant<'short> = c;
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
new file mode 100644
index 00000000000..15853e6ca5d
--- /dev/null
+++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-variance-invariant-use-covariant.rs:17:12
+   |
+LL | fn use_<'b>(c: Invariant<'b>) {
+   |         -- lifetime `'b` defined here
+...
+LL |     let _: Invariant<'static> = c;
+   |            ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs
index 2f3c094ff39..7b499af632e 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/bind-by-move-no-guards.rs
@@ -4,7 +4,6 @@
 
 // compile-pass
 
-#![feature(nll)]
 #![feature(bind_by_move_pattern_guards)]
 
 use std::sync::mpsc::channel;
diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs
index 9a9d11ce1b1..aca6aa5f0f8 100644
--- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs
+++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-basic-examples.rs
@@ -1,4 +1,3 @@
-#![feature(nll)]
 #![feature(bind_by_move_pattern_guards)]
 
 // compile-pass
diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr
new file mode 100644
index 00000000000..c74b82dbbd8
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr
@@ -0,0 +1,14 @@
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-issue-49631.rs:20:9
+   |
+LL |     while let Some(Ok(string)) = foo.get() {
+   |                                  --- immutable borrow occurs here
+LL |         foo.mutate();
+   |         ^^^ mutable borrow occurs here
+LL |
+LL |         println!("foo={:?}", *string);
+   |                              ------- immutable borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
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
new file mode 100644
index 00000000000..8cb9a8cf1f6
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs
@@ -0,0 +1,33 @@
+#![crate_type = "rlib"]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub enum PartiallyInhabitedVariants {
+    Tuple(u8),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+
+pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+
+pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+
+pub struct IndirectUninhabitedVariants(UninhabitedVariants);
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
new file mode 100644
index 00000000000..80b9dc4c1c3
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs
@@ -0,0 +1,38 @@
+// aux-build:uninhabited.rs
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+// This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never
+// type can.
+
+struct A;
+
+fn can_coerce_never_type_to_anything(x: !) -> A {
+    x
+}
+
+fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
new file mode 100644
index 00000000000..d05ee1d39ec
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:23:5
+   |
+LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+   |                                                                - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedEnum`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:27:5
+   |
+LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+   |                                                                               - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedTupleStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:31:5
+   |
+LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+   |                                                                    - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions.rs:35:5
+   |
+LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+   |                                                                                  - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants`
+   |
+   = note: expected type `A`
+              found type `uninhabited::UninhabitedVariants`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
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
new file mode 100644
index 00000000000..803a542f8aa
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs
@@ -0,0 +1,46 @@
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+struct A;
+
+// This test checks that uninhabited non-exhaustive types defined in the same crate cannot coerce
+// to any type, as the never type can.
+
+fn can_coerce_never_type_to_anything(x: !) -> A {
+    x
+}
+
+fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+    x //~ ERROR mismatched types
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..8f6b709bb1f
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:31:5
+   |
+LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+   |                                                                - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `UninhabitedEnum`
+   |
+   = note: expected type `A`
+              found type `UninhabitedEnum`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:35:5
+   |
+LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+   |                                                                               - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `UninhabitedTupleStruct`
+   |
+   = note: expected type `A`
+              found type `UninhabitedTupleStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:39:5
+   |
+LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+   |                                                                    - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found struct `UninhabitedStruct`
+   |
+   = note: expected type `A`
+              found type `UninhabitedStruct`
+
+error[E0308]: mismatched types
+  --> $DIR/coercions_same_crate.rs:43:5
+   |
+LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A {
+   |                                                                                  - expected `A` because of return type
+LL |     x
+   |     ^ expected struct `A`, found enum `UninhabitedVariants`
+   |
+   = note: expected type `A`
+              found type `UninhabitedVariants`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
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
new file mode 100644
index 00000000000..98a7fdbc504
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs
@@ -0,0 +1,36 @@
+// aux-build:uninhabited.rs
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    IndirectUninhabitedEnum,
+    IndirectUninhabitedStruct,
+    IndirectUninhabitedTupleStruct,
+    IndirectUninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type through a level of
+// indirection from an extern crate will not compile.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..af82022e1da
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled
+  --> $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: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: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:33:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
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
new file mode 100644
index 00000000000..3c8d495e12c
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs
@@ -0,0 +1,52 @@
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+
+pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+
+pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+
+pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type through a level of
+// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..27b120792d6
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr
@@ -0,0 +1,59 @@
+error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled
+  --> $DIR/indirect_match_same_crate.rs:35:11
+   |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+   | ----------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `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:39:11
+   |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+   | --------------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `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:43:11
+   |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+   | ------------------------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `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:49:11
+   |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+   | ------------------------------------------------------------
+   | |          |
+   | |          variant not covered
+   | `IndirectUninhabitedVariants` defined here
+...
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
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
new file mode 100644
index 00000000000..be86519ecb1
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs
@@ -0,0 +1,40 @@
+// aux-build:uninhabited.rs
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    IndirectUninhabitedEnum,
+    IndirectUninhabitedStruct,
+    IndirectUninhabitedTupleStruct,
+    IndirectUninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type through a level of
+// indirection from an extern crate will not compile. In particular, this enables the
+// `exhaustive_patterns` feature as this can change the branch used in the compiler to determine
+// this.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..17a8d010072
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.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: type `uninhabited::IndirectUninhabitedStruct` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.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: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:31: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::IndirectUninhabitedVariants` is non-empty
+  --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
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
new file mode 100644
index 00000000000..5dbd38e07df
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs
@@ -0,0 +1,58 @@
+// compile-pass
+// skip-codegen
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+
+pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+
+pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+
+pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
+// will compile. In particular, this enables the `exhaustive_patterns` feature as this can
+// change the branch used in the compiler to determine this.
+// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(
+    x: IndirectUninhabitedVariants,
+) -> A {
+    match x {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
new file mode 100644
index 00000000000..e54098d4d48
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs
@@ -0,0 +1,34 @@
+// aux-build:uninhabited.rs
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate
+// will not compile.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
new file mode 100644
index 00000000000..de39688f45a
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
+  --> $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: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: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:31:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
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
new file mode 100644
index 00000000000..6405dd3bd65
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs
@@ -0,0 +1,42 @@
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
+// will compile.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..410285a39a9
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -0,0 +1,49 @@
+error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled
+  --> $DIR/match_same_crate.rs:31:11
+   |
+LL |   pub struct UninhabitedStruct {
+   |   -          ----------------- variant not covered
+   |  _|
+   | |
+LL | |     _priv: !,
+LL | | }
+   | |_- `UninhabitedStruct` 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 `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled
+  --> $DIR/match_same_crate.rs:35:11
+   |
+LL | pub struct UninhabitedTupleStruct(!);
+   | -------------------------------------
+   | |          |
+   | |          variant not covered
+   | `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:39:11
+   |
+LL | / pub enum UninhabitedVariants {
+LL | |     #[non_exhaustive] Tuple(!),
+   | |                       ----- variant not covered
+LL | |     #[non_exhaustive] Struct { x: ! }
+   | |                       ------ variant not covered
+LL | | }
+   | |_- `UninhabitedVariants` defined here
+...
+LL |       match x {}
+   |             ^
+   |
+   = 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/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
new file mode 100644
index 00000000000..900dfff652e
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs
@@ -0,0 +1,37 @@
+// aux-build:uninhabited.rs
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate
+// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can
+// change the branch used in the compiler to determine this.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {} //~ ERROR non-exhaustive patterns
+}
+
+fn main() {}
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
new file mode 100644
index 00000000000..48a888bc50b
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -0,0 +1,35 @@
+error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty
+  --> $DIR/match_with_exhaustive_patterns.rs:22: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::UninhabitedStruct` is non-empty
+  --> $DIR/match_with_exhaustive_patterns.rs:26: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::UninhabitedTupleStruct` is non-empty
+  --> $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:34:11
+   |
+LL |     match x {}
+   |           ^
+   |
+   = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
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
new file mode 100644
index 00000000000..74922d4bcb5
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs
@@ -0,0 +1,48 @@
+// compile-pass
+// skip-codegen
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+struct A;
+
+// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate
+// will compile. In particular, this enables the `exhaustive_patterns` feature as this can
+// change the branch used in the compiler to determine this.
+// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648.
+
+fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A {
+    match x {}
+}
+
+fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A {
+    match x {}
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs
new file mode 100644
index 00000000000..97061310d19
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs
@@ -0,0 +1,59 @@
+// aux-build:uninhabited.rs
+// compile-pass
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+
+extern crate uninhabited;
+
+use uninhabited::{
+    PartiallyInhabitedVariants,
+    UninhabitedEnum,
+    UninhabitedStruct,
+    UninhabitedTupleStruct,
+    UninhabitedVariants,
+};
+
+fn uninhabited_enum() -> Option<UninhabitedEnum> {
+    None
+}
+
+fn uninhabited_variant() -> Option<UninhabitedVariants> {
+    None
+}
+
+fn partially_inhabited_variant() -> PartiallyInhabitedVariants {
+    PartiallyInhabitedVariants::Tuple(3)
+}
+
+fn uninhabited_struct() -> Option<UninhabitedStruct> {
+    None
+}
+
+fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
+    None
+}
+
+// This test checks that non-exhaustive types that would normally be considered uninhabited within
+// the defining crate are not considered uninhabited from extern crates.
+
+fn main() {
+    match uninhabited_enum() {
+        Some(_x) => (), // This line would normally error.
+        None => (),
+    }
+
+    match uninhabited_variant() {
+        Some(_x) => (), // This line would normally error.
+        None => (),
+    }
+
+    // This line would normally error.
+    while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() {
+    }
+
+    while let Some(_x) = uninhabited_struct() { // This line would normally error.
+    }
+
+    while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error.
+    }
+}
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
new file mode 100644
index 00000000000..302a35cab5f
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs
@@ -0,0 +1,71 @@
+#![deny(unreachable_patterns)]
+#![feature(exhaustive_patterns)]
+#![feature(never_type)]
+#![feature(non_exhaustive)]
+
+#[non_exhaustive]
+pub enum UninhabitedEnum {
+}
+
+#[non_exhaustive]
+pub struct UninhabitedTupleStruct(!);
+
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    _priv: !,
+}
+
+pub enum UninhabitedVariants {
+    #[non_exhaustive] Tuple(!),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+pub enum PartiallyInhabitedVariants {
+    Tuple(u8),
+    #[non_exhaustive] Struct { x: ! }
+}
+
+fn uninhabited_enum() -> Option<UninhabitedEnum> {
+    None
+}
+
+fn uninhabited_variant() -> Option<UninhabitedVariants> {
+    None
+}
+
+fn partially_inhabited_variant() -> PartiallyInhabitedVariants {
+    PartiallyInhabitedVariants::Tuple(3)
+}
+
+fn uninhabited_struct() -> Option<UninhabitedStruct> {
+    None
+}
+
+fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
+    None
+}
+
+// This test checks that non-exhaustive types that would normally be considered uninhabited within
+// the defining crate are still considered uninhabited.
+
+fn main() {
+    match uninhabited_enum() {
+        Some(_x) => (), //~ ERROR unreachable pattern
+        None => (),
+    }
+
+    match uninhabited_variant() {
+        Some(_x) => (), //~ ERROR unreachable pattern
+        None => (),
+    }
+
+    while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
+        //~^ ERROR unreachable pattern
+    }
+
+    while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable pattern
+    }
+
+    while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable pattern
+    }
+}
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
new file mode 100644
index 00000000000..72f37d9a60b
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr
@@ -0,0 +1,38 @@
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:53:9
+   |
+LL |         Some(_x) => (),
+   |         ^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/patterns_same_crate.rs:1:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:58:9
+   |
+LL |         Some(_x) => (),
+   |         ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:62:15
+   |
+LL |     while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:66:15
+   |
+LL |     while let Some(_x) = uninhabited_struct() {
+   |               ^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/patterns_same_crate.rs:69:15
+   |
+LL |     while let Some(_x) = uninhabited_tuple_struct() {
+   |               ^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs
index e2a7ac349ec..e885263aa80 100644
--- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs
+++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs
@@ -1,6 +1,7 @@
 // run-pass
 // ignore-cloudabi no processes
 // ignore-emscripten no processes
+// ignore-sgx no processes
 
 // Tests ensuring that `dbg!(expr)` has the expected run-time behavior.
 // as well as some compile time properties we expect.
@@ -69,44 +70,44 @@ fn test() {
 
 fn validate_stderr(stderr: Vec<String>) {
     assert_eq!(stderr, &[
-        ":21] Unit = Unit",
+        ":22] Unit = Unit",
 
-        ":22] a = Unit",
+        ":23] a = Unit",
 
-        ":28] Point{x: 42, y: 24,} = Point {",
+        ":29] Point{x: 42, y: 24,} = Point {",
         "    x: 42,",
         "    y: 24,",
         "}",
 
-        ":29] b = Point {",
+        ":30] b = Point {",
         "    x: 42,",
         "    y: 24,",
         "}",
 
-        ":37]",
+        ":38]",
 
-        ":41] &a = NoCopy(",
+        ":42] &a = NoCopy(",
         "    1337,",
         ")",
 
-        ":41] dbg!(& a) = NoCopy(",
+        ":42] dbg!(& a) = NoCopy(",
         "    1337,",
         ")",
-        ":46] f(&42) = 42",
+        ":47] f(&42) = 42",
 
         "before",
-        ":51] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
+        ":52] { foo += 1; eprintln!(\"before\"); 7331 } = 7331",
 
-        ":59] (\"Yeah\",) = (",
+        ":60] (\"Yeah\",) = (",
         "    \"Yeah\",",
         ")",
 
-        ":62] 1 = 1",
-        ":62] 2 = 2",
+        ":63] 1 = 1",
+        ":63] 2 = 2",
 
-        ":66] 1u8 = 1",
-        ":66] 2u32 = 2",
-        ":66] \"Yeah\" = \"Yeah\"",
+        ":67] 1u8 = 1",
+        ":67] 2u32 = 2",
+        ":67] \"Yeah\" = \"Yeah\"",
     ]);
 }
 
diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed
index ddd9abbd50e..e51ce5d1d5b 100644
--- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed
+++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed
@@ -12,8 +12,11 @@
 
 //~^ ERROR unused extern crate
 
-use edition_lint_paths as bar;
-//~^ ERROR `extern crate` is not idiomatic in the new edition
+// Shouldn't suggest changing to `use`, as `bar`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `bar` in other
+// modules. See #57672.
+extern crate edition_lint_paths as bar;
 
 fn main() {
     // This is not considered to *use* the `extern crate` in Rust 2018:
diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs
index 47674bc19fc..debbf085d61 100644
--- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs
+++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs
@@ -12,8 +12,11 @@
 extern crate edition_lint_paths;
 //~^ ERROR unused extern crate
 
+// Shouldn't suggest changing to `use`, as `bar`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `bar` in other
+// modules. See #57672.
 extern crate edition_lint_paths as bar;
-//~^ ERROR `extern crate` is not idiomatic in the new edition
 
 fn main() {
     // This is not considered to *use* the `extern crate` in Rust 2018:
diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr
index f3f91939486..13980c70a82 100644
--- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr
+++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr
@@ -11,11 +11,5 @@ LL | #![deny(rust_2018_idioms)]
    |         ^^^^^^^^^^^^^^^^
    = note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)]
 
-error: `extern crate` is not idiomatic in the new edition
-  --> $DIR/extern-crate-idiomatic-in-2018.rs:15:1
-   |
-LL | extern crate edition_lint_paths as bar;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/rust-2018/remove-extern-crate.fixed b/src/test/ui/rust-2018/remove-extern-crate.fixed
index 17449caf84f..14575d18c23 100644
--- a/src/test/ui/rust-2018/remove-extern-crate.fixed
+++ b/src/test/ui/rust-2018/remove-extern-crate.fixed
@@ -7,7 +7,11 @@
 #![warn(rust_2018_idioms)]
 
 
-use core as another_name;
+// Shouldn't suggest changing to `use`, as `another_name`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `another_name` in other
+// modules. See #57672.
+extern crate core as another_name;
 use remove_extern_crate;
 #[macro_use]
 extern crate remove_extern_crate as something_else;
diff --git a/src/test/ui/rust-2018/remove-extern-crate.rs b/src/test/ui/rust-2018/remove-extern-crate.rs
index fb2217df000..0ee85f34e40 100644
--- a/src/test/ui/rust-2018/remove-extern-crate.rs
+++ b/src/test/ui/rust-2018/remove-extern-crate.rs
@@ -7,6 +7,10 @@
 #![warn(rust_2018_idioms)]
 
 extern crate core;
+// Shouldn't suggest changing to `use`, as `another_name`
+// would no longer be added to the prelude which could cause
+// compilation errors for imports that use `another_name` in other
+// modules. See #57672.
 extern crate core as another_name;
 use remove_extern_crate;
 #[macro_use]
diff --git a/src/test/ui/rust-2018/remove-extern-crate.stderr b/src/test/ui/rust-2018/remove-extern-crate.stderr
index 549693201b7..5de0dfe9613 100644
--- a/src/test/ui/rust-2018/remove-extern-crate.stderr
+++ b/src/test/ui/rust-2018/remove-extern-crate.stderr
@@ -12,13 +12,7 @@ LL | #![warn(rust_2018_idioms)]
    = note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)]
 
 warning: `extern crate` is not idiomatic in the new edition
-  --> $DIR/remove-extern-crate.rs:10:1
-   |
-LL | extern crate core as another_name;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
-
-warning: `extern crate` is not idiomatic in the new edition
-  --> $DIR/remove-extern-crate.rs:28:5
+  --> $DIR/remove-extern-crate.rs:32:5
    |
 LL |     extern crate core;
    |     ^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
diff --git a/src/test/ui/save-analysis/issue-59134-0.rs b/src/test/ui/save-analysis/issue-59134-0.rs
new file mode 100644
index 00000000000..3158328b3ff
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-59134-0.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Zsave-analysis
+
+// Check that this doesn't ICE when processing associated const (field expr).
+
+pub fn f() {
+    trait Trait {}
+    impl Trait {
+        const FLAG: u32 = bogus.field; //~ ERROR cannot find value `bogus`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/save-analysis/issue-59134-0.stderr b/src/test/ui/save-analysis/issue-59134-0.stderr
new file mode 100644
index 00000000000..4e9b2e6fdeb
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-59134-0.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `bogus` in this scope
+  --> $DIR/issue-59134-0.rs:8:27
+   |
+LL |         const FLAG: u32 = bogus.field;
+   |                           ^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/save-analysis/issue-59134-1.rs b/src/test/ui/save-analysis/issue-59134-1.rs
new file mode 100644
index 00000000000..3cb629777a4
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-59134-1.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Zsave-analysis
+
+// Check that this doesn't ICE when processing associated const (type).
+
+fn func() {
+    trait Trait {
+        type MyType;
+        const CONST: Self::MyType = bogus.field; //~ ERROR cannot find value `bogus`
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/save-analysis/issue-59134-1.stderr b/src/test/ui/save-analysis/issue-59134-1.stderr
new file mode 100644
index 00000000000..bdc335eaac0
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-59134-1.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `bogus` in this scope
+  --> $DIR/issue-59134-1.rs:8:37
+   |
+LL |         const CONST: Self::MyType = bogus.field;
+   |                                     ^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.rs b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
index 2c1fd937a65..2c1fd937a65 100644
--- a/src/test/ui/arbitrary-self-types-not-object-safe.rs
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr
index dacab1222ab..dacab1222ab 100644
--- a/src/test/ui/arbitrary-self-types-not-object-safe.stderr
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.stderr
diff --git a/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs b/src/test/ui/self/arbitrary_self_types_pointers_and_wrappers.rs
index 6904c29111e..65fec3becac 100644
--- a/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/src/test/ui/self/arbitrary_self_types_pointers_and_wrappers.rs
@@ -1,3 +1,4 @@
+// run-pass
 #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
 #![feature(rustc_attrs)]
 
diff --git a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_struct.rs b/src/test/ui/self/arbitrary_self_types_raw_pointer_struct.rs
index 0eab7617f7a..0eab7617f7a 100644
--- a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_struct.rs
+++ b/src/test/ui/self/arbitrary_self_types_raw_pointer_struct.rs
diff --git a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_trait.rs b/src/test/ui/self/arbitrary_self_types_raw_pointer_trait.rs
index acbe896eebe..acbe896eebe 100644
--- a/src/test/run-pass/self/arbitrary_self_types_raw_pointer_trait.rs
+++ b/src/test/ui/self/arbitrary_self_types_raw_pointer_trait.rs
diff --git a/src/test/run-pass/self/arbitrary_self_types_silly.rs b/src/test/ui/self/arbitrary_self_types_silly.rs
index fb5f9012b18..fb5f9012b18 100644
--- a/src/test/run-pass/self/arbitrary_self_types_silly.rs
+++ b/src/test/ui/self/arbitrary_self_types_silly.rs
diff --git a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs b/src/test/ui/self/arbitrary_self_types_stdlib_pointers.rs
index 9f6a647a07b..29563fbbd86 100644
--- a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs
+++ b/src/test/ui/self/arbitrary_self_types_stdlib_pointers.rs
@@ -1,3 +1,4 @@
+// run-pass
 #![feature(arbitrary_self_types)]
 #![feature(rustc_attrs)]
 
diff --git a/src/test/run-pass/self/arbitrary_self_types_struct.rs b/src/test/ui/self/arbitrary_self_types_struct.rs
index cf62cd3a4e6..cf62cd3a4e6 100644
--- a/src/test/run-pass/self/arbitrary_self_types_struct.rs
+++ b/src/test/ui/self/arbitrary_self_types_struct.rs
diff --git a/src/test/run-pass/self/arbitrary_self_types_trait.rs b/src/test/ui/self/arbitrary_self_types_trait.rs
index fb06344df7e..fb06344df7e 100644
--- a/src/test/run-pass/self/arbitrary_self_types_trait.rs
+++ b/src/test/ui/self/arbitrary_self_types_trait.rs
diff --git a/src/test/run-pass/self/arbitrary_self_types_unsized_struct.rs b/src/test/ui/self/arbitrary_self_types_unsized_struct.rs
index b78223fd57c..b78223fd57c 100644
--- a/src/test/run-pass/self/arbitrary_self_types_unsized_struct.rs
+++ b/src/test/ui/self/arbitrary_self_types_unsized_struct.rs
diff --git a/src/test/run-pass/self/auxiliary/explicit_self_xcrate.rs b/src/test/ui/self/auxiliary/explicit_self_xcrate.rs
index 25cdfa90990..25cdfa90990 100644
--- a/src/test/run-pass/self/auxiliary/explicit_self_xcrate.rs
+++ b/src/test/ui/self/auxiliary/explicit_self_xcrate.rs
diff --git a/src/test/run-pass/self/builtin-superkinds-self-type.rs b/src/test/ui/self/builtin-superkinds-self-type.rs
index c56542bb468..c56542bb468 100644
--- a/src/test/run-pass/self/builtin-superkinds-self-type.rs
+++ b/src/test/ui/self/builtin-superkinds-self-type.rs
diff --git a/src/test/run-pass/self/by-value-self-in-mut-slot.rs b/src/test/ui/self/by-value-self-in-mut-slot.rs
index 267afd1dcad..267afd1dcad 100644
--- a/src/test/run-pass/self/by-value-self-in-mut-slot.rs
+++ b/src/test/ui/self/by-value-self-in-mut-slot.rs
diff --git a/src/test/run-pass/self/explicit-self-closures.rs b/src/test/ui/self/explicit-self-closures.rs
index 61be98fe3d3..1217823da11 100644
--- a/src/test/run-pass/self/explicit-self-closures.rs
+++ b/src/test/ui/self/explicit-self-closures.rs
@@ -1,4 +1,4 @@
-// run-pass
+// compile-pass
 #![allow(dead_code)]
 // Test to make sure that explicit self params work inside closures
 
diff --git a/src/test/run-pass/self/explicit-self-generic.rs b/src/test/ui/self/explicit-self-generic.rs
index 03f72a5513c..03f72a5513c 100644
--- a/src/test/run-pass/self/explicit-self-generic.rs
+++ b/src/test/ui/self/explicit-self-generic.rs
diff --git a/src/test/run-pass/self/explicit-self-objects-uniq.rs b/src/test/ui/self/explicit-self-objects-uniq.rs
index f95686cf112..f95686cf112 100644
--- a/src/test/run-pass/self/explicit-self-objects-uniq.rs
+++ b/src/test/ui/self/explicit-self-objects-uniq.rs
diff --git a/src/test/run-pass/self/explicit-self.rs b/src/test/ui/self/explicit-self.rs
index 6d19d33b6fe..6d19d33b6fe 100644
--- a/src/test/run-pass/self/explicit-self.rs
+++ b/src/test/ui/self/explicit-self.rs
diff --git a/src/test/run-pass/self/explicit_self_xcrate_exe.rs b/src/test/ui/self/explicit_self_xcrate_exe.rs
index c3796f73ab5..c3796f73ab5 100644
--- a/src/test/run-pass/self/explicit_self_xcrate_exe.rs
+++ b/src/test/ui/self/explicit_self_xcrate_exe.rs
diff --git a/src/test/run-pass/self/move-self.rs b/src/test/ui/self/move-self.rs
index 66032780b81..66032780b81 100644
--- a/src/test/run-pass/self/move-self.rs
+++ b/src/test/ui/self/move-self.rs
diff --git a/src/test/run-pass/self/object-safety-sized-self-by-value-self.rs b/src/test/ui/self/object-safety-sized-self-by-value-self.rs
index ae0512666ce..ae0512666ce 100644
--- a/src/test/run-pass/self/object-safety-sized-self-by-value-self.rs
+++ b/src/test/ui/self/object-safety-sized-self-by-value-self.rs
diff --git a/src/test/run-pass/self/object-safety-sized-self-generic-method.rs b/src/test/ui/self/object-safety-sized-self-generic-method.rs
index 0b3f6633737..0b3f6633737 100644
--- a/src/test/run-pass/self/object-safety-sized-self-generic-method.rs
+++ b/src/test/ui/self/object-safety-sized-self-generic-method.rs
diff --git a/src/test/run-pass/self/object-safety-sized-self-return-Self.rs b/src/test/ui/self/object-safety-sized-self-return-Self.rs
index e88dba0a4e8..e88dba0a4e8 100644
--- a/src/test/run-pass/self/object-safety-sized-self-return-Self.rs
+++ b/src/test/ui/self/object-safety-sized-self-return-Self.rs
diff --git a/src/test/run-pass/self/self-impl.rs b/src/test/ui/self/self-impl-2.rs
index 23d513e3fac..23d513e3fac 100644
--- a/src/test/run-pass/self/self-impl.rs
+++ b/src/test/ui/self/self-impl-2.rs
diff --git a/src/test/run-pass/self/self-in-mut-slot-default-method.rs b/src/test/ui/self/self-in-mut-slot-default-method.rs
index 82c5f58f020..82c5f58f020 100644
--- a/src/test/run-pass/self/self-in-mut-slot-default-method.rs
+++ b/src/test/ui/self/self-in-mut-slot-default-method.rs
diff --git a/src/test/run-pass/self/self-in-mut-slot-immediate-value.rs b/src/test/ui/self/self-in-mut-slot-immediate-value.rs
index 60865304f1c..60865304f1c 100644
--- a/src/test/run-pass/self/self-in-mut-slot-immediate-value.rs
+++ b/src/test/ui/self/self-in-mut-slot-immediate-value.rs
diff --git a/src/test/run-pass/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs
index 9c0906013fa..e4fe7324ef3 100644
--- a/src/test/run-pass/self/self-in-typedefs.rs
+++ b/src/test/ui/self/self-in-typedefs.rs
@@ -1,4 +1,4 @@
-// run-pass
+// compile-pass
 
 #![feature(untagged_unions)]
 
diff --git a/src/test/run-pass/self/self-re-assign.rs b/src/test/ui/self/self-re-assign.rs
index a7b089ebff4..a7b089ebff4 100644
--- a/src/test/run-pass/self/self-re-assign.rs
+++ b/src/test/ui/self/self-re-assign.rs
diff --git a/src/test/run-pass/self/self-shadowing-import.rs b/src/test/ui/self/self-shadowing-import.rs
index 1d60c6c2276..1d60c6c2276 100644
--- a/src/test/run-pass/self/self-shadowing-import.rs
+++ b/src/test/ui/self/self-shadowing-import.rs
diff --git a/src/test/run-pass/self/self-type-param.rs b/src/test/ui/self/self-type-param.rs
index 6deae5f2d12..57e01caa692 100644
--- a/src/test/run-pass/self/self-type-param.rs
+++ b/src/test/ui/self/self-type-param.rs
@@ -1,4 +1,4 @@
-// run-pass
+// compile-pass
 #![allow(dead_code)]
 // pretty-expanded FIXME #23616
 
diff --git a/src/test/run-pass/self/string-self-append.rs b/src/test/ui/self/string-self-append.rs
index e63dc0090cb..e63dc0090cb 100644
--- a/src/test/run-pass/self/string-self-append.rs
+++ b/src/test/ui/self/string-self-append.rs
diff --git a/src/test/run-pass/self/ufcs-explicit-self.rs b/src/test/ui/self/ufcs-explicit-self.rs
index 4e2405504f0..4e2405504f0 100644
--- a/src/test/run-pass/self/ufcs-explicit-self.rs
+++ b/src/test/ui/self/ufcs-explicit-self.rs
diff --git a/src/test/run-pass/self/uniq-self-in-mut-slot.rs b/src/test/ui/self/uniq-self-in-mut-slot.rs
index 695f06ecdda..695f06ecdda 100644
--- a/src/test/run-pass/self/uniq-self-in-mut-slot.rs
+++ b/src/test/ui/self/uniq-self-in-mut-slot.rs
diff --git a/src/test/run-pass/self/where-for-self.rs b/src/test/ui/self/where-for-self.rs
index 76c592dc49b..76c592dc49b 100644
--- a/src/test/run-pass/self/where-for-self.rs
+++ b/src/test/ui/self/where-for-self.rs
diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs
index 6dbc8d39976..a3b1d1d8179 100644
--- a/src/test/ui/span/issue-39018.rs
+++ b/src/test/ui/span/issue-39018.rs
@@ -16,3 +16,23 @@ enum World {
     Hello,
     Goodbye,
 }
+
+fn foo() {
+    let a = String::new();
+    let b = String::new();
+    let c = "";
+    let d = "";
+    let e = &a;
+    let _ = &a + &b; //~ ERROR binary operation
+    let _ = &a + b; //~ ERROR binary operation
+    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
+}
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index a5b91f090d2..d8fbf841b61 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str`
 LL |     let x = "Hello " + "World!";
    |             -------- ^ -------- &str
    |             |        |
-   |             |        `+` can't be used to concatenate two `&str` strings
+   |             |        `+` cannot be used to concatenate two `&str` strings
    |             &str
 help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
    |
@@ -25,16 +25,152 @@ error[E0369]: binary operation `+` cannot be applied to type `&str`
   --> $DIR/issue-39018.rs:11:22
    |
 LL |     let x = "Hello " + "World!".to_owned();
-   |             ---------^--------------------
-   |             |          |
-   |             |          std::string::String
+   |             -------- ^ ------------------- std::string::String
+   |             |        |
+   |             |        `+` cannot be used to concatenate a `&str` with a `String`
    |             &str
-   |             `+` can't be used to concatenate a `&str` with a `String`
 help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
    |
 LL |     let x = "Hello ".to_owned() + &"World!".to_owned();
    |             ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+  --> $DIR/issue-39018.rs:26:16
+   |
+LL |     let _ = &a + &b;
+   |             -- ^ -- &std::string::String
+   |             |  |
+   |             |  `+` cannot be used to concatenate two `&str` strings
+   |             &std::string::String
+help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = a + &b;
+   |             ^
+
+error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+  --> $DIR/issue-39018.rs:27:16
+   |
+LL |     let _ = &a + b;
+   |             -- ^ - std::string::String
+   |             |  |
+   |             |  `+` cannot be used to concatenate a `&str` with a `String`
+   |             &std::string::String
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = a + &b;
+   |             ^   ^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-39018.rs:29:17
+   |
+LL |     let _ = a + b;
+   |                 ^
+   |                 |
+   |                 expected &str, found struct `std::string::String`
+   |                 help: consider borrowing here: `&b`
+   |
+   = note: expected type `&str`
+              found type `std::string::String`
+
+error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+  --> $DIR/issue-39018.rs:30:15
+   |
+LL |     let _ = e + b;
+   |             - ^ - std::string::String
+   |             | |
+   |             | `+` cannot be used to concatenate a `&str` with a `String`
+   |             &std::string::String
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = e.to_owned() + &b;
+   |             ^^^^^^^^^^^^   ^^
+
+error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+  --> $DIR/issue-39018.rs:31:15
+   |
+LL |     let _ = e + &b;
+   |             - ^ -- &std::string::String
+   |             | |
+   |             | `+` cannot be used to concatenate two `&str` strings
+   |             &std::string::String
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = e.to_owned() + &b;
+   |             ^^^^^^^^^^^^
+
+error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+  --> $DIR/issue-39018.rs:32:15
+   |
+LL |     let _ = e + d;
+   |             - ^ - &str
+   |             | |
+   |             | `+` cannot be used to concatenate two `&str` strings
+   |             &std::string::String
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = e.to_owned() + d;
+   |             ^^^^^^^^^^^^
+
+error[E0369]: binary operation `+` cannot be applied to type `&std::string::String`
+  --> $DIR/issue-39018.rs:33:15
+   |
+LL |     let _ = e + &d;
+   |             - ^ -- &&str
+   |             | |
+   |             | `+` cannot be used to concatenate two `&str` strings
+   |             &std::string::String
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = e.to_owned() + &d;
+   |             ^^^^^^^^^^^^
+
+error[E0369]: binary operation `+` cannot be applied to type `&&str`
+  --> $DIR/issue-39018.rs:34:16
+   |
+LL |     let _ = &c + &d;
+   |             -- ^ -- &&str
+   |             |
+   |             &&str
+   |
+   = note: an implementation of `std::ops::Add` might be missing for `&&str`
+
+error[E0369]: binary operation `+` cannot be applied to type `&&str`
+  --> $DIR/issue-39018.rs:35:16
+   |
+LL |     let _ = &c + d;
+   |             -- ^ - &str
+   |             |
+   |             &&str
+   |
+   = note: an implementation of `std::ops::Add` might be missing for `&&str`
+
+error[E0369]: binary operation `+` cannot be applied to type `&str`
+  --> $DIR/issue-39018.rs:36:15
+   |
+LL |     let _ = c + &d;
+   |             - ^ -- &&str
+   |             | |
+   |             | `+` cannot be used to concatenate two `&str` strings
+   |             &str
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = c.to_owned() + &d;
+   |             ^^^^^^^^^^^^
+
+error[E0369]: binary operation `+` cannot be applied to type `&str`
+  --> $DIR/issue-39018.rs:37:15
+   |
+LL |     let _ = c + d;
+   |             - ^ - &str
+   |             | |
+   |             | `+` cannot be used to concatenate two `&str` strings
+   |             &str
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+LL |     let _ = c.to_owned() + d;
+   |             ^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0369`.
+Some errors have detailed explanations: E0308, E0369.
+For more information about an error, try `rustc --explain E0308`.
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 61ebcfdefc3..3e53cdc4d98 100644
--- a/src/test/ui/str/str-concat-on-double-ref.stderr
+++ b/src/test/ui/str/str-concat-on-double-ref.stderr
@@ -3,10 +3,13 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri
    |
 LL |     let c = a + b;
    |             - ^ - &str
-   |             |
+   |             | |
+   |             | `+` cannot be used to concatenate two `&str` strings
    |             &std::string::String
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
    |
-   = note: an implementation of `std::ops::Add` might be missing for `&std::string::String`
+LL |     let c = a.to_owned() + b;
+   |             ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs
index 4faede35305..1c1230346a5 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs
+++ b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 #[derive(Clone)]
 enum Either {
     One(X),
diff --git a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr
index b1aaab6a754..f8e043fbfdf 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/duplicate-suggestions.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:41:27
+  --> $DIR/duplicate-suggestions.rs:39:27
    |
 LL |     let &(X(_t), X(_u)) = &(x.clone(), x.clone());
    |         ---------------   ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -9,13 +9,13 @@ LL |     let &(X(_t), X(_u)) = &(x.clone(), x.clone());
    |         help: consider removing the `&`: `(X(_t), X(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:41:13
+  --> $DIR/duplicate-suggestions.rs:39:13
    |
 LL |     let &(X(_t), X(_u)) = &(x.clone(), x.clone());
    |             ^^     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:45:50
+  --> $DIR/duplicate-suggestions.rs:43:50
    |
 LL |     if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
    |            -----------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -25,13 +25,13 @@ LL |     if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) {
    |            help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:45:26
+  --> $DIR/duplicate-suggestions.rs:43:26
    |
 LL |     if let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
    |                          ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:49:53
+  --> $DIR/duplicate-suggestions.rs:47:53
    |
 LL |     while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
    |               -----------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -41,13 +41,13 @@ LL |     while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone())
    |               help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:49:29
+  --> $DIR/duplicate-suggestions.rs:47:29
    |
 LL |     while let &(Either::One(_t), Either::Two(_u)) = &(e.clone(), e.clone()) { }
    |                             ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:53:11
+  --> $DIR/duplicate-suggestions.rs:51:11
    |
 LL |     match &(e.clone(), e.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -61,7 +61,7 @@ LL |         &(Either::Two(_t), Either::One(_u)) => (),
    |                       -- ...and here   -- ...and here
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:55:23
+  --> $DIR/duplicate-suggestions.rs:53:23
    |
 LL |         &(Either::One(_t), Either::Two(_u)) => (),
    |                       ^^               ^^
@@ -78,7 +78,7 @@ LL |         (Either::Two(_t), Either::One(_u)) => (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:63:11
+  --> $DIR/duplicate-suggestions.rs:61:11
    |
 LL |     match &(e.clone(), e.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -91,13 +91,13 @@ LL |         &(Either::One(_t), Either::Two(_u))
    |         help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:65:23
+  --> $DIR/duplicate-suggestions.rs:63:23
    |
 LL |         &(Either::One(_t), Either::Two(_u))
    |                       ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:72:11
+  --> $DIR/duplicate-suggestions.rs:70:11
    |
 LL |     match &(e.clone(), e.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -110,13 +110,13 @@ LL |         &(Either::One(_t), Either::Two(_u)) => (),
    |         help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:74:23
+  --> $DIR/duplicate-suggestions.rs:72:23
    |
 LL |         &(Either::One(_t), Either::Two(_u)) => (),
    |                       ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:80:11
+  --> $DIR/duplicate-suggestions.rs:78:11
    |
 LL |     match &(e.clone(), e.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -129,13 +129,13 @@ LL |         &(Either::One(_t), Either::Two(_u)) => (),
    |         help: consider removing the `&`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:82:23
+  --> $DIR/duplicate-suggestions.rs:80:23
    |
 LL |         &(Either::One(_t), Either::Two(_u)) => (),
    |                       ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:93:31
+  --> $DIR/duplicate-suggestions.rs:91:31
    |
 LL |     let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
    |         -------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -145,13 +145,13 @@ LL |     let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
    |         help: consider removing the `&mut`: `(X(_t), X(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:93:17
+  --> $DIR/duplicate-suggestions.rs:91:17
    |
 LL |     let &mut (X(_t), X(_u)) = &mut (xm.clone(), xm.clone());
    |                 ^^     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:97:54
+  --> $DIR/duplicate-suggestions.rs:95:54
    |
 LL |     if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
    |            ---------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -161,13 +161,13 @@ LL |     if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.c
    |            help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:97:30
+  --> $DIR/duplicate-suggestions.rs:95:30
    |
 LL |     if let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
    |                              ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:101:57
+  --> $DIR/duplicate-suggestions.rs:99:57
    |
 LL |     while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
    |               ---------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -177,13 +177,13 @@ LL |     while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), e
    |               help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:101:33
+  --> $DIR/duplicate-suggestions.rs:99:33
    |
 LL |     while let &mut (Either::One(_t), Either::Two(_u)) = &mut (em.clone(), em.clone()) { }
    |                                 ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:105:11
+  --> $DIR/duplicate-suggestions.rs:103:11
    |
 LL |     match &mut (em.clone(), em.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -197,7 +197,7 @@ LL |         &mut (Either::Two(_t), Either::One(_u)) => (),
    |                           -- ...and here   -- ...and here
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:107:27
+  --> $DIR/duplicate-suggestions.rs:105:27
    |
 LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |                           ^^               ^^
@@ -214,7 +214,7 @@ LL |         (Either::Two(_t), Either::One(_u)) => (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:115:11
+  --> $DIR/duplicate-suggestions.rs:113:11
    |
 LL |     match &mut (em.clone(), em.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -227,13 +227,13 @@ LL |         &mut (Either::One(_t), Either::Two(_u))
    |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:117:27
+  --> $DIR/duplicate-suggestions.rs:115:27
    |
 LL |         &mut (Either::One(_t), Either::Two(_u))
    |                           ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:124:11
+  --> $DIR/duplicate-suggestions.rs:122:11
    |
 LL |     match &mut (em.clone(), em.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -246,13 +246,13 @@ LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:126:27
+  --> $DIR/duplicate-suggestions.rs:124:27
    |
 LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |                           ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:132:11
+  --> $DIR/duplicate-suggestions.rs:130:11
    |
 LL |     match &mut (em.clone(), em.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -265,13 +265,13 @@ LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:134:27
+  --> $DIR/duplicate-suggestions.rs:132:27
    |
 LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |                           ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:140:11
+  --> $DIR/duplicate-suggestions.rs:138:11
    |
 LL |     match &mut (em.clone(), em.clone()) {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -284,13 +284,13 @@ LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |         help: consider removing the `&mut`: `(Either::One(_t), Either::Two(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:142:27
+  --> $DIR/duplicate-suggestions.rs:140:27
    |
 LL |         &mut (Either::One(_t), Either::Two(_u)) => (),
    |                           ^^               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:88:11
+  --> $DIR/duplicate-suggestions.rs:86:11
    |
 LL |     fn f5(&(X(_t), X(_u)): &(X, X)) { }
    |           ^^^^--^^^^^--^^
@@ -301,13 +301,13 @@ LL |     fn f5(&(X(_t), X(_u)): &(X, X)) { }
    |           help: consider removing the `&`: `(X(_t), X(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:88:15
+  --> $DIR/duplicate-suggestions.rs:86:15
    |
 LL |     fn f5(&(X(_t), X(_u)): &(X, X)) { }
    |               ^^     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/duplicate-suggestions.rs:148:11
+  --> $DIR/duplicate-suggestions.rs:146:11
    |
 LL |     fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
    |           ^^^^^^^^--^^^^^--^^
@@ -318,7 +318,7 @@ LL |     fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
    |           help: consider removing the `&mut`: `(X(_t), X(_u))`
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/duplicate-suggestions.rs:148:19
+  --> $DIR/duplicate-suggestions.rs:146:19
    |
 LL |     fn f6(&mut (X(_t), X(_u)): &mut (X, X)) { }
    |                   ^^     ^^
diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs
index 90a9fe4e7d0..6e3879a4155 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs
+++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 #[derive(Clone)]
 enum Either {
     One(X),
diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
index f1d515e932c..74f3a63be57 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:30:21
+  --> $DIR/move-into-closure.rs:28:21
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -12,13 +12,13 @@ LL |         let X(_t) = x;
    |               data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:30:15
+  --> $DIR/move-into-closure.rs:28:15
    |
 LL |         let X(_t) = x;
    |               ^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:34:34
+  --> $DIR/move-into-closure.rs:32:34
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -31,13 +31,13 @@ LL |         if let Either::One(_t) = e { }
    |                            data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:34:28
+  --> $DIR/move-into-closure.rs:32:28
    |
 LL |         if let Either::One(_t) = e { }
    |                            ^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:38:37
+  --> $DIR/move-into-closure.rs:36:37
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -50,13 +50,13 @@ LL |         while let Either::One(_t) = e { }
    |                               data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:38:31
+  --> $DIR/move-into-closure.rs:36:31
    |
 LL |         while let Either::One(_t) = e { }
    |                               ^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:42:15
+  --> $DIR/move-into-closure.rs:40:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -71,13 +71,13 @@ LL |             Either::One(_t)
    |                         -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:46:25
+  --> $DIR/move-into-closure.rs:44:25
    |
 LL |             Either::One(_t)
    |                         ^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:49:15
+  --> $DIR/move-into-closure.rs:47:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -92,13 +92,13 @@ LL |             Either::One(_t) => (),
    |                         -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:53:25
+  --> $DIR/move-into-closure.rs:51:25
    |
 LL |             Either::One(_t) => (),
    |                         ^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:58:25
+  --> $DIR/move-into-closure.rs:56:25
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -111,13 +111,13 @@ LL |         let X(mut _t) = x;
    |               data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:58:15
+  --> $DIR/move-into-closure.rs:56:15
    |
 LL |         let X(mut _t) = x;
    |               ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:62:38
+  --> $DIR/move-into-closure.rs:60:38
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -130,13 +130,13 @@ LL |         if let Either::One(mut _t) = em { }
    |                            data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:62:28
+  --> $DIR/move-into-closure.rs:60:28
    |
 LL |         if let Either::One(mut _t) = em { }
    |                            ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:66:41
+  --> $DIR/move-into-closure.rs:64:41
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -149,13 +149,13 @@ LL |         while let Either::One(mut _t) = em { }
    |                               data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:66:31
+  --> $DIR/move-into-closure.rs:64:31
    |
 LL |         while let Either::One(mut _t) = em { }
    |                               ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:70:15
+  --> $DIR/move-into-closure.rs:68:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -170,13 +170,13 @@ LL |             Either::One(mut _t)
    |                         ------ data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:74:25
+  --> $DIR/move-into-closure.rs:72:25
    |
 LL |             Either::One(mut _t)
    |                         ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `Fn` closure
-  --> $DIR/move-into-closure.rs:77:15
+  --> $DIR/move-into-closure.rs:75:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -191,13 +191,13 @@ LL |             Either::One(mut _t) => (),
    |                         ------ data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:81:25
+  --> $DIR/move-into-closure.rs:79:25
    |
 LL |             Either::One(mut _t) => (),
    |                         ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:97:21
+  --> $DIR/move-into-closure.rs:95:21
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -210,13 +210,13 @@ LL |         let X(_t) = x;
    |               data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:97:15
+  --> $DIR/move-into-closure.rs:95:15
    |
 LL |         let X(_t) = x;
    |               ^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:101:34
+  --> $DIR/move-into-closure.rs:99:34
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -229,13 +229,13 @@ LL |         if let Either::One(_t) = e { }
    |                            data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:101:28
+  --> $DIR/move-into-closure.rs:99:28
    |
 LL |         if let Either::One(_t) = e { }
    |                            ^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:105:37
+  --> $DIR/move-into-closure.rs:103:37
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -248,13 +248,13 @@ LL |         while let Either::One(_t) = e { }
    |                               data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:105:31
+  --> $DIR/move-into-closure.rs:103:31
    |
 LL |         while let Either::One(_t) = e { }
    |                               ^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:109:15
+  --> $DIR/move-into-closure.rs:107:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -269,13 +269,13 @@ LL |             Either::One(_t)
    |                         -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:113:25
+  --> $DIR/move-into-closure.rs:111:25
    |
 LL |             Either::One(_t)
    |                         ^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:116:15
+  --> $DIR/move-into-closure.rs:114:15
    |
 LL |     let e = Either::One(X(Y));
    |         - captured outer variable
@@ -290,13 +290,13 @@ LL |             Either::One(_t) => (),
    |                         -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:120:25
+  --> $DIR/move-into-closure.rs:118:25
    |
 LL |             Either::One(_t) => (),
    |                         ^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:125:25
+  --> $DIR/move-into-closure.rs:123:25
    |
 LL |     let x = X(Y);
    |         - captured outer variable
@@ -309,13 +309,13 @@ LL |         let X(mut _t) = x;
    |               data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:125:15
+  --> $DIR/move-into-closure.rs:123:15
    |
 LL |         let X(mut _t) = x;
    |               ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:129:38
+  --> $DIR/move-into-closure.rs:127:38
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -328,13 +328,13 @@ LL |         if let Either::One(mut _t) = em { }
    |                            data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:129:28
+  --> $DIR/move-into-closure.rs:127:28
    |
 LL |         if let Either::One(mut _t) = em { }
    |                            ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:133:41
+  --> $DIR/move-into-closure.rs:131:41
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -347,13 +347,13 @@ LL |         while let Either::One(mut _t) = em { }
    |                               data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:133:31
+  --> $DIR/move-into-closure.rs:131:31
    |
 LL |         while let Either::One(mut _t) = em { }
    |                               ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:137:15
+  --> $DIR/move-into-closure.rs:135:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -368,13 +368,13 @@ LL |             Either::One(mut _t)
    |                         ------ data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:141:25
+  --> $DIR/move-into-closure.rs:139:25
    |
 LL |             Either::One(mut _t)
    |                         ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:144:15
+  --> $DIR/move-into-closure.rs:142:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -389,13 +389,13 @@ LL |             Either::One(mut _t) => (),
    |                         ------ data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:148:25
+  --> $DIR/move-into-closure.rs:146:25
    |
 LL |             Either::One(mut _t) => (),
    |                         ^^^^^^
 
 error[E0507]: cannot move out of captured variable in an `FnMut` closure
-  --> $DIR/move-into-closure.rs:152:15
+  --> $DIR/move-into-closure.rs:150:15
    |
 LL |     let mut em = Either::One(X(Y));
    |         ------ captured outer variable
@@ -410,7 +410,7 @@ LL |             Either::One(mut _t) => (),
    |                         ------ data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/move-into-closure.rs:156:25
+  --> $DIR/move-into-closure.rs:154:25
    |
 LL |             Either::One(mut _t) => (),
    |                         ^^^^^^
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.rs b/src/test/ui/suggestions/dont-suggest-ref/simple.rs
index 58aab85ac26..31ab1a6639a 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/simple.rs
+++ b/src/test/ui/suggestions/dont-suggest-ref/simple.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 #[derive(Clone)]
 enum Either {
     One(X),
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
index 6a8b17ca870..7f2ba4da714 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:40:17
+  --> $DIR/simple.rs:38:17
    |
 LL |     let X(_t) = *s;
    |           --    ^^
@@ -9,13 +9,13 @@ LL |     let X(_t) = *s;
    |           data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:40:11
+  --> $DIR/simple.rs:38:11
    |
 LL |     let X(_t) = *s;
    |           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:44:30
+  --> $DIR/simple.rs:42:30
    |
 LL |     if let Either::One(_t) = *r { }
    |                        --    ^^
@@ -25,13 +25,13 @@ LL |     if let Either::One(_t) = *r { }
    |                        data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:44:24
+  --> $DIR/simple.rs:42:24
    |
 LL |     if let Either::One(_t) = *r { }
    |                        ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:48:33
+  --> $DIR/simple.rs:46:33
    |
 LL |     while let Either::One(_t) = *r { }
    |                           --    ^^
@@ -41,13 +41,13 @@ LL |     while let Either::One(_t) = *r { }
    |                           data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:48:27
+  --> $DIR/simple.rs:46:27
    |
 LL |     while let Either::One(_t) = *r { }
    |                           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:52:11
+  --> $DIR/simple.rs:50:11
    |
 LL |     match *r {
    |           ^^
@@ -59,13 +59,13 @@ LL |         Either::One(_t)
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:56:21
+  --> $DIR/simple.rs:54:21
    |
 LL |         Either::One(_t)
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:59:11
+  --> $DIR/simple.rs:57:11
    |
 LL |     match *r {
    |           ^^
@@ -77,13 +77,13 @@ LL |         Either::One(_t) => (),
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:63:21
+  --> $DIR/simple.rs:61:21
    |
 LL |         Either::One(_t) => (),
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:68:17
+  --> $DIR/simple.rs:66:17
    |
 LL |     let X(_t) = *sm;
    |           --    ^^^
@@ -93,13 +93,13 @@ LL |     let X(_t) = *sm;
    |           data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:68:11
+  --> $DIR/simple.rs:66:11
    |
 LL |     let X(_t) = *sm;
    |           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:72:30
+  --> $DIR/simple.rs:70:30
    |
 LL |     if let Either::One(_t) = *rm { }
    |                        --    ^^^
@@ -109,13 +109,13 @@ LL |     if let Either::One(_t) = *rm { }
    |                        data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:72:24
+  --> $DIR/simple.rs:70:24
    |
 LL |     if let Either::One(_t) = *rm { }
    |                        ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:76:33
+  --> $DIR/simple.rs:74:33
    |
 LL |     while let Either::One(_t) = *rm { }
    |                           --    ^^^
@@ -125,13 +125,13 @@ LL |     while let Either::One(_t) = *rm { }
    |                           data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:76:27
+  --> $DIR/simple.rs:74:27
    |
 LL |     while let Either::One(_t) = *rm { }
    |                           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:80:11
+  --> $DIR/simple.rs:78:11
    |
 LL |     match *rm {
    |           ^^^
@@ -143,13 +143,13 @@ LL |         Either::One(_t)
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:84:21
+  --> $DIR/simple.rs:82:21
    |
 LL |         Either::One(_t)
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:87:11
+  --> $DIR/simple.rs:85:11
    |
 LL |     match *rm {
    |           ^^^
@@ -161,13 +161,13 @@ LL |         Either::One(_t) => (),
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:91:21
+  --> $DIR/simple.rs:89:21
    |
 LL |         Either::One(_t) => (),
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:95:11
+  --> $DIR/simple.rs:93:11
    |
 LL |     match *rm {
    |           ^^^
@@ -179,13 +179,13 @@ LL |         Either::One(_t) => (),
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:99:21
+  --> $DIR/simple.rs:97:21
    |
 LL |         Either::One(_t) => (),
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:104:17
+  --> $DIR/simple.rs:102:17
    |
 LL |     let X(_t) = vs[0];
    |           --    ^^^^^
@@ -195,13 +195,13 @@ LL |     let X(_t) = vs[0];
    |           data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:104:11
+  --> $DIR/simple.rs:102:11
    |
 LL |     let X(_t) = vs[0];
    |           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:108:30
+  --> $DIR/simple.rs:106:30
    |
 LL |     if let Either::One(_t) = vr[0] { }
    |                        --    ^^^^^
@@ -211,13 +211,13 @@ LL |     if let Either::One(_t) = vr[0] { }
    |                        data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:108:24
+  --> $DIR/simple.rs:106:24
    |
 LL |     if let Either::One(_t) = vr[0] { }
    |                        ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:112:33
+  --> $DIR/simple.rs:110:33
    |
 LL |     while let Either::One(_t) = vr[0] { }
    |                           --    ^^^^^
@@ -227,13 +227,13 @@ LL |     while let Either::One(_t) = vr[0] { }
    |                           data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:112:27
+  --> $DIR/simple.rs:110:27
    |
 LL |     while let Either::One(_t) = vr[0] { }
    |                           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:116:11
+  --> $DIR/simple.rs:114:11
    |
 LL |     match vr[0] {
    |           ^^^^^
@@ -245,13 +245,13 @@ LL |         Either::One(_t)
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:120:21
+  --> $DIR/simple.rs:118:21
    |
 LL |         Either::One(_t)
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:123:11
+  --> $DIR/simple.rs:121:11
    |
 LL |     match vr[0] {
    |           ^^^^^
@@ -263,13 +263,13 @@ LL |         Either::One(_t) => (),
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:127:21
+  --> $DIR/simple.rs:125:21
    |
 LL |         Either::One(_t) => (),
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:132:17
+  --> $DIR/simple.rs:130:17
    |
 LL |     let X(_t) = vsm[0];
    |           --    ^^^^^^
@@ -279,13 +279,13 @@ LL |     let X(_t) = vsm[0];
    |           data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:132:11
+  --> $DIR/simple.rs:130:11
    |
 LL |     let X(_t) = vsm[0];
    |           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:136:30
+  --> $DIR/simple.rs:134:30
    |
 LL |     if let Either::One(_t) = vrm[0] { }
    |                        --    ^^^^^^
@@ -295,13 +295,13 @@ LL |     if let Either::One(_t) = vrm[0] { }
    |                        data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:136:24
+  --> $DIR/simple.rs:134:24
    |
 LL |     if let Either::One(_t) = vrm[0] { }
    |                        ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:140:33
+  --> $DIR/simple.rs:138:33
    |
 LL |     while let Either::One(_t) = vrm[0] { }
    |                           --    ^^^^^^
@@ -311,13 +311,13 @@ LL |     while let Either::One(_t) = vrm[0] { }
    |                           data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:140:27
+  --> $DIR/simple.rs:138:27
    |
 LL |     while let Either::One(_t) = vrm[0] { }
    |                           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:144:11
+  --> $DIR/simple.rs:142:11
    |
 LL |     match vrm[0] {
    |           ^^^^^^
@@ -329,13 +329,13 @@ LL |         Either::One(_t)
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:148:21
+  --> $DIR/simple.rs:146:21
    |
 LL |         Either::One(_t)
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:151:11
+  --> $DIR/simple.rs:149:11
    |
 LL |     match vrm[0] {
    |           ^^^^^^
@@ -347,13 +347,13 @@ LL |         Either::One(_t) => (),
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:155:21
+  --> $DIR/simple.rs:153:21
    |
 LL |         Either::One(_t) => (),
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:159:11
+  --> $DIR/simple.rs:157:11
    |
 LL |     match vrm[0] {
    |           ^^^^^^
@@ -365,13 +365,13 @@ LL |         Either::One(_t) => (),
    |                     -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:163:21
+  --> $DIR/simple.rs:161:21
    |
 LL |         Either::One(_t) => (),
    |                     ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:170:18
+  --> $DIR/simple.rs:168:18
    |
 LL |     let &X(_t) = s;
    |         ------   ^ cannot move out of borrowed content
@@ -380,13 +380,13 @@ LL |     let &X(_t) = s;
    |         help: consider removing the `&`: `X(_t)`
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:170:12
+  --> $DIR/simple.rs:168:12
    |
 LL |     let &X(_t) = s;
    |            ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:174:31
+  --> $DIR/simple.rs:172:31
    |
 LL |     if let &Either::One(_t) = r { }
    |            ----------------   ^ cannot move out of borrowed content
@@ -395,13 +395,13 @@ LL |     if let &Either::One(_t) = r { }
    |            help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:174:25
+  --> $DIR/simple.rs:172:25
    |
 LL |     if let &Either::One(_t) = r { }
    |                         ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:178:34
+  --> $DIR/simple.rs:176:34
    |
 LL |     while let &Either::One(_t) = r { }
    |               ----------------   ^ cannot move out of borrowed content
@@ -410,13 +410,13 @@ LL |     while let &Either::One(_t) = r { }
    |               help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:178:28
+  --> $DIR/simple.rs:176:28
    |
 LL |     while let &Either::One(_t) = r { }
    |                            ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:182:11
+  --> $DIR/simple.rs:180:11
    |
 LL |     match r {
    |           ^ cannot move out of borrowed content
@@ -428,13 +428,13 @@ LL |         &Either::One(_t)
    |         help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:184:22
+  --> $DIR/simple.rs:182:22
    |
 LL |         &Either::One(_t)
    |                      ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:190:11
+  --> $DIR/simple.rs:188:11
    |
 LL |     match r {
    |           ^ cannot move out of borrowed content
@@ -446,13 +446,13 @@ LL |         &Either::One(_t) => (),
    |         help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:192:22
+  --> $DIR/simple.rs:190:22
    |
 LL |         &Either::One(_t) => (),
    |                      ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:197:11
+  --> $DIR/simple.rs:195:11
    |
 LL |     match r {
    |           ^ cannot move out of borrowed content
@@ -464,13 +464,13 @@ LL |         &Either::One(_t) => (),
    |         help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:199:22
+  --> $DIR/simple.rs:197:22
    |
 LL |         &Either::One(_t) => (),
    |                      ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:209:22
+  --> $DIR/simple.rs:207:22
    |
 LL |     let &mut X(_t) = sm;
    |         ----------   ^^ cannot move out of borrowed content
@@ -479,13 +479,13 @@ LL |     let &mut X(_t) = sm;
    |         help: consider removing the `&mut`: `X(_t)`
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:209:16
+  --> $DIR/simple.rs:207:16
    |
 LL |     let &mut X(_t) = sm;
    |                ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:213:35
+  --> $DIR/simple.rs:211:35
    |
 LL |     if let &mut Either::One(_t) = rm { }
    |            --------------------   ^^ cannot move out of borrowed content
@@ -494,13 +494,13 @@ LL |     if let &mut Either::One(_t) = rm { }
    |            help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:213:29
+  --> $DIR/simple.rs:211:29
    |
 LL |     if let &mut Either::One(_t) = rm { }
    |                             ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:217:38
+  --> $DIR/simple.rs:215:38
    |
 LL |     while let &mut Either::One(_t) = rm { }
    |               --------------------   ^^ cannot move out of borrowed content
@@ -509,13 +509,13 @@ LL |     while let &mut Either::One(_t) = rm { }
    |               help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:217:32
+  --> $DIR/simple.rs:215:32
    |
 LL |     while let &mut Either::One(_t) = rm { }
    |                                ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:221:11
+  --> $DIR/simple.rs:219:11
    |
 LL |     match rm {
    |           ^^ cannot move out of borrowed content
@@ -527,7 +527,7 @@ LL |         &mut Either::Two(_t) => (),
    |                          -- ...and here
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/simple.rs:223:26
+  --> $DIR/simple.rs:221:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
@@ -544,7 +544,7 @@ LL |         Either::Two(_t) => (),
    |         ^^^^^^^^^^^^^^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:230:11
+  --> $DIR/simple.rs:228:11
    |
 LL |     match rm {
    |           ^^ cannot move out of borrowed content
@@ -556,13 +556,13 @@ LL |         &mut Either::One(_t) => (),
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:232:26
+  --> $DIR/simple.rs:230:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:237:11
+  --> $DIR/simple.rs:235:11
    |
 LL |     match rm {
    |           ^^ cannot move out of borrowed content
@@ -574,13 +574,13 @@ LL |         &mut Either::One(_t) => (),
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:239:26
+  --> $DIR/simple.rs:237:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:244:11
+  --> $DIR/simple.rs:242:11
    |
 LL |     match rm {
    |           ^^ cannot move out of borrowed content
@@ -592,13 +592,13 @@ LL |         &mut Either::One(_t) => (),
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:246:26
+  --> $DIR/simple.rs:244:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:260:21
+  --> $DIR/simple.rs:258:21
    |
 LL |     let (&X(_t),) = (&x.clone(),);
    |             --      ^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -606,13 +606,13 @@ LL |     let (&X(_t),) = (&x.clone(),);
    |             data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:260:13
+  --> $DIR/simple.rs:258:13
    |
 LL |     let (&X(_t),) = (&x.clone(),);
    |             ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:262:34
+  --> $DIR/simple.rs:260:34
    |
 LL |     if let (&Either::One(_t),) = (&e.clone(),) { }
    |                          --      ^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -620,13 +620,13 @@ LL |     if let (&Either::One(_t),) = (&e.clone(),) { }
    |                          data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:262:26
+  --> $DIR/simple.rs:260:26
    |
 LL |     if let (&Either::One(_t),) = (&e.clone(),) { }
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:264:37
+  --> $DIR/simple.rs:262:37
    |
 LL |     while let (&Either::One(_t),) = (&e.clone(),) { }
    |                             --      ^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -634,13 +634,13 @@ LL |     while let (&Either::One(_t),) = (&e.clone(),) { }
    |                             data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:264:29
+  --> $DIR/simple.rs:262:29
    |
 LL |     while let (&Either::One(_t),) = (&e.clone(),) { }
    |                             ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:266:11
+  --> $DIR/simple.rs:264:11
    |
 LL |     match (&e.clone(),) {
    |           ^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -649,13 +649,13 @@ LL |         (&Either::One(_t),)
    |                       -- data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:268:23
+  --> $DIR/simple.rs:266:23
    |
 LL |         (&Either::One(_t),)
    |                       ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:274:25
+  --> $DIR/simple.rs:272:25
    |
 LL |     let (&mut X(_t),) = (&mut xm.clone(),);
    |                 --      ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -663,13 +663,13 @@ LL |     let (&mut X(_t),) = (&mut xm.clone(),);
    |                 data moved here
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:274:17
+  --> $DIR/simple.rs:272:17
    |
 LL |     let (&mut X(_t),) = (&mut xm.clone(),);
    |                 ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:276:38
+  --> $DIR/simple.rs:274:38
    |
 LL |     if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
    |                              --      ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -677,13 +677,13 @@ LL |     if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
    |                              data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:276:30
+  --> $DIR/simple.rs:274:30
    |
 LL |     if let (&mut Either::One(_t),) = (&mut em.clone(),) { }
    |                              ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:278:41
+  --> $DIR/simple.rs:276:41
    |
 LL |     while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
    |                                 --      ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -691,13 +691,13 @@ LL |     while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
    |                                 data moved here
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:278:33
+  --> $DIR/simple.rs:276:33
    |
 LL |     while let (&mut Either::One(_t),) = (&mut em.clone(),) { }
    |                                 ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:280:11
+  --> $DIR/simple.rs:278:11
    |
 LL |     match (&mut em.clone(),) {
    |           ^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
@@ -708,7 +708,7 @@ LL |         (&mut Either::Two(_t),) => (),
    |                           -- ...and here
    |
 note: move occurs because these variables have types that don't implement the `Copy` trait
-  --> $DIR/simple.rs:282:27
+  --> $DIR/simple.rs:280:27
    |
 LL |         (&mut Either::One(_t),) => (),
    |                           ^^
@@ -716,7 +716,7 @@ LL |         (&mut Either::Two(_t),) => (),
    |                           ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:290:18
+  --> $DIR/simple.rs:288:18
    |
 LL |     let &X(_t) = &x;
    |         ------   ^^ cannot move out of borrowed content
@@ -725,13 +725,13 @@ LL |     let &X(_t) = &x;
    |         help: consider removing the `&`: `X(_t)`
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:290:12
+  --> $DIR/simple.rs:288:12
    |
 LL |     let &X(_t) = &x;
    |            ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:294:31
+  --> $DIR/simple.rs:292:31
    |
 LL |     if let &Either::One(_t) = &e { }
    |            ----------------   ^^ cannot move out of borrowed content
@@ -740,13 +740,13 @@ LL |     if let &Either::One(_t) = &e { }
    |            help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:294:25
+  --> $DIR/simple.rs:292:25
    |
 LL |     if let &Either::One(_t) = &e { }
    |                         ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:298:34
+  --> $DIR/simple.rs:296:34
    |
 LL |     while let &Either::One(_t) = &e { }
    |               ----------------   ^^ cannot move out of borrowed content
@@ -755,13 +755,13 @@ LL |     while let &Either::One(_t) = &e { }
    |               help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:298:28
+  --> $DIR/simple.rs:296:28
    |
 LL |     while let &Either::One(_t) = &e { }
    |                            ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:302:11
+  --> $DIR/simple.rs:300:11
    |
 LL |     match &e {
    |           ^^ cannot move out of borrowed content
@@ -773,13 +773,13 @@ LL |         &Either::One(_t)
    |         help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:304:22
+  --> $DIR/simple.rs:302:22
    |
 LL |         &Either::One(_t)
    |                      ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:310:11
+  --> $DIR/simple.rs:308:11
    |
 LL |     match &e {
    |           ^^ cannot move out of borrowed content
@@ -791,13 +791,13 @@ LL |         &Either::One(_t) => (),
    |         help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:312:22
+  --> $DIR/simple.rs:310:22
    |
 LL |         &Either::One(_t) => (),
    |                      ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:317:11
+  --> $DIR/simple.rs:315:11
    |
 LL |     match &e {
    |           ^^ cannot move out of borrowed content
@@ -809,13 +809,13 @@ LL |         &Either::One(_t) => (),
    |         help: consider removing the `&`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:319:22
+  --> $DIR/simple.rs:317:22
    |
 LL |         &Either::One(_t) => (),
    |                      ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:325:22
+  --> $DIR/simple.rs:323:22
    |
 LL |     let &mut X(_t) = &mut xm;
    |         ----------   ^^^^^^^ cannot move out of borrowed content
@@ -824,13 +824,13 @@ LL |     let &mut X(_t) = &mut xm;
    |         help: consider removing the `&mut`: `X(_t)`
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:325:16
+  --> $DIR/simple.rs:323:16
    |
 LL |     let &mut X(_t) = &mut xm;
    |                ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:329:35
+  --> $DIR/simple.rs:327:35
    |
 LL |     if let &mut Either::One(_t) = &mut em { }
    |            --------------------   ^^^^^^^ cannot move out of borrowed content
@@ -839,13 +839,13 @@ LL |     if let &mut Either::One(_t) = &mut em { }
    |            help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:329:29
+  --> $DIR/simple.rs:327:29
    |
 LL |     if let &mut Either::One(_t) = &mut em { }
    |                             ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:333:38
+  --> $DIR/simple.rs:331:38
    |
 LL |     while let &mut Either::One(_t) = &mut em { }
    |               --------------------   ^^^^^^^ cannot move out of borrowed content
@@ -854,13 +854,13 @@ LL |     while let &mut Either::One(_t) = &mut em { }
    |               help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:333:32
+  --> $DIR/simple.rs:331:32
    |
 LL |     while let &mut Either::One(_t) = &mut em { }
    |                                ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:337:11
+  --> $DIR/simple.rs:335:11
    |
 LL |     match &mut em {
    |           ^^^^^^^ cannot move out of borrowed content
@@ -872,13 +872,13 @@ LL |         &mut Either::One(_t)
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:339:26
+  --> $DIR/simple.rs:337:26
    |
 LL |         &mut Either::One(_t)
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:345:11
+  --> $DIR/simple.rs:343:11
    |
 LL |     match &mut em {
    |           ^^^^^^^ cannot move out of borrowed content
@@ -890,13 +890,13 @@ LL |         &mut Either::One(_t) => (),
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:347:26
+  --> $DIR/simple.rs:345:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:352:11
+  --> $DIR/simple.rs:350:11
    |
 LL |     match &mut em {
    |           ^^^^^^^ cannot move out of borrowed content
@@ -908,13 +908,13 @@ LL |         &mut Either::One(_t) => (),
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:354:26
+  --> $DIR/simple.rs:352:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:359:11
+  --> $DIR/simple.rs:357:11
    |
 LL |     match &mut em {
    |           ^^^^^^^ cannot move out of borrowed content
@@ -926,13 +926,13 @@ LL |         &mut Either::One(_t) => (),
    |         help: consider removing the `&mut`: `Either::One(_t)`
    |
 note: move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:361:26
+  --> $DIR/simple.rs:359:26
    |
 LL |         &mut Either::One(_t) => (),
    |                          ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:204:11
+  --> $DIR/simple.rs:202:11
    |
 LL |     fn f1(&X(_t): &X) { }
    |           ^^^--^
@@ -942,13 +942,13 @@ LL |     fn f1(&X(_t): &X) { }
    |           help: consider removing the `&`: `X(_t)`
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:204:14
+  --> $DIR/simple.rs:202:14
    |
 LL |     fn f1(&X(_t): &X) { }
    |              ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:251:11
+  --> $DIR/simple.rs:249:11
    |
 LL |     fn f2(&mut X(_t): &mut X) { }
    |           ^^^^^^^--^
@@ -958,13 +958,13 @@ LL |     fn f2(&mut X(_t): &mut X) { }
    |           help: consider removing the `&mut`: `X(_t)`
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:251:18
+  --> $DIR/simple.rs:249:18
    |
 LL |     fn f2(&mut X(_t): &mut X) { }
    |                  ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:271:11
+  --> $DIR/simple.rs:269:11
    |
 LL |     fn f3((&X(_t),): (&X,)) { }
    |           ^^^^--^^^
@@ -973,13 +973,13 @@ LL |     fn f3((&X(_t),): (&X,)) { }
    |           cannot move out of borrowed content
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:271:15
+  --> $DIR/simple.rs:269:15
    |
 LL |     fn f3((&X(_t),): (&X,)) { }
    |               ^^
 
 error[E0507]: cannot move out of borrowed content
-  --> $DIR/simple.rs:285:11
+  --> $DIR/simple.rs:283:11
    |
 LL |     fn f4((&mut X(_t),): (&mut X,)) { }
    |           ^^^^^^^^--^^^
@@ -988,7 +988,7 @@ LL |     fn f4((&mut X(_t),): (&mut X,)) { }
    |           cannot move out of borrowed content
    |
 note: move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-  --> $DIR/simple.rs:285:19
+  --> $DIR/simple.rs:283:19
    |
 LL |     fn f4((&mut X(_t),): (&mut X,)) { }
    |                   ^^
diff --git a/src/test/ui/suggestions/issue-57672.rs b/src/test/ui/suggestions/issue-57672.rs
new file mode 100644
index 00000000000..1773f72fc74
--- /dev/null
+++ b/src/test/ui/suggestions/issue-57672.rs
@@ -0,0 +1,14 @@
+// aux-build:foo.rs
+// compile-flags:--extern foo
+// compile-pass
+// edition:2018
+
+#![deny(unused_extern_crates)]
+
+extern crate foo as foo_renamed;
+
+pub mod m {
+    pub use foo_renamed::Foo;
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
new file mode 100644
index 00000000000..f4eb9813c1a
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr
@@ -0,0 +1,11 @@
+error[E0310]: the parameter type `impl Debug` may not live long enough
+  --> $DIR/suggest-impl-trait-lifetime.rs:7:5
+   |
+LL |     bar(d);
+   |     ^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `impl Debug: 'static`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/suggestions/suggest-ref-mut.rs b/src/test/ui/suggestions/suggest-ref-mut.rs
index b4a6fa39f90..d04113ffccc 100644
--- a/src/test/ui/suggestions/suggest-ref-mut.rs
+++ b/src/test/ui/suggestions/suggest-ref-mut.rs
@@ -1,5 +1,3 @@
-#![feature(nll)]
-
 struct X(usize);
 
 impl X {
diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr
index 3dd9fbc6f14..24143678757 100644
--- a/src/test/ui/suggestions/suggest-ref-mut.stderr
+++ b/src/test/ui/suggestions/suggest-ref-mut.stderr
@@ -1,5 +1,5 @@
 error[E0594]: cannot assign to `self.0` which is behind a `&` reference
-  --> $DIR/suggest-ref-mut.rs:9:9
+  --> $DIR/suggest-ref-mut.rs:7:9
    |
 LL |     fn zap(&self) {
    |            ----- help: consider changing this to be a mutable reference: `&mut self`
@@ -8,7 +8,7 @@ LL |         self.0 = 32;
    |         ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
 
 error[E0594]: cannot assign to `*foo` which is behind a `&` reference
-  --> $DIR/suggest-ref-mut.rs:18:5
+  --> $DIR/suggest-ref-mut.rs:16:5
    |
 LL |     let ref foo = 16;
    |         ------- help: consider changing this to be a mutable reference: `ref mut foo`
@@ -17,7 +17,7 @@ LL |     *foo = 32;
    |     ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
 
 error[E0594]: cannot assign to `*bar` which is behind a `&` reference
-  --> $DIR/suggest-ref-mut.rs:23:9
+  --> $DIR/suggest-ref-mut.rs:21:9
    |
 LL |     if let Some(ref bar) = Some(16) {
    |                 ------- help: consider changing this to be a mutable reference: `ref mut bar`
@@ -26,7 +26,7 @@ LL |         *bar = 32;
    |         ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
 
 error[E0594]: cannot assign to `*quo` which is behind a `&` reference
-  --> $DIR/suggest-ref-mut.rs:27:22
+  --> $DIR/suggest-ref-mut.rs:25:22
    |
 LL |         ref quo => { *quo = 32; },
    |         -------      ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written
diff --git a/src/test/ui/thread-local-in-ctfe.nll.stderr b/src/test/ui/thread-local-in-ctfe.nll.stderr
new file mode 100644
index 00000000000..18d01b18790
--- /dev/null
+++ b/src/test/ui/thread-local-in-ctfe.nll.stderr
@@ -0,0 +1,49 @@
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-in-ctfe.rs:6:17
+   |
+LL | static B: u32 = A;
+   |                 ^
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-in-ctfe.rs:9:18
+   |
+LL | static C: &u32 = &A;
+   |                  ^^
+
+error[E0712]: thread-local variable borrowed past end of function
+  --> $DIR/thread-local-in-ctfe.rs:9:18
+   |
+LL | static C: &u32 = &A;
+   |                  ^^- end of enclosing function is here
+   |                  |
+   |                  thread-local variables cannot be borrowed beyond the end of the function
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-in-ctfe.rs:15:16
+   |
+LL | const D: u32 = A;
+   |                ^
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-in-ctfe.rs:18:17
+   |
+LL | const E: &u32 = &A;
+   |                 ^^
+
+error[E0712]: thread-local variable borrowed past end of function
+  --> $DIR/thread-local-in-ctfe.rs:18:17
+   |
+LL | const E: &u32 = &A;
+   |                 ^^- end of enclosing function is here
+   |                 |
+   |                 thread-local variables cannot be borrowed beyond the end of the function
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-in-ctfe.rs:25:5
+   |
+LL |     A
+   |     ^
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0712`.
diff --git a/src/test/ui/traits/cycle-cache-err-60010.rs b/src/test/ui/traits/cycle-cache-err-60010.rs
new file mode 100644
index 00000000000..45aa1b3c522
--- /dev/null
+++ b/src/test/ui/traits/cycle-cache-err-60010.rs
@@ -0,0 +1,71 @@
+// Test that we properly detect the cycle amongst the traits
+// here and report an error.
+
+use std::panic::RefUnwindSafe;
+
+trait Database {
+    type Storage;
+}
+trait HasQueryGroup {}
+trait Query<DB> {
+    type Data;
+}
+trait SourceDatabase {
+    fn parse(&self) {
+        loop {}
+    }
+}
+
+struct ParseQuery;
+struct RootDatabase {
+    _runtime: Runtime<RootDatabase>,
+}
+struct Runtime<DB: Database> {
+    _storage: Box<DB::Storage>,
+}
+struct SalsaStorage {
+    _parse: <ParseQuery as Query<RootDatabase>>::Data, //~ ERROR overflow
+}
+
+impl Database for RootDatabase { //~ ERROR overflow
+    type Storage = SalsaStorage;
+}
+impl HasQueryGroup for RootDatabase {}
+impl<DB> Query<DB> for ParseQuery
+where
+    DB: SourceDatabase,
+    DB: Database,
+{
+    type Data = RootDatabase;
+}
+impl<T> SourceDatabase for T
+where
+    T: RefUnwindSafe,
+    T: HasQueryGroup,
+{
+}
+
+pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 {
+    // This is not satisfied:
+    //
+    // - `RootDatabase: SourceDatabase`
+    //   - requires `RootDatabase: RefUnwindSafe` + `RootDatabase: HasQueryGroup`
+    // - `RootDatabase: RefUnwindSafe`
+    //   - requires `Runtime<RootDatabase>: RefUnwindSafe`
+    // - `Runtime<RootDatabase>: RefUnwindSafe`
+    //   - requires `DB::Storage: RefUnwindSafe` (`SalsaStorage: RefUnwindSafe`)
+    // - `SalsaStorage: RefUnwindSafe`
+    //    - requires `<ParseQuery as Query<RootDatabase>>::Data: RefUnwindSafe`,
+    //      which means `ParseQuery: Query<RootDatabase>`
+    // - `ParseQuery: Query<RootDatabase>`
+    //    - requires `RootDatabase: SourceDatabase`,
+    // - `RootDatabase: SourceDatabase` is already on the stack, so we have a
+    //   cycle with non-coinductive participants
+    //
+    // we used to fail to report an error here because we got the
+    // caching wrong.
+    SourceDatabase::parse(db);
+    22
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr
new file mode 100644
index 00000000000..9192f7ba2e3
--- /dev/null
+++ b/src/test/ui/traits/cycle-cache-err-60010.stderr
@@ -0,0 +1,20 @@
+error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
+  --> $DIR/cycle-cache-err-60010.rs:27:5
+   |
+LL |     _parse: <ParseQuery as Query<RootDatabase>>::Data,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
+
+error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
+  --> $DIR/cycle-cache-err-60010.rs:30:6
+   |
+LL | impl Database for RootDatabase {
+   |      ^^^^^^^^
+   |
+   = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
+   = note: required because it appears within the type `SalsaStorage`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr
index 7c7366df1dc..e1c2c6b675e 100644
--- a/src/test/ui/try-block/try-block-bad-type.stderr
+++ b/src/test/ui/try-block/try-block-bad-type.stderr
@@ -4,6 +4,7 @@ error[E0277]: `?` couldn't convert the error to `i32`
 LL |         Err("")?;
    |                ^ the trait `std::convert::From<&str>` is not implemented for `i32`
    |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the following implementations were found:
              <i32 as std::convert::From<bool>>
              <i32 as std::convert::From<i16>>
diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr
index 4465fbe14b7..db5046f8c15 100644
--- a/src/test/ui/try-on-option.stderr
+++ b/src/test/ui/try-on-option.stderr
@@ -4,6 +4,7 @@ error[E0277]: `?` couldn't convert the error to `()`
 LL |     x?;
    |      ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
    |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = note: required by `std::convert::From::from`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr
new file mode 100644
index 00000000000..ead42c14889
--- /dev/null
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr
@@ -0,0 +1,12 @@
+error: lifetime may not live long enough
+  --> $DIR/unboxed-closures-infer-argument-types-two-region-pointers.rs:17:9
+   |
+LL |     doit(0, &|x, y| {
+   |               -  - has type `&'1 i32`
+   |               |
+   |               has type `&std::cell::Cell<&'2 i32>`
+LL |         x.set(y);
+   |         ^^^^^^^^ argument requires that `'1` must outlive `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
new file mode 100644
index 00000000000..8ed48bda26e
--- /dev/null
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/dyn-trait-underscore.rs:8:5
+   |
+LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
+   |                - let's call the lifetime of this reference `'1`
+LL |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
+LL |     Box::new(items.iter())
+   |     ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr
new file mode 100644
index 00000000000..e1d57b8ba1e
--- /dev/null
+++ b/src/test/ui/underscore-lifetime/underscore-lifetime-elison-mismatch.nll.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/underscore-lifetime-elison-mismatch.rs:1:42
+   |
+LL | fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); }
+   |                    -           -         ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |                    |           |
+   |                    |           let's call the lifetime of this reference `'1`
+   |                    let's call the lifetime of this reference `'2`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr
new file mode 100644
index 00000000000..344437f74e4
--- /dev/null
+++ b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr
@@ -0,0 +1,106 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:4:5
+   |
+LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> {
+   |                     ---- lifetime `'new` defined here
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:7:5
+   |
+LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> {
+   |                     ---- lifetime `'new` defined here
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:10:5
+   |
+LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> {
+   |                        ---- lifetime `'new` defined here
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:13:5
+   |
+LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> {
+   |                        ---- lifetime `'new` defined here
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:18:5
+   |
+LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>)
+   |                    ---- lifetime `'new` defined here
+LL |                          -> OccupiedEntry<'a, &'new (), ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:22:5
+   |
+LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>)
+   |                    ---- lifetime `'new` defined here
+LL |                          -> OccupiedEntry<'a, (), &'new ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:26:5
+   |
+LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>)
+   |                       ---- lifetime `'new` defined here
+LL |                             -> OccupiedEntry<'a, &'static (), ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:30:5
+   |
+LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>)
+   |                       ---- lifetime `'new` defined here
+LL |                             -> OccupiedEntry<'a, (), &'static ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:35:5
+   |
+LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>)
+   |                    ---- lifetime `'new` defined here
+LL |                          -> VacantEntry<'a, &'new (), ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:39:5
+   |
+LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>)
+   |                    ---- lifetime `'new` defined here
+LL |                          -> VacantEntry<'a, (), &'new ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:43:5
+   |
+LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>)
+   |                       ---- lifetime `'new` defined here
+LL |                             -> VacantEntry<'a, &'static (), ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-btree-invariant-types.rs:47:5
+   |
+LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>)
+   |                       ---- lifetime `'new` defined here
+LL |                             -> VacantEntry<'a, (), &'static ()> {
+LL |     v
+   |     ^ returning this value requires that `'new` must outlive `'static`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/variance/variance-cell-is-invariant.nll.stderr b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
new file mode 100644
index 00000000000..a3ae5320c90
--- /dev/null
+++ b/src/test/ui/variance/variance-cell-is-invariant.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-cell-is-invariant.rs:14:12
+   |
+LL | fn use_<'short,'long>(c: Foo<'short>,
+   |         ------ ----- lifetime `'long` defined here
+   |         |
+   |         lifetime `'short` defined here
+...
+LL |     let _: Foo<'long> = c;
+   |            ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr
new file mode 100644
index 00000000000..8b5ecbe56ff
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-contravariant-arg-object.rs:14:5
+   |
+LL | fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-contravariant-arg-object.rs:22:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr b/src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr
new file mode 100644
index 00000000000..dbd75cb52fa
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-contravariant-arg-trait-match.rs:13:5
+   |
+LL | fn get_min_from_max<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<G,&'min i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-contravariant-arg-trait-match.rs:21:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<G,&'max i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr b/src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr
new file mode 100644
index 00000000000..9212cf24be3
--- /dev/null
+++ b/src/test/ui/variance/variance-contravariant-self-trait-match.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-contravariant-self-trait-match.rs:13:5
+   |
+LL | fn get_min_from_max<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<&'min G>();
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-contravariant-self-trait-match.rs:22:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<&'max G>();
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-covariant-arg-object.nll.stderr b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr
new file mode 100644
index 00000000000..acf9f2e060c
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-covariant-arg-object.rs:15:5
+   |
+LL | fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-covariant-arg-object.rs:22:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr b/src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr
new file mode 100644
index 00000000000..33589121c4b
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-arg-trait-match.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-covariant-arg-trait-match.rs:14:5
+   |
+LL | fn get_min_from_max<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<G,&'min i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-covariant-arg-trait-match.rs:20:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<G,&'max i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr b/src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr
new file mode 100644
index 00000000000..6b2413d68be
--- /dev/null
+++ b/src/test/ui/variance/variance-covariant-self-trait-match.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-covariant-self-trait-match.rs:14:5
+   |
+LL | fn get_min_from_max<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<&'min G>();
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-covariant-self-trait-match.rs:20:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<&'max G>();
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-invariant-arg-object.nll.stderr b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr
new file mode 100644
index 00000000000..3c1ee7fc707
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-invariant-arg-object.rs:11:5
+   |
+LL | fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-invariant-arg-object.rs:18:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr b/src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr
new file mode 100644
index 00000000000..2ab44c54c72
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-arg-trait-match.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-invariant-arg-trait-match.rs:10:5
+   |
+LL | fn get_min_from_max<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<G,&'min i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-invariant-arg-trait-match.rs:16:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<G,&'max i32>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr b/src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr
new file mode 100644
index 00000000000..7b7c42fea8d
--- /dev/null
+++ b/src/test/ui/variance/variance-invariant-self-trait-match.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-invariant-self-trait-match.rs:10:5
+   |
+LL | fn get_min_from_max<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<&'min G>();
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-invariant-self-trait-match.rs:16:5
+   |
+LL | fn get_max_from_min<'min, 'max, G>()
+   |                     ----  ---- lifetime `'max` defined here
+   |                     |
+   |                     lifetime `'min` defined here
+...
+LL |     impls_get::<&'max G>();
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/variance/variance-trait-matching.nll.stderr b/src/test/ui/variance/variance-trait-matching.nll.stderr
new file mode 100644
index 00000000000..3308cc6d250
--- /dev/null
+++ b/src/test/ui/variance/variance-trait-matching.nll.stderr
@@ -0,0 +1,12 @@
+error[E0621]: explicit lifetime required in the type of `get`
+  --> $DIR/variance-trait-matching.rs:24:5
+   |
+LL | fn get<'a, G>(get: &G) -> i32
+   |                    -- help: add explicit lifetime `'a` to the type of `get`: `&'a G`
+...
+LL |     pick(get, &22)
+   |     ^^^^^^^^^^^^^^ lifetime `'a` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr
new file mode 100644
index 00000000000..8468448b27b
--- /dev/null
+++ b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-use-contravariant-struct-1.rs:12:5
+   |
+LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+   |        ---- ---- lifetime `'max` defined here
+   |        |
+   |        lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr
new file mode 100644
index 00000000000..19a22f064be
--- /dev/null
+++ b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-use-covariant-struct-1.rs:10:5
+   |
+LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>)
+   |        ---- ---- lifetime `'max` defined here
+   |        |
+   |        lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
new file mode 100644
index 00000000000..61f80fe77e6
--- /dev/null
+++ b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/variance-use-invariant-struct-1.rs:12:5
+   |
+LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
+   |        ---- ---- lifetime `'max` defined here
+   |        |
+   |        lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: lifetime may not live long enough
+  --> $DIR/variance-use-invariant-struct-1.rs:19:5
+   |
+LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>)
+   |        ---- ---- lifetime `'max` defined here
+   |        |
+   |        lifetime `'min` defined here
+...
+LL |     v
+   |     ^ returning this value requires that `'min` must outlive `'max`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr
new file mode 100644
index 00000000000..338de6db180
--- /dev/null
+++ b/src/test/ui/wf/wf-static-method.nll.stderr
@@ -0,0 +1,65 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-static-method.rs:17:9
+   |
+LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |         u
+   |         ^ returning this value requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-static-method.rs:26:18
+   |
+LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |         let me = Self::make_me();
+   |                  ^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-static-method.rs:33:9
+   |
+LL | impl<'a, 'b> Evil<'a, 'b> {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     fn inherent_evil(u: &'b u32) -> &'a u32 {
+LL |         u
+   |         ^ returning this value requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-static-method.rs:41:5
+   |
+LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |         --  -- lifetime `'b` defined here
+   |         |
+   |         lifetime `'a` defined here
+LL |     <()>::static_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-static-method.rs:45:5
+   |
+LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     <IndirectEvil>::static_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-static-method.rs:50:5
+   |
+LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                  --  -- lifetime `'b` defined here
+   |                  |
+   |                  lifetime `'a` defined here
+LL |     <Evil>::inherent_evil(b) // bug? shouldn't this be an error
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 61cc78ad807..5efd51b65c1 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -108,7 +108,7 @@ static TARGETS: &[&str] = &[
     "thumbv8m.main-none-eabihf",
     "wasm32-unknown-emscripten",
     "wasm32-unknown-unknown",
-    "wasm32-unknown-wasi",
+    "wasm32-wasi",
     "x86_64-apple-darwin",
     "x86_64-apple-ios",
     "x86_64-fortanix-unknown-sgx",
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 759b6161a328db1d4863139e90875308ecd25a7
+Subproject c4fcfb725b4be00c72eb9cf30c7d8b095577c28
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject 341c96afd331195beeb001436535c1feb479ff9
+Subproject 60a609acaed3bf2b3ec6ab995bccf0f03bc2606
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 336d7e32024..e759ad1f35d 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -7,7 +7,6 @@ edition = "2018"
 [dependencies]
 diff = "0.1.10"
 env_logger = { version = "0.5", default-features = false }
-filetime = "0.2"
 getopts = "0.2"
 log = "0.4"
 regex = "1.0"
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index e253934e566..442e58bfd74 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -9,7 +9,6 @@ use crate::common::CompareMode;
 use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
 use crate::common::{Config, TestPaths};
 use crate::common::{DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Mode, Pretty};
-use filetime::FileTime;
 use getopts::Options;
 use std::env;
 use std::ffi::OsString;
@@ -17,6 +16,7 @@ use std::fs;
 use std::io::{self, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::time::SystemTime;
 use test::ColorConfig;
 use crate::util::logv;
 use walkdir::WalkDir;
@@ -752,31 +752,36 @@ fn up_to_date(
 
 #[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
 struct Stamp {
-    time: FileTime,
+    time: SystemTime,
     file: PathBuf,
 }
 
 impl Stamp {
     fn from_path(p: &Path) -> Self {
+        let time = fs::metadata(p)
+            .and_then(|metadata| metadata.modified())
+            .unwrap_or(SystemTime::UNIX_EPOCH);
+
         Stamp {
-            time: mtime(&p),
+            time,
             file: p.into(),
         }
     }
 
-    fn from_dir(path: &Path) -> impl Iterator<Item=Stamp> {
+    fn from_dir(path: &Path) -> impl Iterator<Item = Stamp> {
         WalkDir::new(path)
             .into_iter()
             .map(|entry| entry.unwrap())
             .filter(|entry| entry.file_type().is_file())
-            .map(|entry| Stamp::from_path(entry.path()))
-    }
-}
+            .map(|entry| {
+                let time = (|| -> io::Result<_> { entry.metadata()?.modified() })();
 
-fn mtime(path: &Path) -> FileTime {
-    fs::metadata(path)
-        .map(|f| FileTime::from_last_modification_time(&f))
-        .unwrap_or_else(|_| FileTime::zero())
+                Stamp {
+                    time: time.unwrap_or(SystemTime::UNIX_EPOCH),
+                    file: entry.path().into(),
+                }
+            })
+    }
 }
 
 fn make_test_name(
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 3689946c055..2082de7cbce 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -9,7 +9,6 @@ use crate::common::{Config, TestPaths};
 use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly};
 use diff;
 use crate::errors::{self, Error, ErrorKind};
-use filetime::FileTime;
 use crate::header::TestProps;
 use crate::json;
 use regex::{Captures, Regex};
@@ -1650,7 +1649,9 @@ impl<'test> TestCx<'test> {
                 (true, None)
             } else if self.config.target.contains("cloudabi")
                 || self.config.target.contains("emscripten")
-                || (self.config.target.contains("musl") && !aux_props.force_host)
+                || (self.config.target.contains("musl")
+                    && !aux_props.force_host
+                    && !self.config.host.contains("musl"))
                 || self.config.target.contains("wasm32")
                 || self.config.target.contains("nvptx")
             {
@@ -1910,8 +1911,7 @@ impl<'test> TestCx<'test> {
 
         match self.config.compare_mode {
             Some(CompareMode::Nll) => {
-                // FIXME(#56993) use -Zborrowck=mir
-                rustc.args(&["-Zborrowck=migrate"]);
+                rustc.args(&["-Zborrowck=mir"]);
             }
             Some(CompareMode::Polonius) => {
                 rustc.args(&["-Zpolonius", "-Zborrowck=mir"]);
@@ -1932,6 +1932,11 @@ impl<'test> TestCx<'test> {
             }
         }
 
+        // Use dynamic musl for tests because static doesn't allow creating dylibs
+        if self.config.host.contains("musl") {
+            rustc.arg("-Ctarget-feature=-crt-static");
+        }
+
         rustc.args(&self.props.compile_flags);
 
         rustc
@@ -2210,9 +2215,7 @@ impl<'test> TestCx<'test> {
 
     fn charset() -> &'static str {
         // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
-        if cfg!(target_os = "bitrig") {
-            "auto"
-        } else if cfg!(target_os = "freebsd") {
+        if cfg!(target_os = "freebsd") {
             "ISO-8859-1"
         } else {
             "UTF-8"
@@ -2663,8 +2666,7 @@ impl<'test> TestCx<'test> {
         create_dir_all(&tmpdir).unwrap();
 
         let host = &self.config.host;
-        let make = if host.contains("bitrig")
-            || host.contains("dragonfly")
+        let make = if host.contains("dragonfly")
             || host.contains("freebsd")
             || host.contains("netbsd")
             || host.contains("openbsd")
@@ -2725,6 +2727,12 @@ impl<'test> TestCx<'test> {
         // compiler flags set in the test cases:
         cmd.env_remove("RUSTFLAGS");
 
+        // Use dynamic musl for tests because static doesn't allow creating dylibs
+        if self.config.host.contains("musl") {
+            cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static")
+                .env("IS_MUSL_HOST", "1");
+        }
+
         if self.config.target.contains("msvc") && self.config.cc != "" {
             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
             // and that `lib.exe` lives next to it.
@@ -3019,7 +3027,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
-        let t = |file| FileTime::from_last_modification_time(&fs::metadata(file).unwrap());
+        let t = |file| fs::metadata(file).unwrap().modified().unwrap();
         let source_file = &self.testpaths.file;
         let output_time = t(output_file);
         let source_time = t(source_file);
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index adc1224bcd3..8caf5ca00f5 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -9,7 +9,6 @@ use log::*;
 const OS_TABLE: &'static [(&'static str, &'static str)] = &[
     ("android", "android"),
     ("androideabi", "android"),
-    ("bitrig", "bitrig"),
     ("cloudabi", "cloudabi"),
     ("cuda", "cuda"),
     ("darwin", "macos"),
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 04986b59ea0..38bd3fc006d 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -15,6 +15,7 @@ use std::path::Path;
 use std::path::PathBuf;
 use std::cell::RefCell;
 
+use syntax::edition::DEFAULT_EDITION;
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
 use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND};
@@ -97,7 +98,8 @@ impl Formatter for HTMLFormatter {
             Some(ref desc) => {
                 let mut id_map = self.0.borrow_mut();
                 write!(output, "{}",
-                    Markdown(desc, &[], RefCell::new(&mut id_map), ErrorCodes::Yes))?
+                    Markdown(desc, &[], RefCell::new(&mut id_map),
+                             ErrorCodes::Yes, DEFAULT_EDITION))?
             },
             None => write!(output, "<p>No description.</p>\n")?,
         }
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 053aa694990a212ad8942dd72101ede23597c0e
+Subproject 0c85dbf3df0f545133dca24eccfc9f0f6107c7f
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 5b8e99bb61958ca8abcb7c5eda70521726be106
+Subproject 9692ca8fd82a8f96a4113dc4b88c1fb1d79c1c6
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 5bf1553b227..d2b1a7bac60 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -2,7 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "rustbook"
 version = "0.1.0"
-license = "MIT/Apache-2.0"
+license = "MIT OR Apache-2.0"
 edition = "2018"
 
 [dependencies]
diff --git a/src/tools/rustc-std-workspace-alloc/Cargo.toml b/src/tools/rustc-std-workspace-alloc/Cargo.toml
index 98578914963..05df1fddc7f 100644
--- a/src/tools/rustc-std-workspace-alloc/Cargo.toml
+++ b/src/tools/rustc-std-workspace-alloc/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc-std-workspace-alloc"
 version = "1.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = 'MIT/Apache-2.0'
+license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
diff --git a/src/tools/rustc-std-workspace-core/Cargo.toml b/src/tools/rustc-std-workspace-core/Cargo.toml
index d527ce12bc3..38ca56a557b 100644
--- a/src/tools/rustc-std-workspace-core/Cargo.toml
+++ b/src/tools/rustc-std-workspace-core/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc-std-workspace-core"
 version = "1.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = 'MIT/Apache-2.0'
+license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index d51841cd650..290c4481c00 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -2,7 +2,7 @@
 name = "rustc-workspace-hack"
 version = "1.0.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
-license = 'MIT/Apache-2.0'
+license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml
index 3209de09aeb..e43e4e6c7cb 100644
--- a/src/tools/unstable-book-gen/Cargo.toml
+++ b/src/tools/unstable-book-gen/Cargo.toml
@@ -3,7 +3,7 @@ authors = ["est31 <MTest31@outlook.com>",
            "The Rust Project Developers"]
 name = "unstable-book-gen"
 version = "0.1.0"
-license = "MIT/Apache-2.0"
+license = "MIT OR Apache-2.0"
 edition = "2018"
 
 [dependencies]