about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml12
-rw-r--r--Cargo.lock13
-rw-r--r--compiler/rustc_abi/src/layout.rs71
-rw-r--r--compiler/rustc_abi/src/lib.rs44
-rw-r--r--compiler/rustc_ast/src/ast.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs7
-rw-r--r--compiler/rustc_ast/src/util/literal.rs63
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_attr/src/builtin.rs39
-rw-r--r--compiler/rustc_borrowck/src/lib.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs5
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs85
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs9
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs104
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs1
-rw-r--r--compiler/rustc_errors/src/lib.rs35
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs6
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs324
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs5
-rw-r--r--compiler/rustc_infer/src/infer/at.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs22
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs11
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs32
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs75
-rw-r--r--compiler/rustc_interface/src/interface.rs76
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_lexer/src/lib.rs90
-rw-r--r--compiler/rustc_lexer/src/unescape.rs278
-rw-r--r--compiler/rustc_lint/src/builtin.rs20
-rw-r--r--compiler/rustc_lint/src/context.rs70
-rw-r--r--compiler/rustc_lint/src/internal.rs6
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp47
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp22
-rw-r--r--compiler/rustc_metadata/src/creader.rs14
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs18
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs45
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs4
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs17
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs20
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs63
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs22
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs14
-rw-r--r--compiler/rustc_privacy/src/lib.rs271
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs4
-rw-r--r--compiler/rustc_serialize/src/opaque.rs153
-rw-r--r--compiler/rustc_serialize/src/serialize.rs8
-rw-r--r--compiler/rustc_session/messages.ftl2
-rw-r--r--compiler/rustc_session/src/config.rs251
-rw-r--r--compiler/rustc_session/src/errors.rs15
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_smir/Cargo.toml1
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs126
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/body.rs70
-rw-r--r--compiler/rustc_span/src/lib.rs23
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/asm/mod.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs102
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs52
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs84
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs94
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs1
-rw-r--r--library/alloc/src/collections/btree/map.rs4
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs19
-rw-r--r--library/core/src/ffi/c_str.rs2
-rw-r--r--library/core/src/iter/adapters/flatten.rs6
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/ptr/mod.rs14
-rw-r--r--library/core/src/tuple.rs4
-rw-r--r--library/proc_macro/src/bridge/mod.rs4
-rw-r--r--library/std/src/sys/common/thread_local/mod.rs5
-rw-r--r--library/std/src/sys/common/thread_local/os_local.rs2
-rw-r--r--library/std/src/sys/hermit/time.rs12
-rw-r--r--library/std/src/sys/sgx/abi/entry.S6
-rw-r--r--library/std/src/sys/solid/time.rs4
-rw-r--r--library/std/src/sys/unix/thread.rs19
-rw-r--r--library/std/src/sys/unix/time.rs16
-rw-r--r--library/std/src/thread/mod.rs32
-rw-r--r--library/std/src/time/tests.rs27
-rw-r--r--src/bootstrap/config.rs22
-rw-r--r--src/bootstrap/dist.rs2
-rw-r--r--src/bootstrap/flags.rs18
-rw-r--r--src/bootstrap/run.rs5
-rw-r--r--src/bootstrap/test.rs13
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile1
-rwxr-xr-xsrc/ci/docker/run.sh1
-rw-r--r--src/ci/docker/scripts/musl-toolchain.sh18
-rw-r--r--src/ci/docker/scripts/musl.sh2
-rw-r--r--src/ci/github-actions/ci.yml6
-rwxr-xr-xsrc/ci/scripts/install-awscli.sh38
-rw-r--r--src/doc/rustc/src/codegen-options/index.md11
-rw-r--r--src/doc/unstable-book/src/language-features/raw-dylib.md34
-rw-r--r--src/librustdoc/html/highlight.rs4
-rw-r--r--src/librustdoc/html/render/search_index.rs30
-rw-r--r--src/librustdoc/lib.rs19
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/remark.yml6
-rw-r--r--src/tools/clippy/CHANGELOG.md25
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/README.md3
-rw-r--r--src/tools/clippy/book/src/development/lint_passes.md2
-rw-r--r--src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md18
-rw-r--r--src/tools/clippy/book/src/usage.md3
-rw-r--r--src/tools/clippy/clippy_dev/src/dogfood.rs8
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs13
-rw-r--r--src/tools/clippy/clippy_dev/src/lint.rs17
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs54
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_test_module.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs110
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_bool.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs8
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs51
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs6
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/lintcheck/README.md4
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs70
-rw-r--r--src/tools/clippy/src/main.rs2
-rw-r--r--src/tools/clippy/tests/dogfood.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed86
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/both.rs86
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr55
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed85
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs85
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr18
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed85
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs85
-rw-r--r--src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr39
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes_false_positive.rs5
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs7
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs2
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.fixed9
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.rs9
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.stderr2
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed1
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs1
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr32
-rw-r--r--src/tools/clippy/tests/ui/cast_slice_different_sizes.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10645.rs7
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10645.stderr (renamed from src/tools/clippy/tests/ui/crashes/ice-5207.stderr)4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5207.rs4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice_exact_size.rs (renamed from src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs)0
-rw-r--r--src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed119
-rw-r--r--src/tools/clippy/tests/ui/default_constructed_unit_structs.rs119
-rw-r--r--src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr34
-rw-r--r--src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs31
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.fixed2
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.rs2
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.stderr12
-rw-r--r--src/tools/clippy/tests/ui/from_over_into_unfixable.stderr6
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs1
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/block_module.rs (renamed from src/tools/clippy/tests/ui/items_after_test_module.rs)0
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr (renamed from src/tools/clippy/tests/ui/items_after_test_module.stderr)2
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs20
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_untyped.stderr30
-rw-r--r--src/tools/clippy/tests/ui/let_with_type_underscore.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_while_let_some.fixed93
-rw-r--r--src/tools/clippy/tests/ui/manual_while_let_some.rs93
-rw-r--r--src/tools/clippy/tests/ui/manual_while_let_some.stderr87
-rw-r--r--src/tools/clippy/tests/ui/needless_bool_assign.fixed33
-rw-r--r--src/tools/clippy/tests/ui/needless_bool_assign.rs45
-rw-r--r--src/tools/clippy/tests/ui/needless_bool_assign.stderr53
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs2
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed2
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr24
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed1
-rw-r--r--src/tools/clippy/tests/ui/rename.rs1
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr86
-rw-r--r--src/tools/clippy/tests/ui/same_name_method.rs2
-rw-r--r--src/tools/clippy/tests/ui/shadow.rs12
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr92
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.fixed14
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.rs14
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.stderr25
-rw-r--r--src/tools/clippy/tests/ui/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/tests/ui/uninit.rs4
-rw-r--r--src/tools/clippy/tests/ui/use_self_trait.fixed4
-rw-r--r--src/tools/clippy/tests/ui/use_self_trait.rs4
-rw-r--r--src/tools/clippy/tests/ui/use_self_trait.stderr2
-rw-r--r--src/tools/clippy/util/gh-pages/index.html2
-rw-r--r--src/tools/compiletest/src/header/needs.rs36
-rw-r--r--src/tools/compiletest/src/runtest.rs73
-rw-r--r--src/tools/miri/src/bin/miri.rs8
-rw-r--r--src/tools/miropt-test-tools/src/lib.rs19
-rw-r--r--src/tools/rustfmt/src/bin/main.rs9
-rw-r--r--src/tools/suggest-tests/src/static_suggestions.rs2
-rw-r--r--src/tools/suggest-tests/src/tests.rs2
-rw-r--r--tests/codegen/align-offset.rs78
-rw-r--r--tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir32
-rw-r--r--tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir36
-rw-r--r--tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir30
-rw-r--r--tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir32
-rw-r--r--tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir16
-rw-r--r--tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir14
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff46
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.rs17
-rw-r--r--tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff18
-rw-r--r--tests/mir-opt/const_prop/bad_op_mod_by_zero.rs1
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff45
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff45
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs3
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff22
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.rs2
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff6
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff6
-rw-r--r--tests/mir-opt/const_prop/large_array_index.rs2
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff23
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.rs1
-rw-r--r--tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff6
-rw-r--r--tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff6
-rw-r--r--tests/mir-opt/const_prop/repeat.rs5
-rw-r--r--tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir6
-rw-r--r--tests/mir-opt/const_prop/return_place.rs1
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff14
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.rs1
-rw-r--r--tests/mir-opt/const_prop/switch_int.main.ConstProp.diff4
-rw-r--r--tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff4
-rw-r--r--tests/mir-opt/const_prop/switch_int.rs2
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff13
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.rs1
-rw-r--r--tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff (renamed from tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff)27
-rw-r--r--tests/mir-opt/const_prop/while_let_loops.rs (renamed from tests/mir-opt/while_let_loops.rs)2
-rw-r--r--tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff3
-rw-r--r--tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff3
-rw-r--r--tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir17
-rw-r--r--tests/run-make/issue-109934-lto-debuginfo/Makefile12
-rw-r--r--tests/run-make/issue-109934-lto-debuginfo/lib.rs9
-rw-r--r--tests/run-make/raw-dylib-alt-calling-convention/lib.rs1
-rw-r--r--tests/run-make/raw-dylib-c/lib.rs2
-rw-r--r--tests/run-make/raw-dylib-cross-compilation/lib.rs1
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/Makefile11
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/lib.rs10
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/output.txt1
-rw-r--r--tests/run-make/raw-dylib-custom-dlltool/script.cmd2
-rw-r--r--tests/run-make/raw-dylib-import-name-type/driver.rs1
-rw-r--r--tests/run-make/raw-dylib-inline-cross-dylib/driver.rs2
-rw-r--r--tests/run-make/raw-dylib-inline-cross-dylib/lib.rs2
-rw-r--r--tests/run-make/raw-dylib-link-ordinal/lib.rs2
-rw-r--r--tests/run-make/raw-dylib-stdcall-ordinal/lib.rs2
-rw-r--r--tests/rustdoc-js/slice-array.js65
-rw-r--r--tests/rustdoc-js/slice-array.rs16
-rw-r--r--tests/rustdoc-ui/check-cfg/check-cfg.stderr2
-rw-r--r--tests/rustdoc-ui/doctest/check-cfg-test.stderr2
-rw-r--r--tests/rustdoc-ui/ice-bug-report-url.rs14
-rw-r--r--tests/rustdoc-ui/ice-bug-report-url.stderr16
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs24
-rw-r--r--tests/ui/check-cfg/compact-values.stderr2
-rw-r--r--tests/ui/check-cfg/diagnotics.rs31
-rw-r--r--tests/ui/check-cfg/diagnotics.stderr62
-rw-r--r--tests/ui/check-cfg/invalid-cfg-name.stderr2
-rw-r--r--tests/ui/check-cfg/invalid-cfg-value.stderr6
-rw-r--r--tests/ui/check-cfg/mix.rs4
-rw-r--r--tests/ui/check-cfg/mix.stderr82
-rw-r--r--tests/ui/check-cfg/no-values.stderr4
-rw-r--r--tests/ui/check-cfg/values-target-json.stderr4
-rw-r--r--tests/ui/check-cfg/well-known-names.stderr6
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr8
-rw-r--r--tests/ui/dropck/explicit-drop-bounds.bad1.stderr35
-rw-r--r--tests/ui/dropck/explicit-drop-bounds.bad2.stderr35
-rw-r--r--tests/ui/dropck/explicit-drop-bounds.rs44
-rw-r--r--tests/ui/dropck/explicit-implied-outlives.bad1.stderr15
-rw-r--r--tests/ui/dropck/explicit-implied-outlives.bad2.stderr15
-rw-r--r--tests/ui/dropck/explicit-implied-outlives.rs43
-rw-r--r--tests/ui/dropck/transitive-outlives-2.rs18
-rw-r--r--tests/ui/dropck/transitive-outlives.bad.stderr15
-rw-r--r--tests/ui/dropck/transitive-outlives.rs26
-rw-r--r--tests/ui/dropck/trivial-impl-bounds.rs34
-rw-r--r--tests/ui/extern-flag/auxiliary/panic_handler.rs17
-rw-r--r--tests/ui/extern-flag/force-extern.rs9
-rw-r--r--tests/ui/extern-flag/no-force-extern.rs10
-rw-r--r--tests/ui/extern-flag/redundant-force-extern.rs11
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-2.rs12
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr21
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs8
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr21
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib.rs7
-rw-r--r--tests/ui/feature-gates/feature-gate-raw-dylib.stderr12
-rw-r--r--tests/ui/impl-trait/issues/issue-86800.rs10
-rw-r--r--tests/ui/impl-trait/issues/issue-86800.stderr14
-rw-r--r--tests/ui/layout/debug.rs48
-rw-r--r--tests/ui/layout/debug.stderr220
-rw-r--r--tests/ui/lint/internal/trivial-diagnostics.rs8
-rw-r--r--tests/ui/lint/internal/trivial-diagnostics.stderr15
-rw-r--r--tests/ui/optimization-remark.rs2
-rw-r--r--tests/ui/panics/default-backtrace-ice.rs14
-rw-r--r--tests/ui/panics/default-backtrace-ice.stderr5
-rw-r--r--tests/ui/parser/eq-less-to-less-eq.rs33
-rw-r--r--tests/ui/parser/eq-less-to-less-eq.stderr34
-rw-r--r--tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs19
-rw-r--r--tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr5
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs13
-rw-r--r--tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr8
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr6
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr4
-rw-r--r--tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs1
-rw-r--r--tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr2
-rw-r--r--tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs1
-rw-r--r--tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr2
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs7
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs13
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr21
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rsbin0 -> 565 bytes
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderrbin0 -> 674 bytes
-rw-r--r--tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs10
-rw-r--r--tests/ui/specialization/issue-111232.rs11
-rw-r--r--tests/ui/specialization/issue-111232.stderr11
-rw-r--r--tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr24
-rw-r--r--tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs25
-rw-r--r--tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr11
-rwxr-xr-xx5
-rwxr-xr-xx.ps15
427 files changed, 6102 insertions, 2488 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dcdaa06caa2..eb37fe9c801 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -98,9 +98,6 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -170,6 +167,7 @@ jobs:
       TOOLSTATE_PUBLISH: 1
       CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
       ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      AWS_REGION: us-west-1
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
     strategy:
@@ -521,9 +519,6 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -593,6 +588,7 @@ jobs:
       TOOLSTATE_PUBLISH: 1
       CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
       ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      AWS_REGION: us-west-1
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     strategy:
@@ -637,9 +633,6 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -706,6 +699,7 @@ jobs:
       TOOLSTATE_PUBLISH: 1
       CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
       ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      AWS_REGION: us-west-1
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
     steps:
diff --git a/Cargo.lock b/Cargo.lock
index e69b36cb983..724587a4a71 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -577,7 +577,7 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
 
 [[package]]
 name = "clippy"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "clap 4.2.1",
  "clippy_lints",
@@ -619,7 +619,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "arrayvec",
  "cargo_metadata 0.15.3",
@@ -643,7 +643,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -969,7 +969,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "itertools",
  "quote",
@@ -2909,9 +2909,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d65b1271cdac365b71b59570ea35d945dea2dd2cc47eba3d33b4bd1e0190ac6d"
+checksum = "8ed2a90dfa5232ed5ff21d53d4df655f315ab316ea06fc508f1c74bcedb1ce6c"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -4093,6 +4093,7 @@ dependencies = [
 name = "rustc_smir"
 version = "0.0.0"
 dependencies = [
+ "rustc_hir",
  "rustc_middle",
  "rustc_span",
  "tracing",
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index b4597d5bc78..3d97d9b4895 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -729,42 +729,73 @@ pub trait LayoutCalculator {
             align = align.max(AbiAndPrefAlign::new(repr_align));
         }
 
-        let optimize = !repr.inhibit_union_abi_opt();
+        // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
+        // disabled, we can use that common ABI for the union as a whole.
+        struct AbiMismatch;
+        let mut common_non_zst_abi_and_align = if repr.inhibit_union_abi_opt() {
+            // Can't optimize
+            Err(AbiMismatch)
+        } else {
+            Ok(None)
+        };
+
         let mut size = Size::ZERO;
-        let mut abi = Abi::Aggregate { sized: true };
         let only_variant = &variants[FIRST_VARIANT];
         for field in only_variant {
             assert!(field.0.is_sized());
+
             align = align.max(field.align());
+            size = cmp::max(size, field.size());
 
-            // If all non-ZST fields have the same ABI, forward this ABI
-            if optimize && !field.0.is_zst() {
+            if field.0.is_zst() {
+                // Nothing more to do for ZST fields
+                continue;
+            }
+
+            if let Ok(common) = common_non_zst_abi_and_align {
                 // Discard valid range information and allow undef
-                let field_abi = match field.abi() {
-                    Abi::Scalar(x) => Abi::Scalar(x.to_union()),
-                    Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
-                    Abi::Vector { element: x, count } => {
-                        Abi::Vector { element: x.to_union(), count }
-                    }
-                    Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
-                };
+                let field_abi = field.abi().to_union();
 
-                if size == Size::ZERO {
-                    // first non ZST: initialize 'abi'
-                    abi = field_abi;
-                } else if abi != field_abi {
-                    // different fields have different ABI: reset to Aggregate
-                    abi = Abi::Aggregate { sized: true };
+                if let Some((common_abi, common_align)) = common {
+                    if common_abi != field_abi {
+                        // Different fields have different ABI: disable opt
+                        common_non_zst_abi_and_align = Err(AbiMismatch);
+                    } else {
+                        // Fields with the same non-Aggregate ABI should also
+                        // have the same alignment
+                        if !matches!(common_abi, Abi::Aggregate { .. }) {
+                            assert_eq!(
+                                common_align,
+                                field.align().abi,
+                                "non-Aggregate field with matching ABI but differing alignment"
+                            );
+                        }
+                    }
+                } else {
+                    // First non-ZST field: record its ABI and alignment
+                    common_non_zst_abi_and_align = Ok(Some((field_abi, field.align().abi)));
                 }
             }
-
-            size = cmp::max(size, field.size());
         }
 
         if let Some(pack) = repr.pack {
             align = align.min(AbiAndPrefAlign::new(pack));
         }
 
+        // If all non-ZST fields have the same ABI, we may forward that ABI
+        // for the union as a whole, unless otherwise inhibited.
+        let abi = match common_non_zst_abi_and_align {
+            Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true },
+            Ok(Some((abi, _))) => {
+                if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
+                    // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
+                    Abi::Aggregate { sized: true }
+                } else {
+                    abi
+                }
+            }
+        };
+
         Some(LayoutS {
             variants: Variants::Single { index: FIRST_VARIANT },
             fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?),
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index d01a9b00304..43db66a3c28 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1272,6 +1272,50 @@ impl Abi {
     pub fn is_scalar(&self) -> bool {
         matches!(*self, Abi::Scalar(_))
     }
+
+    /// Returns the fixed alignment of this ABI, if any is mandated.
+    pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
+        Some(match *self {
+            Abi::Scalar(s) => s.align(cx),
+            Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
+            Abi::Vector { element, count } => {
+                cx.data_layout().vector_align(element.size(cx) * count)
+            }
+            Abi::Uninhabited | Abi::Aggregate { .. } => return None,
+        })
+    }
+
+    /// Returns the fixed size of this ABI, if any is mandated.
+    pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
+        Some(match *self {
+            Abi::Scalar(s) => {
+                // No padding in scalars.
+                s.size(cx)
+            }
+            Abi::ScalarPair(s1, s2) => {
+                // May have some padding between the pair.
+                let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
+                (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
+            }
+            Abi::Vector { element, count } => {
+                // No padding in vectors, except possibly for trailing padding
+                // to make the size a multiple of align (e.g. for vectors of size 3).
+                (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
+            }
+            Abi::Uninhabited | Abi::Aggregate { .. } => return None,
+        })
+    }
+
+    /// Discard validity range information and allow undef.
+    pub fn to_union(&self) -> Self {
+        assert!(self.is_sized());
+        match *self {
+            Abi::Scalar(s) => Abi::Scalar(s.to_union()),
+            Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()),
+            Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count },
+            Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
+        }
+    }
 }
 
 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index b5dba0713bf..e3ac8a8784a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1821,6 +1821,8 @@ pub enum LitKind {
     /// A byte string (`b"foo"`). Not stored as a symbol because it might be
     /// non-utf8, and symbols only allow utf8 strings.
     ByteStr(Lrc<[u8]>, StrStyle),
+    /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end.
+    CStr(Lrc<[u8]>, StrStyle),
     /// A byte char (`b'f'`).
     Byte(u8),
     /// A character literal (`'a'`).
@@ -1875,6 +1877,7 @@ impl LitKind {
             // unsuffixed variants
             LitKind::Str(..)
             | LitKind::ByteStr(..)
+            | LitKind::CStr(..)
             | LitKind::Byte(..)
             | LitKind::Char(..)
             | LitKind::Int(_, LitIntType::Unsuffixed)
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f947ae4d057..42b843482a3 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -74,6 +74,8 @@ pub enum LitKind {
     StrRaw(u8), // raw string delimited by `n` hash symbols
     ByteStr,
     ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
+    CStr,
+    CStrRaw(u8),
     Err,
 }
 
@@ -141,6 +143,10 @@ impl fmt::Display for Lit {
                 delim = "#".repeat(n as usize),
                 string = symbol
             )?,
+            CStr => write!(f, "c\"{symbol}\"")?,
+            CStrRaw(n) => {
+                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
+            }
             Integer | Float | Bool | Err => write!(f, "{symbol}")?,
         }
 
@@ -170,6 +176,7 @@ impl LitKind {
             Float => "float",
             Str | StrRaw(..) => "string",
             ByteStr | ByteStrRaw(..) => "byte string",
+            CStr | CStrRaw(..) => "C string",
             Err => "error",
         }
     }
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 74b842ac96e..15a54fe13d0 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,9 +2,13 @@
 
 use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
 use crate::token::{self, Token};
-use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
+use rustc_lexer::unescape::{
+    byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,
+    Mode,
+};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
+use std::ops::Range;
 use std::{ascii, fmt, str};
 
 // Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -35,6 +39,7 @@ pub enum LitError {
     InvalidFloatSuffix,
     NonDecimalFloat(u32),
     IntTooLarge(u32),
+    NulInCStr(Range<usize>),
 }
 
 impl LitKind {
@@ -158,6 +163,52 @@ impl LitKind {
 
                 LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
             }
+            token::CStr => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
+                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+                        error = Err(LitError::NulInCStr(span));
+                    }
+                    Ok(CStrUnit::Byte(b)) => buf.push(b),
+                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+                    Ok(CStrUnit::Char(c)) => {
+                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                    }
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
+                        }
+                    }
+                });
+                error?;
+                buf.push(0);
+                LitKind::CStr(buf.into(), StrStyle::Cooked)
+            }
+            token::CStrRaw(n) => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
+                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+                        error = Err(LitError::NulInCStr(span));
+                    }
+                    Ok(CStrUnit::Byte(b)) => buf.push(b),
+                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+                    Ok(CStrUnit::Char(c)) => {
+                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                    }
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
+                        }
+                    }
+                });
+                error?;
+                buf.push(0);
+                LitKind::CStr(buf.into(), StrStyle::Raw(n))
+            }
             token::Err => LitKind::Err,
         })
     }
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {
                     string = symbol
                 )?;
             }
+            LitKind::CStr(ref bytes, StrStyle::Cooked) => {
+                write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))?
+            }
+            LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {
+                // This can only be valid UTF-8.
+                let symbol = str::from_utf8(bytes).unwrap();
+                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
+            }
             LitKind::Int(n, ty) => {
                 write!(f, "{n}")?;
                 match ty {
@@ -237,6 +296,8 @@ impl MetaItemLit {
             LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
             LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
             LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
+            LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,
+            LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),
             LitKind::Byte(_) => token::Byte,
             LitKind::Char(_) => token::Char,
             LitKind::Int(..) => token::Integer,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index a46fe9e898f..b960671bf6e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -572,6 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
             }
         };
     }
+    gate_all!(c_str_literals, "`c\"..\"` literals are experimental");
     gate_all!(
         if_let_guard,
         "`if let` guards are experimental",
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index ae346510ccc..3f80728a260 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -210,6 +210,10 @@ pub fn literal_to_string(lit: token::Lit) -> String {
         token::ByteStrRaw(n) => {
             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
         }
+        token::CStr => format!("c\"{symbol}\""),
+        token::CStrRaw(n) => {
+            format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
+        }
         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
     };
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index d2d3792345f..2a3092d3c7b 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -5,6 +5,7 @@ use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedM
 use rustc_ast_pretty::pprust;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::{feature_err, ParseSess};
@@ -581,32 +582,32 @@ pub fn cfg_matches(
 ) -> bool {
     eval_condition(cfg, sess, features, &mut |cfg| {
         try_gate_cfg(cfg.name, cfg.span, sess, features);
-        if let Some(names_valid) = &sess.check_config.names_valid {
-            if !names_valid.contains(&cfg.name) {
+        match sess.check_config.expecteds.get(&cfg.name) {
+            Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
                 sess.buffer_lint_with_diagnostic(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
-                    "unexpected `cfg` condition name",
-                    BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
+                    "unexpected `cfg` condition value",
+                    BuiltinLintDiagnostics::UnexpectedCfgValue(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
                 );
             }
-        }
-        if let Some(value) = cfg.value {
-            if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
-                if !values.contains(&value) {
-                    sess.buffer_lint_with_diagnostic(
-                        UNEXPECTED_CFGS,
-                        cfg.span,
-                        lint_node_id,
-                        "unexpected `cfg` condition value",
-                        BuiltinLintDiagnostics::UnexpectedCfg(
-                            (cfg.name, cfg.name_span),
-                            cfg.value_span.map(|vs| (value, vs)),
-                        ),
-                    );
-                }
+            None if sess.check_config.exhaustive_names => {
+                sess.buffer_lint_with_diagnostic(
+                    UNEXPECTED_CFGS,
+                    cfg.span,
+                    lint_node_id,
+                    "unexpected `cfg` condition name",
+                    BuiltinLintDiagnostics::UnexpectedCfgName(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
+                );
             }
+            _ => { /* not unexpected */ }
         }
         sess.config.contains(&(cfg.name, cfg.value))
     })
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index c4c54620e04..315303b25fe 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -498,11 +498,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
         let next_region = self.infcx.next_region_var(origin);
         let vid = next_region.as_var();
 
-        if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
+        if cfg!(debug_assertions) {
             debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
             let ctxt = get_ctxt_fn();
             let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
-            var_to_origin.insert(vid, ctxt);
+            assert_eq!(var_to_origin.insert(vid, ctxt), None);
         }
 
         next_region
@@ -520,11 +520,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
         let next_region = self.infcx.next_nll_region_var(origin);
         let vid = next_region.as_var();
 
-        if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
+        if cfg!(debug_assertions) {
             debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
             let ctxt = get_ctxt_fn();
             let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
-            var_to_origin.insert(vid, ctxt);
+            assert_eq!(var_to_origin.insert(vid, ctxt), None);
         }
 
         next_region
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 7e6d17ec343..7158c62b548 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -131,9 +131,13 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
             ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
         };
 
-        if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
+        if cfg!(debug_assertions) {
             let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
-            var_to_origin.insert(reg.as_var(), RegionCtxt::Placeholder(reg_info));
+            let new = RegionCtxt::Placeholder(reg_info);
+            let prev = var_to_origin.insert(reg.as_var(), new);
+            if let Some(prev) = prev {
+                assert_eq!(new, prev);
+            }
         }
 
         reg
@@ -146,9 +150,10 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
             universe,
         );
 
-        if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
+        if cfg!(debug_assertions) {
             let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
-            var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
+            let prev = var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
+            assert_eq!(prev, None);
         }
 
         reg
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index b92964d03e9..50e88ae2eee 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -32,6 +32,10 @@ pub fn expand_concat(
                 Ok(ast::LitKind::Bool(b)) => {
                     accumulator.push_str(&b.to_string());
                 }
+                Ok(ast::LitKind::CStr(..)) => {
+                    cx.span_err(e.span, "cannot concatenate a C string literal");
+                    has_errors = true;
+                }
                 Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
                     cx.emit_err(errors::ConcatBytestr { span: e.span });
                     has_errors = true;
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index ba639c0a9fe..5ef35af0a05 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -18,6 +18,11 @@ fn invalid_type_err(
     };
     let snippet = cx.sess.source_map().span_to_snippet(span).ok();
     match ast::LitKind::from_token_lit(token_lit) {
+        Ok(ast::LitKind::CStr(_, _)) => {
+            // FIXME(c_str_literals): should concatenation of C string literals
+            // include the null bytes in the end?
+            cx.span_err(span, "cannot concatenate C string literals");
+        }
         Ok(ast::LitKind::Char(_)) => {
             let sugg =
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index b6d7484bcce..d77634741fb 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -24,7 +24,7 @@ codegen_llvm_error_writing_def_file =
     Error writing .DEF file: {$error}
 
 codegen_llvm_error_calling_dlltool =
-    Error calling dlltool: {$error}
+    Error calling dlltool '{$dlltool_path}': {$error}
 
 codegen_llvm_dlltool_fail_import_library =
     Dlltool could not create import library: {$stdout}
@@ -82,7 +82,7 @@ codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO
 codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
 codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
 
-codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name}: {$message}
+codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
 codegen_llvm_from_llvm_diag = {$message}
 
 codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 12da21dc477..a6416e9540c 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -198,7 +198,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 "arm" => ("arm", "--32"),
                 _ => panic!("unsupported arch {}", sess.target.arch),
             };
-            let result = std::process::Command::new(dlltool)
+            let result = std::process::Command::new(&dlltool)
                 .args([
                     "-d",
                     def_file_path.to_str().unwrap(),
@@ -218,9 +218,13 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
 
             match result {
                 Err(e) => {
-                    sess.emit_fatal(ErrorCallingDllTool { error: e });
+                    sess.emit_fatal(ErrorCallingDllTool {
+                        dlltool_path: dlltool.to_string_lossy(),
+                        error: e,
+                    });
                 }
-                Ok(output) if !output.status.success() => {
+                // dlltool returns '0' on failure, so check for error output instead.
+                Ok(output) if !output.stderr.is_empty() => {
                     sess.emit_fatal(DlltoolFailImportLibrary {
                         stdout: String::from_utf8_lossy(&output.stdout),
                         stderr: String::from_utf8_lossy(&output.stderr),
@@ -431,7 +435,7 @@ fn string_to_io_error(s: String) -> io::Error {
 
 fn find_binutils_dlltool(sess: &Session) -> OsString {
     assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
-    if let Some(dlltool_path) = &sess.opts.unstable_opts.dlltool {
+    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
         return dlltool_path.clone().into_os_string();
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 7136f750f39..ca2eab28f87 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -31,6 +31,7 @@ use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
 use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
 
+use crate::llvm::diagnostic::OptimizationDiagnosticKind;
 use libc::{c_char, c_int, c_uint, c_void, size_t};
 use std::ffi::CString;
 use std::fs;
@@ -363,6 +364,15 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
                     line: opt.line,
                     column: opt.column,
                     pass_name: &opt.pass_name,
+                    kind: match opt.kind {
+                        OptimizationDiagnosticKind::OptimizationRemark => "success",
+                        OptimizationDiagnosticKind::OptimizationMissed
+                        | OptimizationDiagnosticKind::OptimizationFailure => "missed",
+                        OptimizationDiagnosticKind::OptimizationAnalysis
+                        | OptimizationDiagnosticKind::OptimizationAnalysisFPCommute
+                        | OptimizationDiagnosticKind::OptimizationAnalysisAliasing => "analysis",
+                        OptimizationDiagnosticKind::OptimizationRemarkOther => "other",
+                    },
                     message: &opt.message,
                 });
             }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 2e9f89f4196..b138b0c0e70 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -322,7 +322,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let tcx = self.tcx;
 
         let def_id = instance.def_id();
-        let containing_scope = get_containing_scope(self, instance);
+        let (containing_scope, is_method) = get_containing_scope(self, instance);
         let span = tcx.def_span(def_id);
         let loc = self.lookup_debug_loc(span.lo());
         let file_metadata = file_metadata(self, &loc.file);
@@ -378,8 +378,29 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             }
         }
 
-        unsafe {
-            return llvm::LLVMRustDIBuilderCreateFunction(
+        // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because
+        // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
+        // When we use this `decl` below, the subprogram definition gets created at the CU level
+        // with a DW_AT_specification pointing back to the type's declaration.
+        let decl = is_method.then(|| unsafe {
+            llvm::LLVMRustDIBuilderCreateMethod(
+                DIB(self),
+                containing_scope,
+                name.as_ptr().cast(),
+                name.len(),
+                linkage_name.as_ptr().cast(),
+                linkage_name.len(),
+                file_metadata,
+                loc.line,
+                function_type_metadata,
+                flags,
+                spflags & !DISPFlags::SPFlagDefinition,
+                template_parameters,
+            )
+        });
+
+        return unsafe {
+            llvm::LLVMRustDIBuilderCreateFunction(
                 DIB(self),
                 containing_scope,
                 name.as_ptr().cast(),
@@ -394,9 +415,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 spflags,
                 maybe_definition_llfn,
                 template_parameters,
-                None,
-            );
-        }
+                decl,
+            )
+        };
 
         fn get_function_signature<'ll, 'tcx>(
             cx: &CodegenCx<'ll, 'tcx>,
@@ -493,14 +514,16 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             names
         }
 
+        /// Returns a scope, plus `true` if that's a type scope for "class" methods,
+        /// otherwise `false` for plain namespace scopes.
         fn get_containing_scope<'ll, 'tcx>(
             cx: &CodegenCx<'ll, 'tcx>,
             instance: Instance<'tcx>,
-        ) -> &'ll DIScope {
+        ) -> (&'ll DIScope, bool) {
             // First, let's see if this is a method within an inherent impl. Because
             // if yes, we want to make the result subroutine DIE a child of the
             // subroutine's self-type.
-            let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| {
+            if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
                 // If the method does *not* belong to a trait, proceed
                 if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
                     let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
@@ -511,39 +534,33 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
                     // Only "class" methods are generally understood by LLVM,
                     // so avoid methods on other types (e.g., `<*mut T>::null`).
-                    match impl_self_ty.kind() {
-                        ty::Adt(def, ..) if !def.is_box() => {
-                            // Again, only create type information if full debuginfo is enabled
-                            if cx.sess().opts.debuginfo == DebugInfo::Full
-                                && !impl_self_ty.has_param()
-                            {
-                                Some(type_di_node(cx, impl_self_ty))
-                            } else {
-                                Some(namespace::item_namespace(cx, def.did()))
-                            }
+                    if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() {
+                        // Again, only create type information if full debuginfo is enabled
+                        if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
+                        {
+                            return (type_di_node(cx, impl_self_ty), true);
+                        } else {
+                            return (namespace::item_namespace(cx, def.did()), false);
                         }
-                        _ => None,
                     }
                 } else {
                     // For trait method impls we still use the "parallel namespace"
                     // strategy
-                    None
                 }
-            });
+            }
 
-            self_type.unwrap_or_else(|| {
-                namespace::item_namespace(
-                    cx,
-                    DefId {
-                        krate: instance.def_id().krate,
-                        index: cx
-                            .tcx
-                            .def_key(instance.def_id())
-                            .parent
-                            .expect("get_containing_scope: missing parent?"),
-                    },
-                )
-            })
+            let scope = namespace::item_namespace(
+                cx,
+                DefId {
+                    krate: instance.def_id().krate,
+                    index: cx
+                        .tcx
+                        .def_key(instance.def_id())
+                        .parent
+                        .expect("get_containing_scope: missing parent?"),
+                },
+            );
+            (scope, false)
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index bae88d94293..6a9173ab450 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -67,7 +67,8 @@ pub(crate) struct ErrorWritingDEFFile {
 
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_error_calling_dlltool)]
-pub(crate) struct ErrorCallingDllTool {
+pub(crate) struct ErrorCallingDllTool<'a> {
+    pub dlltool_path: Cow<'a, str>,
     pub error: std::io::Error,
 }
 
@@ -195,6 +196,7 @@ pub(crate) struct FromLlvmOptimizationDiag<'a> {
     pub line: std::ffi::c_uint,
     pub column: std::ffi::c_uint,
     pub pass_name: &'a str,
+    pub kind: &'a str,
     pub message: &'a str,
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index c95148013eb..61365e6dc4b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1987,6 +1987,21 @@ extern "C" {
         Decl: Option<&'a DIDescriptor>,
     ) -> &'a DISubprogram;
 
+    pub fn LLVMRustDIBuilderCreateMethod<'a>(
+        Builder: &DIBuilder<'a>,
+        Scope: &'a DIDescriptor,
+        Name: *const c_char,
+        NameLen: size_t,
+        LinkageName: *const c_char,
+        LinkageNameLen: size_t,
+        File: &'a DIFile,
+        LineNo: c_uint,
+        Ty: &'a DIType,
+        Flags: DIFlags,
+        SPFlags: DISPFlags,
+        TParam: &'a DIArray,
+    ) -> &'a DISubprogram;
+
     pub fn LLVMRustDIBuilderCreateBasicType<'a>(
         Builder: &DIBuilder<'a>,
         Name: *const c_char,
@@ -2249,7 +2264,7 @@ extern "C" {
 
     pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
 
-    pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
+    pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine, cpu: *const c_char);
     pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
     pub fn LLVMRustGetTargetFeature(
         T: &TargetMachine,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 46692fd5e8b..2fbdab9f8ce 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -329,7 +329,14 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
     require_inited();
     let tm = create_informational_target_machine(sess);
     match req {
-        PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) },
+        PrintRequest::TargetCPUs => {
+            // SAFETY generate a C compatible string from a byte slice to pass
+            // the target CPU name into LLVM, the lifetime of the reference is
+            // at least as long as the C function
+            let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
+                .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
+            unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) };
+        }
         PrintRequest::TargetFeatures => print_target_features(sess, tm),
         _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c42d59bd51c..c323372bda4 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1821,9 +1821,15 @@ impl SharedEmitterMain {
                         let source = sess
                             .source_map()
                             .new_source_file(FileName::inline_asm_source_code(&buffer), buffer);
-                        let source_span = Span::with_root_ctxt(source.start_pos, source.end_pos);
-                        let spans: Vec<_> =
-                            spans.iter().map(|sp| source_span.from_inner(*sp)).collect();
+                        let spans: Vec<_> = spans
+                            .iter()
+                            .map(|sp| {
+                                Span::with_root_ctxt(
+                                    source.normalized_byte_pos(sp.start as u32),
+                                    source.normalized_byte_pos(sp.end as u32),
+                                )
+                            })
+                            .collect();
                         err.span_note(spans, "instantiated into assembly here");
                     }
 
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 5cc87d1e56c..8dae5dab429 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -592,15 +592,6 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
     use rustc_ast::{LitIntType, LitKind, MetaItemLit};
-    if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
-        feature_err(
-            &tcx.sess.parse_sess,
-            sym::raw_dylib,
-            attr.span,
-            "`#[link_ordinal]` is unstable on x86",
-        )
-        .emit();
-    }
     let meta_item_list = attr.meta_item_list();
     let meta_item_list = meta_item_list.as_deref();
     let sole_meta_list = match meta_item_list {
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 5fac485de64..405f3d5b66d 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -25,7 +25,7 @@ use rustc_data_structures::profiling::{
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{
-    DiagnosticMessage, ErrorGuaranteed, PResult, SubdiagnosticMessage, TerminalUrl,
+    DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl,
 };
 use rustc_feature::find_gated_cfg;
 use rustc_fluent_macro::fluent_messages;
@@ -55,7 +55,7 @@ use std::panic::{self, catch_unwind};
 use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
 use std::str;
-use std::sync::LazyLock;
+use std::sync::OnceLock;
 use std::time::Instant;
 
 // This import blocks the use of panicking `print` and `println` in all the code
@@ -119,7 +119,7 @@ pub const EXIT_SUCCESS: i32 = 0;
 /// Exit status code used for compilation failures and invalid flags.
 pub const EXIT_FAILURE: i32 = 1;
 
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
+pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
 
 const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
@@ -1178,6 +1178,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
 pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuaranteed> {
     catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
         if value.is::<rustc_errors::FatalErrorMarker>() {
+            #[allow(deprecated)]
             ErrorGuaranteed::unchecked_claim_error_was_emitted()
         } else {
             panic::resume_unwind(value);
@@ -1195,35 +1196,58 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
     }
 }
 
-static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    LazyLock::new(|| {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(|info| {
-            // If the error was caused by a broken pipe then this is not a bug.
-            // Write the error and return immediately. See #98700.
-            #[cfg(windows)]
-            if let Some(msg) = info.payload().downcast_ref::<String>() {
-                if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
-                {
-                    early_error_no_abort(ErrorOutputType::default(), &msg);
-                    return;
-                }
-            };
+/// Stores the default panic hook, from before [`install_ice_hook`] was called.
+static DEFAULT_HOOK: OnceLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
+    OnceLock::new();
+
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// The hook is intended to be useable even by external tools. You can pass a custom
+/// `bug_report_url`, or report arbitrary info in `extra_info`. Note that `extra_info` is called in
+/// a context where *the thread is currently panicking*, so it must not panic or the process will
+/// abort.
+///
+/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
+/// extra_info.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) {
+    // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
+    // full backtraces. When a compiler ICE happens, we want to gather
+    // as much information as possible to present in the issue opened
+    // by the user. Compiler developers and other rustc users can
+    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+    // (e.g. `RUST_BACKTRACE=1`)
+    if std::env::var("RUST_BACKTRACE").is_err() {
+        std::env::set_var("RUST_BACKTRACE", "full");
+    }
 
-            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            // Don't do this for delayed bugs, which already emit their own more useful backtrace.
-            if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
-                (*DEFAULT_HOOK)(info);
+    let default_hook = DEFAULT_HOOK.get_or_init(panic::take_hook);
 
-                // Separate the output with an empty line
-                eprintln!();
+    panic::set_hook(Box::new(move |info| {
+        // If the error was caused by a broken pipe then this is not a bug.
+        // Write the error and return immediately. See #98700.
+        #[cfg(windows)]
+        if let Some(msg) = info.payload().downcast_ref::<String>() {
+            if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
+                early_error_no_abort(ErrorOutputType::default(), &msg);
+                return;
             }
+        };
 
-            // Print the ICE message
-            report_ice(info, BUG_REPORT_URL);
-        }));
-        hook
-    });
+        // Invoke the default handler, which prints the actual panic message and optionally a backtrace
+        // Don't do this for delayed bugs, which already emit their own more useful backtrace.
+        if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
+            (*default_hook)(info);
+
+            // Separate the output with an empty line
+            eprintln!();
+        }
+
+        // Print the ICE message
+        report_ice(info, bug_report_url, extra_info);
+    }));
+}
 
 /// Prints the ICE message, including query stack, but without backtrace.
 ///
@@ -1231,7 +1255,7 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
 ///
 /// When `install_ice_hook` is called, this function will be called as the panic
 /// hook.
-pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
+pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
     let fallback_bundle =
         rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
@@ -1276,6 +1300,10 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
 
     interface::try_print_query_stack(&handler, num_frames);
 
+    // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
+    // printed all the relevant info.
+    extra_info(&handler);
+
     #[cfg(windows)]
     if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
         // Trigger a debugger if we crashed during bootstrap
@@ -1283,22 +1311,6 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     }
 }
 
-/// Installs a panic hook that will print the ICE message on unexpected panics.
-///
-/// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook() {
-    // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
-    // full backtraces. When a compiler ICE happens, we want to gather
-    // as much information as possible to present in the issue opened
-    // by the user. Compiler developers and other rustc users can
-    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
-    // (e.g. `RUST_BACKTRACE=1`)
-    if std::env::var("RUST_BACKTRACE").is_err() {
-        std::env::set_var("RUST_BACKTRACE", "full");
-    }
-    LazyLock::force(&DEFAULT_HOOK);
-}
-
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
@@ -1369,7 +1381,7 @@ pub fn main() -> ! {
     init_rustc_env_logger();
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
-    install_ice_hook();
+    install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
     let exit_code = catch_with_exit_code(|| {
         let args = env::args_os()
             .enumerate()
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 1f1398342b1..ef528d87cb2 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -192,6 +192,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
                      became non-error ({:?}), after original `.emit()`",
                     db.inner.diagnostic.level,
                 );
+                #[allow(deprecated)]
                 ErrorGuaranteed::unchecked_claim_error_was_emitted()
             }
         }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index f9c062d3a21..fcbd9a53b48 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1069,26 +1069,29 @@ impl Handler {
     }
 
     pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
-        self.inner.borrow().has_errors().then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().has_errors().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
 
     pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
-        self.inner
-            .borrow()
-            .has_errors_or_lint_errors()
-            .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().has_errors_or_lint_errors().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
     pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> {
-        self.inner
-            .borrow()
-            .has_errors_or_delayed_span_bugs()
-            .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().has_errors_or_delayed_span_bugs().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
     pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
-        self.inner
-            .borrow()
-            .is_compilation_going_to_fail()
-            .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().is_compilation_going_to_fail().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
 
     pub fn print_error_count(&self, registry: &Registry) {
@@ -1333,6 +1336,7 @@ impl HandlerInner {
                 .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
 
             if !self.flags.report_delayed_bugs {
+                #[allow(deprecated)]
                 return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
             }
         }
@@ -1411,7 +1415,10 @@ impl HandlerInner {
                     self.bump_err_count();
                 }
 
-                guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+                #[allow(deprecated)]
+                {
+                    guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+                }
             } else {
                 self.bump_warn_count();
             }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 1e7d07bc22d..891e84a2f30 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -61,6 +61,8 @@ impl FromInternal<token::LitKind> for LitKind {
             token::StrRaw(n) => LitKind::StrRaw(n),
             token::ByteStr => LitKind::ByteStr,
             token::ByteStrRaw(n) => LitKind::ByteStrRaw(n),
+            token::CStr => LitKind::CStr,
+            token::CStrRaw(n) => LitKind::CStrRaw(n),
             token::Err => LitKind::Err,
             token::Bool => unreachable!(),
         }
@@ -78,6 +80,8 @@ impl ToInternal<token::LitKind> for LitKind {
             LitKind::StrRaw(n) => token::StrRaw(n),
             LitKind::ByteStr => token::ByteStr,
             LitKind::ByteStrRaw(n) => token::ByteStrRaw(n),
+            LitKind::CStr => token::CStr,
+            LitKind::CStrRaw(n) => token::CStrRaw(n),
             LitKind::Err => token::Err,
         }
     }
@@ -436,6 +440,8 @@ impl server::FreeFunctions for Rustc<'_, '_> {
                 | token::LitKind::StrRaw(_)
                 | token::LitKind::ByteStr
                 | token::LitKind::ByteStrRaw(_)
+                | token::LitKind::CStr
+                | token::LitKind::CStrRaw(_)
                 | token::LitKind::Err => return Err(()),
                 token::LitKind::Integer | token::LitKind::Float => {}
             }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 70d608a5ea4..5b2e4d15dfe 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -280,6 +280,8 @@ declare_features! (
     (accepted, pub_restricted, "1.18.0", Some(32409), None),
     /// Allows use of the postfix `?` operator in expressions.
     (accepted, question_mark, "1.13.0", Some(31436), None),
+    /// Allows the use of raw-dylibs (RFC 2627).
+    (accepted, raw_dylib, "CURRENT_RUSTC_VERSION", Some(58713), None),
     /// Allows keywords to be escaped for use as identifiers.
     (accepted, raw_identifiers, "1.30.0", Some(48589), None),
     /// Allows relaxing the coherence rules such that
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index dc5dc4608a0..27d30c315af 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -313,6 +313,8 @@ declare_features! (
     (active, async_closure, "1.37.0", Some(62290), None),
     /// Allows async functions to be declared, implemented, and used in traits.
     (active, async_fn_in_trait, "1.66.0", Some(91611), None),
+    /// Allows `c"foo"` literals.
+    (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None),
     /// Treat `extern "C"` function as nounwind.
     (active, c_unwind, "1.52.0", Some(74990), None),
     /// Allows using C-variadics.
@@ -487,8 +489,6 @@ declare_features! (
     (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
-    /// Allows the use of raw-dylibs (RFC 2627).
-    (active, raw_dylib, "1.65.0", Some(58713), None),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (active, raw_ref_op, "1.41.0", Some(64490), None),
     /// Allows using the `#[register_tool]` attribute.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 0a8bd1d6123..1f08befb180 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -333,6 +333,7 @@ language_item_table! {
     RangeTo,                 sym::RangeTo,             range_to_struct,            Target::Struct,         GenericRequirement::None;
 
     String,                  sym::String,              string,                     Target::Struct,         GenericRequirement::None;
+    CStr,                    sym::CStr,                c_str,                      Target::Struct,         GenericRequirement::None;
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index bae80807f71..5ba1ca1c807 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,12 +1,14 @@
 // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
 //
 // We don't do any drop checking during hir typeck.
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::util::IgnoreRegions;
-use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 use crate::errors;
 use crate::hir::def_id::{DefId, LocalDefId};
@@ -43,21 +45,20 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
         }
     }
     let dtor_self_type = tcx.type_of(drop_impl_did).subst_identity();
-    let dtor_predicates = tcx.predicates_of(drop_impl_did);
     match dtor_self_type.kind() {
-        ty::Adt(adt_def, self_to_impl_substs) => {
+        ty::Adt(adt_def, adt_to_impl_substs) => {
             ensure_drop_params_and_item_params_correspond(
                 tcx,
                 drop_impl_did.expect_local(),
                 adt_def.did(),
-                self_to_impl_substs,
+                adt_to_impl_substs,
             )?;
 
             ensure_drop_predicates_are_implied_by_item_defn(
                 tcx,
-                dtor_predicates,
+                drop_impl_did.expect_local(),
                 adt_def.did().expect_local(),
-                self_to_impl_substs,
+                adt_to_impl_substs,
             )
         }
         _ => {
@@ -78,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     tcx: TyCtxt<'tcx>,
     drop_impl_did: LocalDefId,
     self_type_did: DefId,
-    drop_impl_substs: SubstsRef<'tcx>,
+    adt_to_impl_substs: SubstsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let Err(arg) = tcx.uses_unique_generic_params(drop_impl_substs, IgnoreRegions::No) else {
+    let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, IgnoreRegions::No) else {
         return Ok(())
     };
 
@@ -111,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
 /// implied by assuming the predicates attached to self_type_did.
 fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     tcx: TyCtxt<'tcx>,
-    dtor_predicates: ty::GenericPredicates<'tcx>,
-    self_type_did: LocalDefId,
-    self_to_impl_substs: SubstsRef<'tcx>,
+    drop_impl_def_id: LocalDefId,
+    adt_def_id: LocalDefId,
+    adt_to_impl_substs: SubstsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let mut result = Ok(());
-
-    // Here is an example, analogous to that from
-    // `compare_impl_method`.
-    //
-    // Consider a struct type:
-    //
-    //     struct Type<'c, 'b:'c, 'a> {
-    //         x: &'a Contents            // (contents are irrelevant;
-    //         y: &'c Cell<&'b Contents>, //  only the bounds matter for our purposes.)
-    //     }
-    //
-    // and a Drop impl:
-    //
-    //     impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
-    //         fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
-    //     }
-    //
-    // We start out with self_to_impl_substs, that maps the generic
-    // parameters of Type to that of the Drop impl.
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
+
+    // Take the param-env of the adt and substitute the substs that show up in
+    // the implementation's self type. This gives us the assumptions that the
+    // self ty of the implementation is allowed to know just from it being a
+    // well-formed adt, since that's all we're allowed to assume while proving
+    // the Drop implementation is not specialized.
     //
-    //     self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
-    //
-    // Applying this to the predicates (i.e., assumptions) provided by the item
-    // definition yields the instantiated assumptions:
-    //
-    //     ['y : 'z]
-    //
-    // We then check all of the predicates of the Drop impl:
-    //
-    //     ['y:'z, 'x:'y]
-    //
-    // and ensure each is in the list of instantiated
-    // assumptions. Here, `'y:'z` is present, but `'x:'y` is
-    // absent. So we report an error that the Drop impl injected a
-    // predicate that is not present on the struct definition.
-
-    // We can assume the predicates attached to struct/enum definition
-    // hold.
-    let generic_assumptions = tcx.predicates_of(self_type_did);
-
-    let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
-    let assumptions_in_impl_context = assumptions_in_impl_context.predicates;
-
-    debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates);
-
-    let self_param_env = tcx.param_env(self_type_did);
-
-    // An earlier version of this code attempted to do this checking
-    // via the traits::fulfill machinery. However, it ran into trouble
-    // since the fulfill machinery merely turns outlives-predicates
-    // 'a:'b and T:'b into region inference constraints. It is simpler
-    // just to look for all the predicates directly.
-
-    assert_eq!(dtor_predicates.parent, None);
-    for &(predicate, predicate_sp) in dtor_predicates.predicates {
-        // (We do not need to worry about deep analysis of type
-        // expressions etc because the Drop impls are already forced
-        // to take on a structure that is roughly an alpha-renaming of
-        // the generic parameters of the item definition.)
-
-        // This path now just checks *all* predicates via an instantiation of
-        // the `SimpleEqRelation`, which simply forwards to the `relate` machinery
-        // after taking care of anonymizing late bound regions.
-        //
-        // However, it may be more efficient in the future to batch
-        // the analysis together via the fulfill (see comment above regarding
-        // the usage of the fulfill machinery), rather than the
-        // repeated `.iter().any(..)` calls.
+    // We don't need to normalize this param-env or anything, since we're only
+    // substituting it with free params, so no additional param-env normalization
+    // can occur on top of what has been done in the param_env query itself.
+    let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id))
+        .subst(tcx, adt_to_impl_substs)
+        .with_constness(tcx.constness(drop_impl_def_id));
+
+    for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
+        let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
+        let pred = ocx.normalize(&normalize_cause, param_env, pred);
+        let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl);
+        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
+    }
 
-        // This closure is a more robust way to check `Predicate` equality
-        // than simple `==` checks (which were the previous implementation).
-        // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`,
-        // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait),
-        // while delegating on simple equality for the other `Predicate`.
-        // This implementation solves (Issue #59497) and (Issue #58311).
-        // It is unclear to me at the moment whether the approach based on `relate`
-        // could be extended easily also to the other `Predicate`.
-        let predicate_matches_closure = |p: Predicate<'tcx>| {
-            let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
-            let predicate = predicate.kind();
-            let p = p.kind();
-            match (predicate.skip_binder(), p.skip_binder()) {
-                (
-                    ty::PredicateKind::Clause(ty::Clause::Trait(a)),
-                    ty::PredicateKind::Clause(ty::Clause::Trait(b)),
-                ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
-                (
-                    ty::PredicateKind::Clause(ty::Clause::Projection(a)),
-                    ty::PredicateKind::Clause(ty::Clause::Projection(b)),
-                ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
-                (
-                    ty::PredicateKind::ConstEvaluatable(a),
-                    ty::PredicateKind::ConstEvaluatable(b),
-                ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
-                (
-                    ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
-                        ty_a,
-                        lt_a,
-                    ))),
-                    ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
-                        ty_b,
-                        lt_b,
-                    ))),
-                ) => {
-                    relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
-                        && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
-                }
-                (ty::PredicateKind::WellFormed(arg_a), ty::PredicateKind::WellFormed(arg_b)) => {
-                    relator.relate(predicate.rebind(arg_a), p.rebind(arg_b)).is_ok()
-                }
-                _ => predicate == p,
+    // All of the custom error reporting logic is to preserve parity with the old
+    // error messages.
+    //
+    // They can probably get removed with better treatment of the new `DropImpl`
+    // obligation cause code, and perhaps some custom logic in `report_region_errors`.
+
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let mut guar = None;
+        let mut root_predicates = FxHashSet::default();
+        for error in errors {
+            let root_predicate = error.root_obligation.predicate;
+            if root_predicates.insert(root_predicate) {
+                let item_span = tcx.def_span(adt_def_id);
+                let self_descr = tcx.def_descr(adt_def_id.to_def_id());
+                guar = Some(
+                    struct_span_err!(
+                        tcx.sess,
+                        error.root_obligation.cause.span,
+                        E0367,
+                        "`Drop` impl requires `{root_predicate}` \
+                        but the {self_descr} it is implemented for does not",
+                    )
+                    .span_note(item_span, "the implementor must specify the same requirement")
+                    .emit(),
+                );
             }
-        };
-
-        if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) {
-            let item_span = tcx.def_span(self_type_did);
-            let self_descr = tcx.def_descr(self_type_did.to_def_id());
-            let reported = struct_span_err!(
-                tcx.sess,
-                predicate_sp,
-                E0367,
-                "`Drop` impl requires `{predicate}` but the {self_descr} it is implemented for does not",
-            )
-            .span_note(item_span, "the implementor must specify the same requirement")
-            .emit();
-            result = Err(reported);
         }
+        return Err(guar.unwrap());
     }
 
-    result
-}
-
-/// This is an implementation of the [`TypeRelation`] trait with the
-/// aim of simply comparing for equality (without side-effects).
-///
-/// It is not intended to be used anywhere else other than here.
-pub(crate) struct SimpleEqRelation<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'tcx> SimpleEqRelation<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> SimpleEqRelation<'tcx> {
-        SimpleEqRelation { tcx, param_env }
-    }
-}
-
-impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn tag(&self) -> &'static str {
-        "dropck::SimpleEqRelation"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        _: ty::Variance,
-        _info: ty::VarianceDiagInfo<'tcx>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        // Here we ignore variance because we require drop impl's types
-        // to be *exactly* the same as to the ones in the struct definition.
-        self.relate(a, b)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("SimpleEqRelation::tys(a={:?}, b={:?})", a, b);
-        ty::relate::super_relate_tys(self, a, b)
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("SimpleEqRelation::regions(a={:?}, b={:?})", a, b);
-
-        // We can just equate the regions because LBRs have been
-        // already anonymized.
-        if a == b {
-            Ok(a)
-        } else {
-            // I'm not sure is this `TypeError` is the right one, but
-            // it should not matter as it won't be checked (the dropck
-            // will emit its own, more informative and higher-level errors
-            // in case anything goes wrong).
-            Err(TypeError::RegionsPlaceholderMismatch)
+    let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
+    if !errors.is_empty() {
+        let mut guar = None;
+        for error in errors {
+            let item_span = tcx.def_span(adt_def_id);
+            let self_descr = tcx.def_descr(adt_def_id.to_def_id());
+            let outlives = match error {
+                RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
+                RegionResolutionError::GenericBoundFailure(_, generic, r) => {
+                    format!("{generic}: {r}")
+                }
+                RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
+                RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
+                    format!("{b}: {a}", a = tcx.mk_re_var(a))
+                }
+            };
+            guar = Some(
+                struct_span_err!(
+                    tcx.sess,
+                    error.origin().span(),
+                    E0367,
+                    "`Drop` impl requires `{outlives}` \
+                    but the {self_descr} it is implemented for does not",
+                )
+                .span_note(item_span, "the implementor must specify the same requirement")
+                .emit(),
+            );
         }
+        return Err(guar.unwrap());
     }
 
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b);
-        ty::relate::super_relate_consts(self, a, b)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<'tcx>,
-    {
-        debug!("SimpleEqRelation::binders({:?}: {:?}", a, b);
-
-        // Anonymizing the LBRs is necessary to solve (Issue #59497).
-        // After we do so, it should be totally fine to skip the binders.
-        let anon_a = self.tcx.anonymize_bound_vars(a);
-        let anon_b = self.tcx.anonymize_bound_vars(b);
-        self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
-
-        Ok(a)
-    }
+    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c0ee777722e..30e2c675f59 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -657,7 +657,6 @@ pub enum ImplNotMarkedDefault {
     #[note]
     Err {
         #[primary_span]
-        #[label]
         span: Span,
         cname: Symbol,
         ident: Symbol,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index cbedbad1f38..9e78e6acba5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -854,9 +854,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let result = self
             .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
             .or_else(|error| {
+                let guar = self
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, "method resolution should've emitted an error");
                 let result = match error {
                     method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
-                    _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()),
+                    _ => Err(guar),
                 };
 
                 // If we have a path like `MyTrait::missing_method`, then don't register
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 78bd489a44b..4b8fc7303a2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1300,6 +1300,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
+            ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+                tcx.lifetimes.re_static,
+                tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
+                    .skip_binder(),
+            ),
             ast::LitKind::Err => tcx.ty_error_misc(),
         }
     }
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index d240d8e491f..0c8854e962a 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -30,8 +30,6 @@ use super::*;
 use rustc_middle::ty::relate::{Relate, TypeRelation};
 use rustc_middle::ty::{Const, ImplSubject};
 
-use std::cell::Cell;
-
 /// Whether we should define opaque types or just treat them opaquely.
 ///
 /// Currently only used to prevent predicate matching from matching anything
@@ -84,7 +82,6 @@ impl<'tcx> InferCtxt<'tcx> {
             in_snapshot: self.in_snapshot.clone(),
             universe: self.universe.clone(),
             intercrate: self.intercrate,
-            inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index d798202a644..427d05c8b4d 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -561,8 +561,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     where
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
-        let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt();
-
         let needs_canonical_flags = if canonicalize_region_mode.any() {
             TypeFlags::HAS_INFER |
             TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c9e13be02ff..2a51439b0a9 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -73,6 +73,8 @@ impl<'tcx> InferCtxt<'tcx> {
         R: ObligationEmittingRelation<'tcx>,
     {
         let a_is_expected = relation.a_is_expected();
+        debug_assert!(!a.has_escaping_bound_vars());
+        debug_assert!(!b.has_escaping_bound_vars());
 
         match (a.kind(), b.kind()) {
             // Relate integral variables to other types
@@ -163,6 +165,8 @@ impl<'tcx> InferCtxt<'tcx> {
         R: ObligationEmittingRelation<'tcx>,
     {
         debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
+        debug_assert!(!a.has_escaping_bound_vars());
+        debug_assert!(!b.has_escaping_bound_vars());
         if a == b {
             return Ok(a);
         }
@@ -238,22 +242,12 @@ impl<'tcx> InferCtxt<'tcx> {
             (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
                 return self.unify_const_variable(vid, a);
             }
-            (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
-                // FIXME(#59490): Need to remove the leak check to accommodate
-                // escaping bound variables here.
-                if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                    relation.register_const_equate_obligation(a, b);
-                }
+            (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
+                if self.tcx.lazy_normalization() =>
+            {
+                relation.register_const_equate_obligation(a, b);
                 return Ok(b);
             }
-            (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => {
-                // FIXME(#59490): Need to remove the leak check to accommodate
-                // escaping bound variables here.
-                if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                    relation.register_const_equate_obligation(a, b);
-                }
-                return Ok(a);
-            }
             _ => {}
         }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index f1468cae455..8482ae2aa38 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -102,6 +102,17 @@ pub enum RegionResolutionError<'tcx> {
     ),
 }
 
+impl<'tcx> RegionResolutionError<'tcx> {
+    pub fn origin(&self) -> &SubregionOrigin<'tcx> {
+        match self {
+            RegionResolutionError::ConcreteFailure(origin, _, _)
+            | RegionResolutionError::GenericBoundFailure(origin, _, _)
+            | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _)
+            | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin,
+        }
+    }
+}
+
 struct RegionAndOrigin<'tcx> {
     region: Region<'tcx>,
     origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 1cfdb791cd6..a89b9931599 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -39,7 +39,6 @@ use rustc_span::Span;
 
 use std::cell::{Cell, RefCell};
 use std::fmt;
-use std::ops::Drop;
 
 use self::combine::CombineFields;
 use self::error_reporting::TypeErrCtxt;
@@ -342,11 +341,6 @@ pub struct InferCtxt<'tcx> {
     /// there is no type that the user could *actually name* that
     /// would satisfy it. This avoids crippling inference, basically.
     pub intercrate: bool,
-
-    /// Flag that is set when we enter canonicalization. Used for debugging to ensure
-    /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin`
-    /// inside non-canonicalization contexts.
-    inside_canonicalization_ctxt: Cell<bool>,
 }
 
 /// See the `error_reporting` module for more details.
@@ -638,7 +632,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             skip_leak_check: Cell::new(false),
             universe: Cell::new(ty::UniverseIndex::ROOT),
             intercrate,
-            inside_canonicalization_ctxt: Cell::new(false),
         }
     }
 }
@@ -1636,31 +1629,6 @@ impl<'tcx> InferCtxt<'tcx> {
             }
         }
     }
-
-    pub fn inside_canonicalization_ctxt(&self) -> bool {
-        self.inside_canonicalization_ctxt.get()
-    }
-
-    pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> {
-        let prev_ctxt = self.inside_canonicalization_ctxt();
-        self.inside_canonicalization_ctxt.set(true);
-        CanonicalizationCtxtGuard { prev_ctxt, infcx: self }
-    }
-
-    fn set_canonicalization_ctxt_to(&self, ctxt: bool) {
-        self.inside_canonicalization_ctxt.set(ctxt);
-    }
-}
-
-pub struct CanonicalizationCtxtGuard<'cx, 'tcx> {
-    prev_ctxt: bool,
-    infcx: &'cx InferCtxt<'tcx>,
-}
-
-impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
-    fn drop(&mut self) {
-        self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt)
-    }
 }
 
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 9f7b26b87f4..88a0a81e276 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -30,11 +30,10 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
 use rustc_span::{Span, Symbol};
 use std::fmt::Debug;
-use std::ops::ControlFlow;
 
 use super::combine::ObligationEmittingRelation;
 
@@ -115,11 +114,6 @@ pub trait TypeRelatingDelegate<'tcx> {
     fn forbid_inference_vars() -> bool;
 }
 
-#[derive(Clone, Debug, Default)]
-struct BoundRegionScope<'tcx> {
-    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
-}
-
 #[derive(Copy, Clone)]
 struct UniversallyQuantified(bool);
 
@@ -230,10 +224,13 @@ where
     ) -> RelateResult<'tcx, T> {
         let universe = self.infcx.probe_ty_var(for_vid).unwrap_err();
 
+        if value.has_escaping_bound_vars() {
+            bug!("trying to instantiate {for_vid:?} with escaping bound vars: {value:?}");
+        }
+
         let mut generalizer = TypeGeneralizer {
             infcx: self.infcx,
             delegate: &mut self.delegate,
-            first_free_index: ty::INNERMOST,
             ambient_variance: self.ambient_variance,
             for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
             universe,
@@ -488,13 +485,7 @@ where
         }
 
         if a == b {
-            // Subtle: if a or b has a bound variable that we are lazily
-            // substituting, then even if a == b, it could be that the values we
-            // will substitute for those bound variables are *not* the same, and
-            // hence returning `Ok(a)` is incorrect.
-            if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                return Ok(a);
-            }
+            return Ok(a);
         }
 
         match (a.kind(), b.kind()) {
@@ -726,47 +717,6 @@ where
     }
 }
 
-/// When we encounter a binder like `for<..> fn(..)`, we actually have
-/// to walk the `fn` value to find all the values bound by the `for`
-/// (these are not explicitly present in the ty representation right
-/// now). This visitor handles that: it descends the type, tracking
-/// binder depth, and finds late-bound regions targeting the
-/// `for<..`>. For each of those, it creates an entry in
-/// `bound_region_scope`.
-struct ScopeInstantiator<'me, 'tcx> {
-    next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
-    // The debruijn index of the scope we are instantiating.
-    target_index: ty::DebruijnIndex,
-    bound_region_scope: &'me mut BoundRegionScope<'tcx>,
-}
-
-impl<'me, 'tcx> TypeVisitor<TyCtxt<'tcx>> for ScopeInstantiator<'me, 'tcx> {
-    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: &ty::Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.target_index.shift_in(1);
-        t.super_visit_with(self);
-        self.target_index.shift_out(1);
-
-        ControlFlow::Continue(())
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let ScopeInstantiator { bound_region_scope, next_region, .. } = self;
-
-        match *r {
-            ty::ReLateBound(debruijn, br) if debruijn == self.target_index => {
-                bound_region_scope.map.entry(br).or_insert_with(|| next_region(br));
-            }
-
-            _ => {}
-        }
-
-        ControlFlow::Continue(())
-    }
-}
-
 /// The "type generalizer" is used when handling inference variables.
 ///
 /// The basic strategy for handling a constraint like `?A <: B` is to
@@ -780,11 +730,6 @@ impl<'me, 'tcx> TypeVisitor<TyCtxt<'tcx>> for ScopeInstantiator<'me, 'tcx> {
 /// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
 /// establishes `'0: 'x` as a constraint.
 ///
-/// As a side-effect of this generalization procedure, we also replace
-/// all the bound regions that we have traversed with concrete values,
-/// so that the resulting generalized type is independent from the
-/// scopes.
-///
 /// [blog post]: https://is.gd/0hKvIr
 struct TypeGeneralizer<'me, 'tcx, D>
 where
@@ -798,8 +743,6 @@ where
     /// some other type. What will be the variance at this point?
     ambient_variance: ty::Variance,
 
-    first_free_index: ty::DebruijnIndex,
-
     /// The vid of the type variable that is in the process of being
     /// instantiated. If we find this within the value we are folding,
     /// that means we would have created a cyclic value.
@@ -939,7 +882,7 @@ where
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("TypeGeneralizer::regions(a={:?})", a);
 
-        if let ty::ReLateBound(debruijn, _) = *a && debruijn < self.first_free_index {
+        if let ty::ReLateBound(..) = *a {
             return Ok(a);
         }
 
@@ -958,7 +901,6 @@ where
         // FIXME(#54105) -- if the ambient variance is bivariant,
         // though, we may however need to check well-formedness or
         // risk a problem like #41677 again.
-
         let replacement_region_vid = self.delegate.generalize_existential(self.universe);
 
         Ok(replacement_region_vid)
@@ -1002,10 +944,7 @@ where
         T: Relate<'tcx>,
     {
         debug!("TypeGeneralizer::binders(a={:?})", a);
-
-        self.first_free_index.shift_in(1);
         let result = self.relate(a.skip_binder(), a.skip_binder())?;
-        self.first_free_index.shift_out(1);
         Ok(a.rebind(result))
     }
 }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8e9150ba8ad..9d9f4ee13f4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -9,11 +9,12 @@ use rustc_data_structures::OnDrop;
 use rustc_errors::registry::Registry;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_lint::LintStore;
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
-use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{CheckCfg, ExpectedValues};
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
 use rustc_session::Session;
@@ -121,9 +122,9 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
 pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
     rustc_span::create_default_session_if_not_set_then(move |_| {
-        let mut cfg = CheckCfg::default();
+        let mut check_cfg = CheckCfg::default();
 
-        'specs: for s in specs {
+        for s in specs {
             let sess = ParseSess::with_silent_emitter(Some(format!(
                 "this error occurred on the command line: `--check-cfg={s}`"
             )));
@@ -137,40 +138,54 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
                             concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
                             s
                         ),
-                    );
+                    )
                 };
             }
 
+            let expected_error = || {
+                error!(
+                    "expected `names(name1, name2, ... nameN)` or \
+                        `values(name, \"value1\", \"value2\", ... \"valueN\")`"
+                )
+            };
+
             match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
                 Ok(mut parser) => match parser.parse_meta_item() {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if let Some(args) = meta_item.meta_item_list() {
                             if meta_item.has_name(sym::names) {
-                                let names_valid =
-                                    cfg.names_valid.get_or_insert_with(|| FxHashSet::default());
+                                check_cfg.exhaustive_names = true;
                                 for arg in args {
                                     if arg.is_word() && arg.ident().is_some() {
                                         let ident = arg.ident().expect("multi-segment cfg key");
-                                        names_valid.insert(ident.name.to_string());
+                                        check_cfg
+                                            .expecteds
+                                            .entry(ident.name.to_string())
+                                            .or_insert(ExpectedValues::Any);
                                     } else {
                                         error!("`names()` arguments must be simple identifiers");
                                     }
                                 }
-                                continue 'specs;
                             } else if meta_item.has_name(sym::values) {
                                 if let Some((name, values)) = args.split_first() {
                                     if name.is_word() && name.ident().is_some() {
                                         let ident = name.ident().expect("multi-segment cfg key");
-                                        let ident_values = cfg
-                                            .values_valid
+                                        let expected_values = check_cfg
+                                            .expecteds
                                             .entry(ident.name.to_string())
-                                            .or_insert_with(|| FxHashSet::default());
+                                            .or_insert_with(|| {
+                                                ExpectedValues::Some(FxHashSet::default())
+                                            });
+
+                                        let ExpectedValues::Some(expected_values) = expected_values else {
+                                            bug!("shoudn't be possible")
+                                        };
 
                                         for val in values {
                                             if let Some(LitKind::Str(s, _)) =
                                                 val.lit().map(|lit| &lit.kind)
                                             {
-                                                ident_values.insert(s.to_string());
+                                                expected_values.insert(Some(s.to_string()));
                                             } else {
                                                 error!(
                                                     "`values()` arguments must be string literals"
@@ -178,35 +193,40 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
                                             }
                                         }
 
-                                        continue 'specs;
+                                        if values.is_empty() {
+                                            expected_values.insert(None);
+                                        }
                                     } else {
                                         error!(
                                             "`values()` first argument must be a simple identifier"
                                         );
                                     }
                                 } else if args.is_empty() {
-                                    cfg.well_known_values = true;
-                                    continue 'specs;
+                                    check_cfg.exhaustive_values = true;
+                                } else {
+                                    expected_error();
                                 }
+                            } else {
+                                expected_error();
                             }
+                        } else {
+                            expected_error();
                         }
                     }
-                    Ok(..) => {}
-                    Err(err) => err.cancel(),
+                    Ok(..) => expected_error(),
+                    Err(err) => {
+                        err.cancel();
+                        expected_error();
+                    }
                 },
-                Err(errs) => drop(errs),
+                Err(errs) => {
+                    drop(errs);
+                    expected_error();
+                }
             }
-
-            error!(
-                "expected `names(name1, name2, ... nameN)` or \
-                `values(name, \"value1\", \"value2\", ... \"valueN\")`"
-            );
         }
 
-        if let Some(names_valid) = &mut cfg.names_valid {
-            names_valid.extend(cfg.values_valid.keys().cloned());
-        }
-        cfg
+        check_cfg
     })
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a0c576234f9..1bae771e373 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -69,6 +69,7 @@ where
         is_private_dep: false,
         add_prelude: true,
         nounused_dep: false,
+        force: false,
     }
 }
 
@@ -547,6 +548,7 @@ fn test_codegen_options_tracking_hash() {
     untracked!(ar, String::from("abc"));
     untracked!(codegen_units, Some(42));
     untracked!(default_linker_libraries, true);
+    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(extra_filename, String::from("extra-filename"));
     untracked!(incremental, Some(String::from("abc")));
     // `link_arg` is omitted because it just forwards to `link_args`.
@@ -651,7 +653,6 @@ fn test_unstable_options_tracking_hash() {
     untracked!(assert_incr_state, Some(String::from("loaded")));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
-    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
     untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b3f4b5cd5e5..c07dc19a0ac 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -186,12 +186,16 @@ pub enum LiteralKind {
     Str { terminated: bool },
     /// "b"abc"", "b"abc"
     ByteStr { terminated: bool },
+    /// `c"abc"`, `c"abc`
+    CStr { terminated: bool },
     /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
     /// an invalid literal.
     RawStr { n_hashes: Option<u8> },
     /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
     /// indicates an invalid literal.
     RawByteStr { n_hashes: Option<u8> },
+    /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
+    RawCStr { n_hashes: Option<u8> },
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -357,39 +361,18 @@ impl Cursor<'_> {
             },
 
             // Byte literal, byte string literal, raw byte string literal or identifier.
-            'b' => match (self.first(), self.second()) {
-                ('\'', _) => {
-                    self.bump();
-                    let terminated = self.single_quoted_string();
-                    let suffix_start = self.pos_within_token();
-                    if terminated {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = Byte { terminated };
-                    Literal { kind, suffix_start }
-                }
-                ('"', _) => {
-                    self.bump();
-                    let terminated = self.double_quoted_string();
-                    let suffix_start = self.pos_within_token();
-                    if terminated {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = ByteStr { terminated };
-                    Literal { kind, suffix_start }
-                }
-                ('r', '"') | ('r', '#') => {
-                    self.bump();
-                    let res = self.raw_double_quoted_string(2);
-                    let suffix_start = self.pos_within_token();
-                    if res.is_ok() {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = RawByteStr { n_hashes: res.ok() };
-                    Literal { kind, suffix_start }
-                }
-                _ => self.ident_or_unknown_prefix(),
-            },
+            'b' => self.c_or_byte_string(
+                |terminated| ByteStr { terminated },
+                |n_hashes| RawByteStr { n_hashes },
+                Some(|terminated| Byte { terminated }),
+            ),
+
+            // c-string literal, raw c-string literal or identifier.
+            'c' => self.c_or_byte_string(
+                |terminated| CStr { terminated },
+                |n_hashes| RawCStr { n_hashes },
+                None,
+            ),
 
             // Identifier (this should be checked after other variant that can
             // start as identifier).
@@ -553,6 +536,47 @@ impl Cursor<'_> {
         }
     }
 
+    fn c_or_byte_string(
+        &mut self,
+        mk_kind: impl FnOnce(bool) -> LiteralKind,
+        mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
+        single_quoted: Option<fn(bool) -> LiteralKind>,
+    ) -> TokenKind {
+        match (self.first(), self.second(), single_quoted) {
+            ('\'', _, Some(mk_kind)) => {
+                self.bump();
+                let terminated = self.single_quoted_string();
+                let suffix_start = self.pos_within_token();
+                if terminated {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind(terminated);
+                Literal { kind, suffix_start }
+            }
+            ('"', _, _) => {
+                self.bump();
+                let terminated = self.double_quoted_string();
+                let suffix_start = self.pos_within_token();
+                if terminated {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind(terminated);
+                Literal { kind, suffix_start }
+            }
+            ('r', '"', _) | ('r', '#', _) => {
+                self.bump();
+                let res = self.raw_double_quoted_string(2);
+                let suffix_start = self.pos_within_token();
+                if res.is_ok() {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind_raw(res.ok());
+                Literal { kind, suffix_start }
+            }
+            _ => self.ident_or_unknown_prefix(),
+        }
+    }
+
     fn number(&mut self, first_digit: char) -> LiteralKind {
         debug_assert!('0' <= self.prev() && self.prev() <= '9');
         let mut base = Base::Decimal;
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index bb4d91247b8..c9ad54d8d98 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -86,10 +86,45 @@ where
             let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
             callback(0..(src.len() - chars.as_str().len()), res);
         }
-        Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(src, mode == Mode::ByteStr, callback),
+        Mode::Str | Mode::ByteStr => unescape_str_common(src, mode, callback),
+
         Mode::RawStr | Mode::RawByteStr => {
             unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
         }
+        Mode::CStr | Mode::RawCStr => unreachable!(),
+    }
+}
+
+/// A unit within CStr. Must not be a nul character.
+pub enum CStrUnit {
+    Byte(u8),
+    Char(char),
+}
+
+impl From<u8> for CStrUnit {
+    fn from(value: u8) -> Self {
+        CStrUnit::Byte(value)
+    }
+}
+
+impl From<char> for CStrUnit {
+    fn from(value: char) -> Self {
+        CStrUnit::Char(value)
+    }
+}
+
+pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>),
+{
+    if mode == Mode::RawCStr {
+        unescape_raw_str_or_raw_byte_str(
+            src,
+            mode.characters_should_be_ascii(),
+            &mut |r, result| callback(r, result.map(CStrUnit::Char)),
+        );
+    } else {
+        unescape_str_common(src, mode, callback);
     }
 }
 
@@ -114,34 +149,69 @@ pub enum Mode {
     ByteStr,
     RawStr,
     RawByteStr,
+    CStr,
+    RawCStr,
 }
 
 impl Mode {
     pub fn in_double_quotes(self) -> bool {
         match self {
-            Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true,
+            Mode::Str
+            | Mode::ByteStr
+            | Mode::RawStr
+            | Mode::RawByteStr
+            | Mode::CStr
+            | Mode::RawCStr => true,
             Mode::Char | Mode::Byte => false,
         }
     }
 
-    pub fn is_byte(self) -> bool {
+    /// Non-byte literals should have `\xXX` escapes that are within the ASCII range.
+    pub fn ascii_escapes_should_be_ascii(self) -> bool {
+        match self {
+            Mode::Char | Mode::Str | Mode::RawStr => true,
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    /// Whether characters within the literal must be within the ASCII range
+    pub fn characters_should_be_ascii(self) -> bool {
+        match self {
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
+            Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    /// Byte literals do not allow unicode escape.
+    pub fn is_unicode_escape_disallowed(self) -> bool {
         match self {
             Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
-            Mode::Char | Mode::Str | Mode::RawStr => false,
+            Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    pub fn prefix_noraw(self) -> &'static str {
+        match self {
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b",
+            Mode::CStr | Mode::RawCStr => "c",
+            Mode::Char | Mode::Str | Mode::RawStr => "",
         }
     }
 }
 
-fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
+fn scan_escape<T: From<u8> + From<char>>(
+    chars: &mut Chars<'_>,
+    mode: Mode,
+) -> Result<T, EscapeError> {
     // Previous character was '\\', unescape what follows.
     let res = match chars.next().ok_or(EscapeError::LoneSlash)? {
-        '"' => '"',
-        'n' => '\n',
-        'r' => '\r',
-        't' => '\t',
-        '\\' => '\\',
-        '\'' => '\'',
-        '0' => '\0',
+        '"' => b'"',
+        'n' => b'\n',
+        'r' => b'\r',
+        't' => b'\t',
+        '\\' => b'\\',
+        '\'' => b'\'',
+        '0' => b'\0',
 
         'x' => {
             // Parse hexadecimal character code.
@@ -154,76 +224,78 @@ fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError
 
             let value = hi * 16 + lo;
 
-            // For a non-byte literal verify that it is within ASCII range.
-            if !is_byte && !is_ascii(value) {
+            if mode.ascii_escapes_should_be_ascii() && !is_ascii(value) {
                 return Err(EscapeError::OutOfRangeHexEscape);
             }
-            let value = value as u8;
 
-            value as char
+            value as u8
         }
 
-        'u' => {
-            // We've parsed '\u', now we have to parse '{..}'.
+        'u' => return scan_unicode(chars, mode.is_unicode_escape_disallowed()).map(Into::into),
+        _ => return Err(EscapeError::InvalidEscape),
+    };
+    Ok(res.into())
+}
+
+fn scan_unicode(
+    chars: &mut Chars<'_>,
+    is_unicode_escape_disallowed: bool,
+) -> Result<char, EscapeError> {
+    // We've parsed '\u', now we have to parse '{..}'.
 
-            if chars.next() != Some('{') {
-                return Err(EscapeError::NoBraceInUnicodeEscape);
-            }
+    if chars.next() != Some('{') {
+        return Err(EscapeError::NoBraceInUnicodeEscape);
+    }
 
-            // First character must be a hexadecimal digit.
-            let mut n_digits = 1;
-            let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
-                '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
-                '}' => return Err(EscapeError::EmptyUnicodeEscape),
-                c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
-            };
-
-            // First character is valid, now parse the rest of the number
-            // and closing brace.
-            loop {
-                match chars.next() {
-                    None => return Err(EscapeError::UnclosedUnicodeEscape),
-                    Some('_') => continue,
-                    Some('}') => {
-                        if n_digits > 6 {
-                            return Err(EscapeError::OverlongUnicodeEscape);
-                        }
-
-                        // Incorrect syntax has higher priority for error reporting
-                        // than unallowed value for a literal.
-                        if is_byte {
-                            return Err(EscapeError::UnicodeEscapeInByte);
-                        }
-
-                        break std::char::from_u32(value).ok_or_else(|| {
-                            if value > 0x10FFFF {
-                                EscapeError::OutOfRangeUnicodeEscape
-                            } else {
-                                EscapeError::LoneSurrogateUnicodeEscape
-                            }
-                        })?;
-                    }
-                    Some(c) => {
-                        let digit: u32 =
-                            c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
-                        n_digits += 1;
-                        if n_digits > 6 {
-                            // Stop updating value since we're sure that it's incorrect already.
-                            continue;
-                        }
-                        value = value * 16 + digit;
+    // First character must be a hexadecimal digit.
+    let mut n_digits = 1;
+    let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
+        '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
+        '}' => return Err(EscapeError::EmptyUnicodeEscape),
+        c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
+    };
+
+    // First character is valid, now parse the rest of the number
+    // and closing brace.
+    loop {
+        match chars.next() {
+            None => return Err(EscapeError::UnclosedUnicodeEscape),
+            Some('_') => continue,
+            Some('}') => {
+                if n_digits > 6 {
+                    return Err(EscapeError::OverlongUnicodeEscape);
+                }
+
+                // Incorrect syntax has higher priority for error reporting
+                // than unallowed value for a literal.
+                if is_unicode_escape_disallowed {
+                    return Err(EscapeError::UnicodeEscapeInByte);
+                }
+
+                break std::char::from_u32(value).ok_or_else(|| {
+                    if value > 0x10FFFF {
+                        EscapeError::OutOfRangeUnicodeEscape
+                    } else {
+                        EscapeError::LoneSurrogateUnicodeEscape
                     }
-                };
+                });
             }
-        }
-        _ => return Err(EscapeError::InvalidEscape),
-    };
-    Ok(res)
+            Some(c) => {
+                let digit: u32 = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
+                n_digits += 1;
+                if n_digits > 6 {
+                    // Stop updating value since we're sure that it's incorrect already.
+                    continue;
+                }
+                value = value * 16 + digit;
+            }
+        };
+    }
 }
 
 #[inline]
-fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
-    if is_byte && !c.is_ascii() {
+fn ascii_check(c: char, characters_should_be_ascii: bool) -> Result<char, EscapeError> {
+    if characters_should_be_ascii && !c.is_ascii() {
         // Byte literal can't be a non-ascii character.
         Err(EscapeError::NonAsciiCharInByte)
     } else {
@@ -234,7 +306,7 @@ fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
 fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
     let c = chars.next().ok_or(EscapeError::ZeroChars)?;
     let res = match c {
-        '\\' => scan_escape(chars, is_byte),
+        '\\' => scan_escape(chars, if is_byte { Mode::Byte } else { Mode::Char }),
         '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
         '\r' => Err(EscapeError::BareCarriageReturn),
         _ => ascii_check(c, is_byte),
@@ -247,9 +319,9 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, E
 
 /// Takes a contents of a string literal (without quotes) and produces a
 /// sequence of escaped characters or errors.
-fn unescape_str_or_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
+fn unescape_str_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F)
 where
-    F: FnMut(Range<usize>, Result<char, EscapeError>),
+    F: FnMut(Range<usize>, Result<T, EscapeError>),
 {
     let mut chars = src.chars();
 
@@ -266,47 +338,49 @@ where
                         // if unescaped '\' character is followed by '\n'.
                         // For details see [Rust language reference]
                         // (https://doc.rust-lang.org/reference/tokens.html#string-literals).
-                        skip_ascii_whitespace(&mut chars, start, callback);
+                        skip_ascii_whitespace(&mut chars, start, &mut |range, err| {
+                            callback(range, Err(err))
+                        });
                         continue;
                     }
-                    _ => scan_escape(&mut chars, is_byte),
+                    _ => scan_escape::<T>(&mut chars, mode),
                 }
             }
-            '\n' => Ok('\n'),
-            '\t' => Ok('\t'),
+            '\n' => Ok(b'\n'.into()),
+            '\t' => Ok(b'\t'.into()),
             '"' => Err(EscapeError::EscapeOnlyChar),
             '\r' => Err(EscapeError::BareCarriageReturn),
-            _ => ascii_check(c, is_byte),
+            _ => ascii_check(c, mode.characters_should_be_ascii()).map(Into::into),
         };
         let end = src.len() - chars.as_str().len();
-        callback(start..end, res);
+        callback(start..end, res.map(Into::into));
     }
+}
 
-    fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
-    where
-        F: FnMut(Range<usize>, Result<char, EscapeError>),
-    {
-        let tail = chars.as_str();
-        let first_non_space = tail
-            .bytes()
-            .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
-            .unwrap_or(tail.len());
-        if tail[1..first_non_space].contains('\n') {
-            // The +1 accounts for the escaping slash.
-            let end = start + first_non_space + 1;
-            callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
-        }
-        let tail = &tail[first_non_space..];
-        if let Some(c) = tail.chars().nth(0) {
-            if c.is_whitespace() {
-                // For error reporting, we would like the span to contain the character that was not
-                // skipped. The +1 is necessary to account for the leading \ that started the escape.
-                let end = start + first_non_space + c.len_utf8() + 1;
-                callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
-            }
+fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
+where
+    F: FnMut(Range<usize>, EscapeError),
+{
+    let tail = chars.as_str();
+    let first_non_space = tail
+        .bytes()
+        .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
+        .unwrap_or(tail.len());
+    if tail[1..first_non_space].contains('\n') {
+        // The +1 accounts for the escaping slash.
+        let end = start + first_non_space + 1;
+        callback(start..end, EscapeError::MultipleSkippedLinesWarning);
+    }
+    let tail = &tail[first_non_space..];
+    if let Some(c) = tail.chars().nth(0) {
+        if c.is_whitespace() {
+            // For error reporting, we would like the span to contain the character that was not
+            // skipped. The +1 is necessary to account for the leading \ that started the escape.
+            let end = start + first_non_space + c.len_utf8() + 1;
+            callback(start..end, EscapeError::UnskippedWhitespaceWarning);
         }
-        *chars = tail.chars();
     }
+    *chars = tail.chars();
 }
 
 /// Takes a contents of a string literal (without quotes) and produces a
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index aeb791901bd..01052698850 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -63,6 +63,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
@@ -3306,16 +3307,15 @@ impl EarlyLintPass for UnexpectedCfgs {
         let cfg = &cx.sess().parse_sess.config;
         let check_cfg = &cx.sess().parse_sess.check_config;
         for &(name, value) in cfg {
-            if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
-                cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
-                    name,
-                });
-            }
-            if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
-                cx.emit_lint(
-                    UNEXPECTED_CFGS,
-                    BuiltinUnexpectedCliConfigValue { name, value },
-                );
+            match check_cfg.expecteds.get(&name) {
+                Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
+                    let value = value.unwrap_or(kw::Empty);
+                    cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
+                }
+                None if check_cfg.exhaustive_names => {
+                    cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
+                }
+                _ => { /* expected */ }
             }
         }
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index d4898ffe883..53d7cf74cde 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -36,6 +36,7 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
@@ -768,22 +769,52 @@ pub trait LintContext: Sized {
                     db.help(help);
                     db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
                 },
-                BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
-                    let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
-                        bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
-                    };
-                    let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
+                BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => {
+                    let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
 
                     // Suggest the most probable if we found one
                     if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
-                        db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
+                        if let Some(ExpectedValues::Some(best_match_values)) =
+                            sess.parse_sess.check_config.expecteds.get(&best_match) {
+                            let mut possibilities = best_match_values.iter()
+                                .flatten()
+                                .map(Symbol::as_str)
+                                .collect::<Vec<_>>();
+                            possibilities.sort();
+
+                            if let Some((value, value_span)) = value {
+                                if best_match_values.contains(&Some(value)) {
+                                    db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
+                                } else if best_match_values.contains(&None) {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
+                                } else if let Some(first_value) = possibilities.first() {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
+                                } else {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", best_match, Applicability::MaybeIncorrect);
+                                };
+                            } else {
+                                db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+                            }
+
+                            if !possibilities.is_empty() {
+                                let possibilities = possibilities.join("`, `");
+                                db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+                            }
+                        } else {
+                            db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+                        }
                     }
                 },
-                BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
-                    let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
+                BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
+                    let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
                         bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
                     };
-                    let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
+                    let mut have_none_possibility = false;
+                    let possibilities: Vec<Symbol> = values.iter()
+                        .inspect(|a| have_none_possibility |= a.is_none())
+                        .copied()
+                        .flatten()
+                        .collect();
 
                     // Show the full list if all possible values for a given name, but don't do it
                     // for names as the possibilities could be very long
@@ -792,17 +823,24 @@ pub trait LintContext: Sized {
                             let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
                             possibilities.sort();
 
-                            let possibilities = possibilities.join(", ");
-                            db.note(format!("expected values for `{name}` are: {possibilities}"));
+                            let possibilities = possibilities.join("`, `");
+                            let none = if have_none_possibility { "(none), " } else { "" };
+
+                            db.note(format!("expected values for `{name}` are: {none}`{possibilities}`"));
                         }
 
-                        // Suggest the most probable if we found one
-                        if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
-                            db.span_suggestion(value_span, "did you mean", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+                        if let Some((value, value_span)) = value {
+                            // Suggest the most probable if we found one
+                            if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+                                db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+
+                            }
+                        } else if let &[first_possibility] = &possibilities[..] {
+                            db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect);
                         }
-                    } else {
+                    } else if have_none_possibility {
                         db.note(format!("no expected value for `{name}`"));
-                        if name != sym::feature {
+                        if let Some((_value, value_span)) = value {
                             db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
                         }
                     }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 595b50c4063..0082aaa4a38 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -478,8 +478,10 @@ impl EarlyLintPass for Diagnostics {
         }
         if !segments.iter().all(|(name, args)| {
             let arg = match name.as_str() {
-                "struct_span_err" | "span_note" | "span_label" | "span_help" => &args[1],
-                "note" | "help" => &args[0],
+                "struct_span_err" | "span_note" | "span_label" | "span_help" if args.len() == 2 => {
+                    &args[1]
+                }
+                "note" | "help" if args.len() == 1 => &args[0],
                 _ => {
                     return false;
                 }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7ea472ed504..e27e322db88 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -496,7 +496,8 @@ pub enum BuiltinLintDiagnostics {
     BreakWithLabelAndLoop(Span),
     NamedAsmLabel(String),
     UnicodeTextFlow(Span, String),
-    UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
+    UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
+    UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
     DeprecatedWhereclauseLocation(Span, String),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 1acdc95ca8d..5ec3b95225d 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -297,7 +297,6 @@ static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) {
   report_fatal_error("Bad RelocModel.");
 }
 
-#ifdef LLVM_RUSTLLVM
 /// getLongestEntryLength - Return the length of the longest entry in the table.
 template<typename KV>
 static size_t getLongestEntryLength(ArrayRef<KV> Table) {
@@ -307,56 +306,68 @@ static size_t getLongestEntryLength(ArrayRef<KV> Table) {
   return MaxLen;
 }
 
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
+extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, const char* TargetCPU) {
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch();
   const Triple::ArchType TargetArch = Target->getTargetTriple().getArch();
+
+#if LLVM_VERSION_GE(17, 0)
+  const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions();
+#elif defined(LLVM_RUSTLLVM)
   const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable();
+#else
+  printf("Full target CPU help is not supported by this LLVM version.\n\n");
+  SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} };
+  const ArrayRef<SubtargetSubTypeKV> CPUTable = TargetCPUKV;
+#endif
   unsigned MaxCPULen = getLongestEntryLength(CPUTable);
 
   printf("Available CPUs for this target:\n");
   // Don't print the "native" entry when the user specifies --target with a
   // different arch since that could be wrong or misleading.
   if (HostArch == TargetArch) {
+    MaxCPULen = std::max(MaxCPULen, (unsigned) std::strlen("native"));
     const StringRef HostCPU = sys::getHostCPUName();
     printf("    %-*s - Select the CPU of the current host (currently %.*s).\n",
       MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data());
   }
-  for (auto &CPU : CPUTable)
-    printf("    %-*s\n", MaxCPULen, CPU.Key);
-  printf("\n");
+  for (auto &CPU : CPUTable) {
+    // Compare cpu against current target to label the default
+    if (strcmp(CPU.Key, TargetCPU) == 0) {
+      printf("    %-*s - This is the default target CPU"
+      " for the current build target (currently %s).",
+        MaxCPULen, CPU.Key, Target->getTargetTriple().str().c_str());
+    }
+    else {
+      printf("    %-*s", MaxCPULen, CPU.Key);
+    }
+    printf("\n");
+  }
 }
 
 extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
+#ifdef LLVM_RUSTLLVM
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
   return FeatTable.size();
+#else
+  return 0;
+#endif
 }
 
 extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
                                          const char** Feature, const char** Desc) {
+#ifdef LLVM_RUSTLLVM
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
   const SubtargetFeatureKV Feat = FeatTable[Index];
   *Feature = Feat.Key;
   *Desc = Feat.Desc;
-}
-
-#else
-
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
-  printf("Target CPU help is not supported by this LLVM version.\n\n");
-}
-
-extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) {
-  return 0;
-}
-
-extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {}
 #endif
+}
 
 extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
   StringRef Name = sys::getHostCPUName();
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index cadb6b1e23f..49acd71b3e1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -831,6 +831,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
   return wrap(Sub);
 }
 
+extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
+    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
+    const char *Name, size_t NameLen,
+    const char *LinkageName, size_t LinkageNameLen,
+    LLVMMetadataRef File, unsigned LineNo,
+    LLVMMetadataRef Ty, LLVMRustDIFlags Flags,
+    LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
+  DITemplateParameterArray TParams =
+      DITemplateParameterArray(unwrap<MDTuple>(TParam));
+  DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
+  DINode::DIFlags llvmFlags = fromRust(Flags);
+  DISubprogram *Sub = Builder->createMethod(
+      unwrapDI<DIScope>(Scope),
+      StringRef(Name, NameLen),
+      StringRef(LinkageName, LinkageNameLen),
+      unwrapDI<DIFile>(File), LineNo,
+      unwrapDI<DISubroutineType>(Ty),
+      0, 0, nullptr, // VTable params aren't used
+      llvmFlags, llvmSPFlags, TParams);
+  return wrap(Sub);
+}
+
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType(
     LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen,
     uint64_t SizeInBits, unsigned Encoding) {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 01b69966ca9..e6e7d25773e 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -865,6 +865,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
+    fn inject_forced_externs(&mut self) {
+        for (name, entry) in self.sess.opts.externs.iter() {
+            if entry.force {
+                let name_interned = Symbol::intern(name);
+                if !self.used_extern_options.contains(&name_interned) {
+                    self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
+                }
+            }
+        }
+    }
+
     fn inject_dependency_if(
         &self,
         krate: CrateNum,
@@ -913,7 +924,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 // Don't worry about pathless `--extern foo` sysroot references
                 continue;
             }
-            if entry.nounused_dep {
+            if entry.nounused_dep || entry.force {
                 // We're not worried about this one
                 continue;
             }
@@ -942,6 +953,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     pub fn postprocess(&mut self, krate: &ast::Crate) {
+        self.inject_forced_externs();
         self.inject_profiler_runtime(krate);
         self.inject_allocator_crate(krate);
         self.inject_panic_runtime(krate);
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b43dcf3e5a1..c83c47e722b 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -161,14 +161,6 @@ impl<'tcx> Collector<'tcx> {
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
                                     sess.emit_err(errors::FrameworkOnlyWindows { span });
-                                } else if !features.raw_dylib && sess.target.arch == "x86" {
-                                    feature_err(
-                                        &sess.parse_sess,
-                                        sym::raw_dylib,
-                                        span,
-                                        "link kind `raw-dylib` is unstable on x86",
-                                    )
-                                    .emit();
                                 }
                                 NativeLibKind::RawDylib
                             }
@@ -251,16 +243,6 @@ impl<'tcx> Collector<'tcx> {
                                 continue;
                             }
                         };
-                        if !features.raw_dylib {
-                            let span = item.name_value_literal_span().unwrap();
-                            feature_err(
-                                &sess.parse_sess,
-                                sym::raw_dylib,
-                                span,
-                                "import name type is unstable",
-                            )
-                            .emit();
-                        }
                         import_name_type = Some((link_import_name_type, item.span()));
                     }
                     _ => {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 32f9e883fd6..82c66b9dfb9 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -108,11 +108,7 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
         emit_i64(i64);
         emit_i32(i32);
         emit_i16(i16);
-        emit_i8(i8);
 
-        emit_bool(bool);
-        emit_char(char);
-        emit_str(&str);
         emit_raw_bytes(&[u8]);
     }
 }
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 967fed687b6..aeb6a1601fc 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -64,7 +64,7 @@ impl EffectiveVisibility {
         self.at_level(level).is_public()
     }
 
-    pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
+    pub const fn from_vis(vis: Visibility) -> EffectiveVisibility {
         EffectiveVisibility {
             direct: vis,
             reexported: vis,
@@ -72,6 +72,18 @@ impl EffectiveVisibility {
             reachable_through_impl_trait: vis,
         }
     }
+
+    #[must_use]
+    pub fn min(mut self, lhs: EffectiveVisibility, tcx: TyCtxt<'_>) -> Self {
+        for l in Level::all_levels() {
+            let rhs_vis = self.at_level_mut(l);
+            let lhs_vis = *lhs.at_level(l);
+            if rhs_vis.is_at_least(lhs_vis, tcx) {
+                *rhs_vis = lhs_vis;
+            };
+        }
+        self
+    }
 }
 
 /// Holds a map of effective visibilities for reachable HIR nodes.
@@ -137,24 +149,6 @@ impl EffectiveVisibilities {
         };
     }
 
-    pub fn set_public_at_level(
-        &mut self,
-        id: LocalDefId,
-        lazy_private_vis: impl FnOnce() -> Visibility,
-        level: Level,
-    ) {
-        let mut effective_vis = self
-            .effective_vis(id)
-            .copied()
-            .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis()));
-        for l in Level::all_levels() {
-            if l <= level {
-                *effective_vis.at_level_mut(l) = Visibility::Public;
-            }
-        }
-        self.map.insert(id, effective_vis);
-    }
-
     pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
         if !cfg!(debug_assertions) {
             return;
@@ -219,7 +213,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
     pub fn update(
         &mut self,
         id: Id,
-        nominal_vis: Visibility,
+        nominal_vis: Option<Visibility>,
         lazy_private_vis: impl FnOnce() -> Visibility,
         inherited_effective_vis: EffectiveVisibility,
         level: Level,
@@ -243,12 +237,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
                 if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
                     && level != l)
                 {
-                    calculated_effective_vis =
-                        if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
-                            inherited_effective_vis_at_level
-                        } else {
-                            nominal_vis
-                        };
+                    calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
+                        nominal_vis
+                    } else {
+                        inherited_effective_vis_at_level
+                    }
                 }
                 // effective visibility can't be decreased at next update call for the
                 // same id
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index e56faff5ed4..220118ae5cc 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -1026,11 +1026,7 @@ impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> {
         emit_i64(i64);
         emit_i32(i32);
         emit_i16(i16);
-        emit_i8(i8);
 
-        emit_bool(bool);
-        emit_char(char);
-        emit_str(&str);
         emit_raw_bytes(&[u8]);
     }
 }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index c2375564208..8366567c2c3 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -444,6 +444,10 @@ pub enum ObligationCauseCode<'tcx> {
     AscribeUserTypeProvePredicate(Span),
 
     RustCall,
+
+    /// Obligations to prove that a `std::ops::Drop` impl is not stronger than
+    /// the ADT it's being implemented for.
+    DropImpl,
 }
 
 /// The 'location' at which we try to perform HIR-based wf checking.
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 7536903ef96..7fc75674da5 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -506,23 +506,18 @@ macro_rules! implement_ty_decoder {
 
             impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
                 $crate::__impl_decoder_methods! {
+                    read_usize -> usize;
                     read_u128 -> u128;
                     read_u64 -> u64;
                     read_u32 -> u32;
                     read_u16 -> u16;
                     read_u8 -> u8;
-                    read_usize -> usize;
 
+                    read_isize -> isize;
                     read_i128 -> i128;
                     read_i64 -> i64;
                     read_i32 -> i32;
                     read_i16 -> i16;
-                    read_i8 -> i8;
-                    read_isize -> isize;
-
-                    read_bool -> bool;
-                    read_char -> char;
-                    read_str -> &str;
                 }
 
                 #[inline]
@@ -531,13 +526,13 @@ macro_rules! implement_ty_decoder {
                 }
 
                 #[inline]
-                fn position(&self) -> usize {
-                    self.opaque.position()
+                fn peek_byte(&self) -> u8 {
+                    self.opaque.peek_byte()
                 }
 
                 #[inline]
-                fn peek_byte(&self) -> u8 {
-                    self.opaque.peek_byte()
+                fn position(&self) -> usize {
+                    self.opaque.position()
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index cc86cba6fda..6c8f4af7594 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -385,7 +385,7 @@ impl<'tcx> Instance<'tcx> {
     /// couldn't complete due to errors elsewhere - this is distinct
     /// from `Ok(None)` to avoid misleading diagnostics when an error
     /// has already been/will be emitted, for the original cause
-    #[instrument(level = "debug", skip(tcx))]
+    #[instrument(level = "debug", skip(tcx), ret)]
     pub fn resolve(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index fbcfd433724..59549435233 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -146,6 +146,12 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
             let id = tcx.allocate_bytes(data);
             ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
         }
+        (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
+        {
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
+            let allocation = tcx.mk_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+        }
         (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
             ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
         }
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index b3a3a25ebe8..7f995c69a48 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -714,13 +714,22 @@ impl CanConstProp {
     }
 }
 
-impl Visitor<'_> for CanConstProp {
+impl<'tcx> Visitor<'tcx> for CanConstProp {
+    fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
+        use rustc_middle::mir::visit::PlaceContext::*;
+
+        // Dereferencing just read the addess of `place.local`.
+        if place.projection.first() == Some(&PlaceElem::Deref) {
+            context = NonMutatingUse(NonMutatingUseContext::Copy);
+        }
+
+        self.visit_local(place.local, context, loc);
+        self.visit_projection(place.as_ref(), context, loc);
+    }
+
     fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::PlaceContext::*;
         match context {
-            // Projections are fine, because `&mut foo.x` will be caught by
-            // `MutatingUseContext::Borrow` elsewhere.
-            MutatingUse(MutatingUseContext::Projection)
             // These are just stores, where the storing is not propagatable, but there may be later
             // mutations of the same local via `Store`
             | MutatingUse(MutatingUseContext::Call)
@@ -751,7 +760,6 @@ impl Visitor<'_> for CanConstProp {
             NonMutatingUse(NonMutatingUseContext::Copy)
             | NonMutatingUse(NonMutatingUseContext::Move)
             | NonMutatingUse(NonMutatingUseContext::Inspect)
-            | NonMutatingUse(NonMutatingUseContext::Projection)
             | NonMutatingUse(NonMutatingUseContext::PlaceMention)
             | NonUse(_) => {}
 
@@ -771,6 +779,8 @@ impl Visitor<'_> for CanConstProp {
                 trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
                 self.can_const_prop[local] = ConstPropMode::NoPropagation;
             }
+            MutatingUse(MutatingUseContext::Projection)
+            | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
         }
     }
 }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index b1c0dedd3c7..51e90489002 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
 use crate::errors;
 use crate::lexer::unicode_chars::UNICODE_ARRAY;
 use crate::make_unclosed_delims_error;
@@ -6,7 +8,7 @@ use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey};
-use rustc_lexer::unescape::{self, Mode};
+use rustc_lexer::unescape::{self, EscapeError, Mode};
 use rustc_lexer::Cursor;
 use rustc_lexer::{Base, DocStyle, RawStrError};
 use rustc_session::lint::builtin::{
@@ -204,6 +206,9 @@ impl<'a> StringReader<'a> {
                 rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
                     let suffix_start = start + BytePos(suffix_start);
                     let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
+                    if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind {
+                        self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos));
+                    }
                     let suffix = if suffix_start < self.pos {
                         let string = self.str_from(suffix_start);
                         if string == "_" {
@@ -415,6 +420,16 @@ impl<'a> StringReader<'a> {
                 }
                 self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
             }
+            rustc_lexer::LiteralKind::CStr { terminated } => {
+                if !terminated {
+                    self.sess.span_diagnostic.span_fatal_with_code(
+                        self.mk_sp(start + BytePos(1), end),
+                        "unterminated C string",
+                        error_code!(E0767),
+                    )
+                }
+                self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" "
+            }
             rustc_lexer::LiteralKind::RawStr { n_hashes } => {
                 if let Some(n_hashes) = n_hashes {
                     let n = u32::from(n_hashes);
@@ -433,6 +448,15 @@ impl<'a> StringReader<'a> {
                     self.report_raw_str_error(start, 2);
                 }
             }
+            rustc_lexer::LiteralKind::RawCStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    let kind = token::CStrRaw(n_hashes);
+                    self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "##
+                } else {
+                    self.report_raw_str_error(start, 2);
+                }
+            }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
                 if empty_int {
                     let span = self.mk_sp(start, end);
@@ -648,7 +672,7 @@ impl<'a> StringReader<'a> {
         self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
     }
 
-    fn cook_quoted(
+    fn cook_common(
         &self,
         kind: token::LitKind,
         mode: Mode,
@@ -656,12 +680,13 @@ impl<'a> StringReader<'a> {
         end: BytePos,
         prefix_len: u32,
         postfix_len: u32,
+        unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)),
     ) -> (token::LitKind, Symbol) {
         let mut has_fatal_err = false;
         let content_start = start + BytePos(prefix_len);
         let content_end = end - BytePos(postfix_len);
         let lit_content = self.str_from_to(content_start, content_end);
-        unescape::unescape_literal(lit_content, mode, &mut |range, result| {
+        unescape(lit_content, mode, &mut |range, result| {
             // Here we only check for errors. The actual unescaping is done later.
             if let Err(err) = result {
                 let span_with_quotes = self.mk_sp(start, end);
@@ -692,6 +717,38 @@ impl<'a> StringReader<'a> {
             (token::Err, self.symbol_from_to(start, end))
         }
     }
+
+    fn cook_quoted(
+        &self,
+        kind: token::LitKind,
+        mode: Mode,
+        start: BytePos,
+        end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) -> (token::LitKind, Symbol) {
+        self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+            unescape::unescape_literal(src, mode, &mut |span, result| {
+                callback(span, result.map(drop))
+            })
+        })
+    }
+
+    fn cook_c_string(
+        &self,
+        kind: token::LitKind,
+        mode: Mode,
+        start: BytePos,
+        end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) -> (token::LitKind, Symbol) {
+        self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+            unescape::unescape_c_string(src, mode, &mut |span, result| {
+                callback(span, result.map(drop))
+            })
+        })
+    }
 }
 
 pub fn nfc_normalize(string: &str) -> Symbol {
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index d8bcf816fb2..eb9625f923a 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -78,8 +78,7 @@ pub(crate) fn emit_unescape_error(
                 }
             };
             let sugg = sugg.unwrap_or_else(|| {
-                let is_byte = mode.is_byte();
-                let prefix = if is_byte { "b" } else { "" };
+                let prefix = mode.prefix_noraw();
                 let mut escaped = String::with_capacity(lit.len());
                 let mut chrs = lit.chars().peekable();
                 while let Some(first) = chrs.next() {
@@ -97,7 +96,11 @@ pub(crate) fn emit_unescape_error(
                     };
                 }
                 let sugg = format!("{prefix}\"{escaped}\"");
-                MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg }
+                MoreThanOneCharSugg::Quotes {
+                    span: span_with_quotes,
+                    is_byte: mode == Mode::Byte,
+                    sugg,
+                }
             });
             handler.emit_err(UnescapeError::MoreThanOneChar {
                 span: span_with_quotes,
@@ -112,7 +115,7 @@ pub(crate) fn emit_unescape_error(
                 char_span,
                 escaped_sugg: c.escape_default().to_string(),
                 escaped_msg: escaped_char(c),
-                byte: mode.is_byte(),
+                byte: mode == Mode::Byte,
             });
         }
         EscapeError::BareCarriageReturn => {
@@ -126,12 +129,15 @@ pub(crate) fn emit_unescape_error(
         EscapeError::InvalidEscape => {
             let (c, span) = last_char();
 
-            let label =
-                if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
+            let label = if mode == Mode::Byte || mode == Mode::ByteStr {
+                "unknown byte escape"
+            } else {
+                "unknown character escape"
+            };
             let ec = escaped_char(c);
             let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec));
             diag.span_label(span, label);
-            if c == '{' || c == '}' && !mode.is_byte() {
+            if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
                 diag.help(
                     "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                 );
@@ -141,7 +147,7 @@ pub(crate) fn emit_unescape_error(
                      version control settings",
                 );
             } else {
-                if !mode.is_byte() {
+                if mode == Mode::Str || mode == Mode::Char {
                     diag.span_suggestion(
                         span_with_quotes,
                         "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index f58f8919e5c..018eddea4b0 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1448,8 +1448,19 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
+        let maybe_eq_tok = self.prev_token.clone();
         let (qself, path) = if self.eat_lt() {
-            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+            let lt_span = self.prev_token.span;
+            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
+                // Suggests using '<=' if there is an error parsing qpath when the previous token
+                // is an '=' token. Only emits suggestion if the '<' token and '=' token are
+                // directly adjacent (i.e. '=<')
+                if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+                    let eq_lt = maybe_eq_tok.span.to(lt_span);
+                    err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
+                }
+                err
+            })?;
             (Some(qself), path)
         } else {
             (None, self.parse_path(PathStyle::Expr)?)
@@ -1870,6 +1881,7 @@ impl<'a> Parser<'a> {
         let recovered = self.recover_after_dot();
         let token = recovered.as_ref().unwrap_or(&self.token);
         let span = token.span;
+
         token::Lit::from_token(token).map(|token_lit| {
             self.bump();
             (token_lit, span)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 04ac585076f..b738ce35ada 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -25,7 +25,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
@@ -38,7 +38,7 @@ use rustc_span::Span;
 
 use std::marker::PhantomData;
 use std::ops::ControlFlow;
-use std::{cmp, fmt, mem};
+use std::{fmt, mem};
 
 use errors::{
     FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
@@ -375,8 +375,9 @@ impl VisibilityLike for ty::Visibility {
         min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
-impl VisibilityLike for Option<Level> {
-    const MAX: Self = Some(Level::Direct);
+
+impl VisibilityLike for Option<EffectiveVisibility> {
+    const MAX: Self = Some(EffectiveVisibility::from_vis(ty::Visibility::Public));
     // Type inference is very smart sometimes.
     // It can make an impl reachable even some components of its type or trait are unreachable.
     // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
@@ -388,7 +389,13 @@ impl VisibilityLike for Option<Level> {
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
     fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
-        cmp::min(find.effective_visibilities.public_at_level(def_id), find.min)
+        if let Some(min) = find.min {
+            return find
+                .effective_visibilities
+                .effective_vis(def_id)
+                .map(|eff_vis| min.min(*eff_vis, find.tcx));
+        }
+        None
     }
 }
 
@@ -414,49 +421,79 @@ struct EmbargoVisitor<'tcx> {
     ///     n::p::f()
     /// }
     macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
-    /// Previous visibility level; `None` means unreachable.
-    prev_level: Option<Level>,
     /// Has something changed in the level map?
     changed: bool,
 }
 
 struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
-    level: Option<Level>,
+    effective_vis: Option<EffectiveVisibility>,
     item_def_id: LocalDefId,
     ev: &'a mut EmbargoVisitor<'tcx>,
+    level: Level,
 }
 
 impl<'tcx> EmbargoVisitor<'tcx> {
-    fn get(&self, def_id: LocalDefId) -> Option<Level> {
-        self.effective_visibilities.public_at_level(def_id)
-    }
-
-    /// Updates node level and returns the updated level.
-    fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> {
-        let old_level = self.get(def_id);
-        // Visibility levels can only grow.
-        if level > old_level {
-            self.effective_visibilities.set_public_at_level(
-                def_id,
-                || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
-                level.unwrap(),
-            );
-            self.changed = true;
-            level
-        } else {
-            old_level
+    fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
+        self.effective_visibilities.effective_vis(def_id).copied()
+    }
+
+    // Updates node effective visibility.
+    fn update(
+        &mut self,
+        def_id: LocalDefId,
+        inherited_effective_vis: Option<EffectiveVisibility>,
+        level: Level,
+    ) {
+        let nominal_vis = self.tcx.local_visibility(def_id);
+        self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
+    }
+
+    fn update_eff_vis(
+        &mut self,
+        def_id: LocalDefId,
+        inherited_effective_vis: Option<EffectiveVisibility>,
+        nominal_vis: Option<ty::Visibility>,
+        level: Level,
+    ) {
+        if let Some(inherited_effective_vis) = inherited_effective_vis {
+            let private_vis =
+                ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id));
+            if Some(private_vis) != nominal_vis {
+                self.changed |= self.effective_visibilities.update(
+                    def_id,
+                    nominal_vis,
+                    || private_vis,
+                    inherited_effective_vis,
+                    level,
+                    self.tcx,
+                );
+            }
         }
     }
 
     fn reach(
         &mut self,
         def_id: LocalDefId,
-        level: Option<Level>,
+        effective_vis: Option<EffectiveVisibility>,
     ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
         ReachEverythingInTheInterfaceVisitor {
-            level: cmp::min(level, Some(Level::Reachable)),
+            effective_vis,
             item_def_id: def_id,
             ev: self,
+            level: Level::Reachable,
+        }
+    }
+
+    fn reach_through_impl_trait(
+        &mut self,
+        def_id: LocalDefId,
+        effective_vis: Option<EffectiveVisibility>,
+    ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
+        ReachEverythingInTheInterfaceVisitor {
+            effective_vis,
+            item_def_id: def_id,
+            ev: self,
+            level: Level::ReachableThroughImplTrait,
         }
     }
 
@@ -477,16 +514,18 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             return;
         }
 
-        if self.get(local_def_id).is_none() {
+        if self.effective_visibilities.public_at_level(local_def_id).is_none() {
             return;
         }
 
         // Since we are starting from an externally visible module,
         // all the parents in the loop below are also guaranteed to be modules.
         let mut module_def_id = macro_module_def_id;
+        let macro_ev = self.get(local_def_id);
+        assert!(macro_ev.is_some());
         loop {
             let changed_reachability =
-                self.update_macro_reachable(module_def_id, macro_module_def_id);
+                self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
             if changed_reachability || module_def_id == CRATE_DEF_ID {
                 break;
             }
@@ -500,21 +539,33 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         &mut self,
         module_def_id: LocalDefId,
         defining_mod: LocalDefId,
+        macro_ev: Option<EffectiveVisibility>,
     ) -> bool {
         if self.macro_reachable.insert((module_def_id, defining_mod)) {
-            self.update_macro_reachable_mod(module_def_id, defining_mod);
+            self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev);
             true
         } else {
             false
         }
     }
 
-    fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
+    fn update_macro_reachable_mod(
+        &mut self,
+        module_def_id: LocalDefId,
+        defining_mod: LocalDefId,
+        macro_ev: Option<EffectiveVisibility>,
+    ) {
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
             let def_kind = self.tcx.def_kind(item_id.owner_id);
             let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
-            self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod);
+            self.update_macro_reachable_def(
+                item_id.owner_id.def_id,
+                def_kind,
+                vis,
+                defining_mod,
+                macro_ev,
+            );
         }
         for child in self.tcx.module_children_local(module_def_id) {
             // FIXME: Use module children for the logic above too.
@@ -523,7 +574,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
                 && let Res::Def(def_kind, def_id) = child.res
                 && let Some(def_id) = def_id.as_local() {
                 let vis = self.tcx.local_visibility(def_id);
-                self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
+                self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
             }
         }
     }
@@ -534,16 +585,14 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         def_kind: DefKind,
         vis: ty::Visibility,
         module: LocalDefId,
+        macro_ev: Option<EffectiveVisibility>,
     ) {
-        let level = Some(Level::Reachable);
-        if vis.is_public() {
-            self.update(def_id, level);
-        }
+        self.update(def_id, macro_ev, Level::Reachable);
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
             DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
                 if vis.is_accessible_from(module, self.tcx) {
-                    self.update(def_id, level);
+                    self.update(def_id, macro_ev, Level::Reachable);
                 }
             }
 
@@ -555,7 +604,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
                 let item = self.tcx.hir().expect_item(def_id);
                 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
                     if vis.is_accessible_from(module, self.tcx) {
-                        self.update(def_id, level);
+                        self.update(def_id, macro_ev, Level::Reachable);
                     }
                 }
             }
@@ -566,26 +615,24 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             // the module, however may be reachable.
             DefKind::Mod => {
                 if vis.is_accessible_from(module, self.tcx) {
-                    self.update_macro_reachable(def_id, module);
+                    self.update_macro_reachable(def_id, module, macro_ev);
                 }
             }
 
             DefKind::Struct | DefKind::Union => {
                 // While structs and unions have type privacy, their fields do not.
-                if vis.is_public() {
-                    let item = self.tcx.hir().expect_item(def_id);
-                    if let hir::ItemKind::Struct(ref struct_def, _)
-                    | hir::ItemKind::Union(ref struct_def, _) = item.kind
-                    {
-                        for field in struct_def.fields() {
-                            let field_vis = self.tcx.local_visibility(field.def_id);
-                            if field_vis.is_accessible_from(module, self.tcx) {
-                                self.reach(field.def_id, level).ty();
-                            }
+                let item = self.tcx.hir().expect_item(def_id);
+                if let hir::ItemKind::Struct(ref struct_def, _)
+                | hir::ItemKind::Union(ref struct_def, _) = item.kind
+                {
+                    for field in struct_def.fields() {
+                        let field_vis = self.tcx.local_visibility(field.def_id);
+                        if field_vis.is_accessible_from(module, self.tcx) {
+                            self.reach(field.def_id, macro_ev).ty();
                         }
-                    } else {
-                        bug!("item {:?} with DefKind {:?}", item, def_kind);
                     }
+                } else {
+                    bug!("item {:?} with DefKind {:?}", item, def_kind);
                 }
             }
 
@@ -629,14 +676,16 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let item_level = match item.kind {
+        let item_ev = match item.kind {
             hir::ItemKind::Impl { .. } => {
-                let impl_level = Option::<Level>::of_impl(
+                let impl_ev = Option::<EffectiveVisibility>::of_impl(
                     item.owner_id.def_id,
                     self.tcx,
                     &self.effective_visibilities,
                 );
-                self.update(item.owner_id.def_id, impl_level)
+
+                self.update_eff_vis(item.owner_id.def_id, impl_ev, None, Level::Direct);
+                impl_ev
             }
             _ => self.get(item.owner_id.def_id),
         };
@@ -645,38 +694,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
         match item.kind {
             hir::ItemKind::Enum(ref def, _) => {
                 for variant in def.variants {
-                    let variant_level = self.update(variant.def_id, item_level);
+                    self.update(variant.def_id, item_ev, Level::Reachable);
+                    let variant_ev = self.get(variant.def_id);
                     if let Some(ctor_def_id) = variant.data.ctor_def_id() {
-                        self.update(ctor_def_id, item_level);
+                        self.update(ctor_def_id, variant_ev, Level::Reachable);
                     }
                     for field in variant.data.fields() {
-                        self.update(field.def_id, variant_level);
+                        self.update(field.def_id, variant_ev, Level::Reachable);
                     }
                 }
             }
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
-                    if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
-                    {
-                        self.update(impl_item_ref.id.owner_id.def_id, item_level);
-                    }
+                    self.update(impl_item_ref.id.owner_id.def_id, item_ev, Level::Direct);
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 for trait_item_ref in trait_item_refs {
-                    self.update(trait_item_ref.id.owner_id.def_id, item_level);
+                    self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable);
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
                 if let Some(ctor_def_id) = def.ctor_def_id() {
-                    self.update(ctor_def_id, item_level);
+                    self.update(ctor_def_id, item_ev, Level::Reachable);
                 }
                 for field in def.fields() {
-                    let vis = self.tcx.visibility(field.def_id);
-                    if vis.is_public() {
-                        self.update(field.def_id, item_level);
-                    }
+                    self.update(field.def_id, item_ev, Level::Reachable);
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -684,9 +727,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if self.tcx.visibility(foreign_item.id.owner_id).is_public() {
-                        self.update(foreign_item.id.owner_id.def_id, item_level);
-                    }
+                    self.update(foreign_item.id.owner_id.def_id, item_ev, Level::Reachable);
                 }
             }
 
@@ -721,8 +762,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     // FIXME: This is some serious pessimization intended to workaround deficiencies
                     // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
                     // reachable if they are returned via `impl Trait`, even from private functions.
-                    let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait));
-                    self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty();
+                    let exist_ev = Some(EffectiveVisibility::from_vis(ty::Visibility::Public));
+                    self.reach_through_impl_trait(item.owner_id.def_id, exist_ev)
+                        .generics()
+                        .predicates()
+                        .ty();
                 }
             }
             // Visit everything.
@@ -730,17 +774,18 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates().ty();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
                         let tcx = self.tcx;
-                        let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level);
+                        let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev);
+
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
@@ -754,23 +799,24 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                 }
             }
             hir::ItemKind::TraitAlias(..) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
                 }
             }
             // Visit everything except for private impl items.
             hir::ItemKind::Impl(ref impl_) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level)
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev)
                         .generics()
                         .predicates()
                         .ty()
                         .trait_ref();
 
                     for impl_item_ref in impl_.items {
-                        let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id);
-                        if impl_item_level.is_some() {
-                            self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level)
+                        let impl_item_ev = self.get(impl_item_ref.id.owner_id.def_id);
+
+                        if impl_item_ev.is_some() {
+                            self.reach(impl_item_ref.id.owner_id.def_id, impl_item_ev)
                                 .generics()
                                 .predicates()
                                 .ty();
@@ -781,23 +827,23 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
 
             // Visit everything, but enum variants have their own levels.
             hir::ItemKind::Enum(ref def, _) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
                 }
                 for variant in def.variants {
-                    let variant_level = self.get(variant.def_id);
-                    if variant_level.is_some() {
+                    let variant_ev = self.get(variant.def_id);
+                    if variant_ev.is_some() {
                         for field in variant.data.fields() {
-                            self.reach(field.def_id, variant_level).ty();
+                            self.reach(field.def_id, variant_ev).ty();
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.reach(item.owner_id.def_id, variant_level).ty();
+                        self.reach(item.owner_id.def_id, variant_ev).ty();
                     }
                     if let Some(ctor_def_id) = variant.data.ctor_def_id() {
-                        let ctor_level = self.get(ctor_def_id);
-                        if ctor_level.is_some() {
-                            self.reach(item.owner_id.def_id, ctor_level).ty();
+                        let ctor_ev = self.get(ctor_def_id);
+                        if ctor_ev.is_some() {
+                            self.reach(item.owner_id.def_id, ctor_ev).ty();
                         }
                     }
                 }
@@ -805,9 +851,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything, but foreign items have their own levels.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    let foreign_item_level = self.get(foreign_item.id.owner_id.def_id);
-                    if foreign_item_level.is_some() {
-                        self.reach(foreign_item.id.owner_id.def_id, foreign_item_level)
+                    let foreign_item_ev = self.get(foreign_item.id.owner_id.def_id);
+                    if foreign_item_ev.is_some() {
+                        self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev)
                             .generics()
                             .predicates()
                             .ty();
@@ -816,36 +862,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             // Visit everything except for private fields.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
                     for field in struct_def.fields() {
-                        let field_level = self.get(field.def_id);
-                        if field_level.is_some() {
-                            self.reach(field.def_id, field_level).ty();
+                        let field_ev = self.get(field.def_id);
+                        if field_ev.is_some() {
+                            self.reach(field.def_id, field_ev).ty();
                         }
                     }
                 }
                 if let Some(ctor_def_id) = struct_def.ctor_def_id() {
-                    let ctor_level = self.get(ctor_def_id);
-                    if ctor_level.is_some() {
-                        self.reach(item.owner_id.def_id, ctor_level).ty();
+                    let ctor_ev = self.get(ctor_def_id);
+                    if ctor_ev.is_some() {
+                        self.reach(item.owner_id.def_id, ctor_ev).ty();
                     }
                 }
             }
         }
 
-        let orig_level = mem::replace(&mut self.prev_level, item_level);
         intravisit::walk_item(self, item);
-        self.prev_level = orig_level;
     }
 
     fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
         // Blocks can have public items, for example impls, but they always
         // start as completely private regardless of publicity of a function,
         // constant, type, field, etc., in which this block resides.
-        let orig_level = mem::replace(&mut self.prev_level, None);
         intravisit::walk_block(self, b);
-        self.prev_level = orig_level;
     }
 }
 
@@ -899,11 +941,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
         if let Some(def_id) = def_id.as_local() {
-            if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) =
-                (self.tcx().visibility(def_id.to_def_id()), self.level)
-            {
-                self.ev.update(def_id, self.level);
-            }
+            self.ev.update_eff_vis(def_id, self.effective_vis, None, self.level);
         }
         ControlFlow::Continue(())
     }
@@ -2131,7 +2169,6 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
         tcx,
         effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
         macro_reachable: Default::default(),
-        prev_level: Some(Level::Direct),
         changed: false,
     };
 
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 87067189a77..7393bdb388a 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -199,7 +199,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         let tcx = self.r.tcx;
         self.changed |= self.import_effective_visibilities.update(
             binding,
-            nominal_vis,
+            Some(nominal_vis),
             || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)),
             inherited_eff_vis,
             parent_id.level(),
@@ -213,7 +213,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         let tcx = self.r.tcx;
         self.changed |= self.def_effective_visibilities.update(
             def_id,
-            nominal_vis,
+            Some(nominal_vis),
             || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)),
             inherited_eff_vis,
             parent_id.level(),
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index a2ec318df6d..6b559cb5b2f 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -265,52 +265,41 @@ impl Drop for FileEncoder {
     }
 }
 
-macro_rules! file_encoder_write_leb128 {
-    ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
-        const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
+macro_rules! write_leb128 {
+    ($this_fn:ident, $int_ty:ty, $write_leb_fn:ident) => {
+        #[inline]
+        fn $this_fn(&mut self, v: $int_ty) {
+            const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
 
-        // We ensure this during `FileEncoder` construction.
-        debug_assert!($enc.capacity() >= MAX_ENCODED_LEN);
+            // We ensure this during `FileEncoder` construction.
+            debug_assert!(self.capacity() >= MAX_ENCODED_LEN);
 
-        let mut buffered = $enc.buffered;
+            let mut buffered = self.buffered;
 
-        // This can't overflow. See assertion in `FileEncoder::with_capacity`.
-        if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > $enc.capacity()) {
-            $enc.flush();
-            buffered = 0;
-        }
+            // This can't overflow. See assertion in `FileEncoder::with_capacity`.
+            if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > self.capacity()) {
+                self.flush();
+                buffered = 0;
+            }
 
-        // SAFETY: The above check and flush ensures that there is enough
-        // room to write the encoded value to the buffer.
-        let buf = unsafe {
-            &mut *($enc.buf.as_mut_ptr().add(buffered) as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN])
-        };
+            // SAFETY: The above check and flush ensures that there is enough
+            // room to write the encoded value to the buffer.
+            let buf = unsafe {
+                &mut *(self.buf.as_mut_ptr().add(buffered)
+                    as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN])
+            };
 
-        let encoded = leb128::$fun(buf, $value);
-        $enc.buffered = buffered + encoded.len();
-    }};
+            let encoded = leb128::$write_leb_fn(buf, v);
+            self.buffered = buffered + encoded.len();
+        }
+    };
 }
 
 impl Encoder for FileEncoder {
-    #[inline]
-    fn emit_usize(&mut self, v: usize) {
-        file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
-    }
-
-    #[inline]
-    fn emit_u128(&mut self, v: u128) {
-        file_encoder_write_leb128!(self, v, u128, write_u128_leb128)
-    }
-
-    #[inline]
-    fn emit_u64(&mut self, v: u64) {
-        file_encoder_write_leb128!(self, v, u64, write_u64_leb128)
-    }
-
-    #[inline]
-    fn emit_u32(&mut self, v: u32) {
-        file_encoder_write_leb128!(self, v, u32, write_u32_leb128)
-    }
+    write_leb128!(emit_usize, usize, write_usize_leb128);
+    write_leb128!(emit_u128, u128, write_u128_leb128);
+    write_leb128!(emit_u64, u64, write_u64_leb128);
+    write_leb128!(emit_u32, u32, write_u32_leb128);
 
     #[inline]
     fn emit_u16(&mut self, v: u16) {
@@ -322,25 +311,10 @@ impl Encoder for FileEncoder {
         self.write_one(v);
     }
 
-    #[inline]
-    fn emit_isize(&mut self, v: isize) {
-        file_encoder_write_leb128!(self, v, isize, write_isize_leb128)
-    }
-
-    #[inline]
-    fn emit_i128(&mut self, v: i128) {
-        file_encoder_write_leb128!(self, v, i128, write_i128_leb128)
-    }
-
-    #[inline]
-    fn emit_i64(&mut self, v: i64) {
-        file_encoder_write_leb128!(self, v, i64, write_i64_leb128)
-    }
-
-    #[inline]
-    fn emit_i32(&mut self, v: i32) {
-        file_encoder_write_leb128!(self, v, i32, write_i32_leb128)
-    }
+    write_leb128!(emit_isize, isize, write_isize_leb128);
+    write_leb128!(emit_i128, i128, write_i128_leb128);
+    write_leb128!(emit_i64, i64, write_i64_leb128);
+    write_leb128!(emit_i32, i32, write_i32_leb128);
 
     #[inline]
     fn emit_i16(&mut self, v: i16) {
@@ -437,30 +411,19 @@ impl<'a> MemDecoder<'a> {
 }
 
 macro_rules! read_leb128 {
-    ($dec:expr, $fun:ident) => {{ leb128::$fun($dec) }};
+    ($this_fn:ident, $int_ty:ty, $read_leb_fn:ident) => {
+        #[inline]
+        fn $this_fn(&mut self) -> $int_ty {
+            leb128::$read_leb_fn(self)
+        }
+    };
 }
 
 impl<'a> Decoder for MemDecoder<'a> {
-    #[inline]
-    fn position(&self) -> usize {
-        // SAFETY: This type guarantees start <= current
-        unsafe { self.current.sub_ptr(self.start) }
-    }
-
-    #[inline]
-    fn read_u128(&mut self) -> u128 {
-        read_leb128!(self, read_u128_leb128)
-    }
-
-    #[inline]
-    fn read_u64(&mut self) -> u64 {
-        read_leb128!(self, read_u64_leb128)
-    }
-
-    #[inline]
-    fn read_u32(&mut self) -> u32 {
-        read_leb128!(self, read_u32_leb128)
-    }
+    read_leb128!(read_usize, usize, read_usize_leb128);
+    read_leb128!(read_u128, u128, read_u128_leb128);
+    read_leb128!(read_u64, u64, read_u64_leb128);
+    read_leb128!(read_u32, u32, read_u32_leb128);
 
     #[inline]
     fn read_u16(&mut self) -> u16 {
@@ -480,25 +443,10 @@ impl<'a> Decoder for MemDecoder<'a> {
         }
     }
 
-    #[inline]
-    fn read_usize(&mut self) -> usize {
-        read_leb128!(self, read_usize_leb128)
-    }
-
-    #[inline]
-    fn read_i128(&mut self) -> i128 {
-        read_leb128!(self, read_i128_leb128)
-    }
-
-    #[inline]
-    fn read_i64(&mut self) -> i64 {
-        read_leb128!(self, read_i64_leb128)
-    }
-
-    #[inline]
-    fn read_i32(&mut self) -> i32 {
-        read_leb128!(self, read_i32_leb128)
-    }
+    read_leb128!(read_isize, isize, read_isize_leb128);
+    read_leb128!(read_i128, i128, read_i128_leb128);
+    read_leb128!(read_i64, i64, read_i64_leb128);
+    read_leb128!(read_i32, i32, read_i32_leb128);
 
     #[inline]
     fn read_i16(&mut self) -> i16 {
@@ -506,11 +454,6 @@ impl<'a> Decoder for MemDecoder<'a> {
     }
 
     #[inline]
-    fn read_isize(&mut self) -> isize {
-        read_leb128!(self, read_isize_leb128)
-    }
-
-    #[inline]
     fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] {
         if bytes > self.remaining() {
             Self::decoder_exhausted();
@@ -532,6 +475,12 @@ impl<'a> Decoder for MemDecoder<'a> {
         // Since we just checked current == end, the current pointer must be inbounds.
         unsafe { *self.current }
     }
+
+    #[inline]
+    fn position(&self) -> usize {
+        // SAFETY: This type guarantees start <= current
+        unsafe { self.current.sub_ptr(self.start) }
+    }
 }
 
 // Specializations for contiguous byte sequences follow. The default implementations for slices
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index e1bc598736f..06166cabc18 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -1,9 +1,5 @@
 //! Support code for encoding and decoding types.
 
-/*
-Core encoding and decoding interfaces.
-*/
-
 use std::alloc::Allocator;
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
@@ -35,13 +31,13 @@ const STR_SENTINEL: u8 = 0xC1;
 /// really makes sense to store floating-point values at all.
 /// (If you need it, revert <https://github.com/rust-lang/rust/pull/109984>.)
 pub trait Encoder {
-    // Primitive types:
     fn emit_usize(&mut self, v: usize);
     fn emit_u128(&mut self, v: u128);
     fn emit_u64(&mut self, v: u64);
     fn emit_u32(&mut self, v: u32);
     fn emit_u16(&mut self, v: u16);
     fn emit_u8(&mut self, v: u8);
+
     fn emit_isize(&mut self, v: isize);
     fn emit_i128(&mut self, v: i128);
     fn emit_i64(&mut self, v: i64);
@@ -93,13 +89,13 @@ pub trait Encoder {
 /// really makes sense to store floating-point values at all.
 /// (If you need it, revert <https://github.com/rust-lang/rust/pull/109984>.)
 pub trait Decoder {
-    // Primitive types:
     fn read_usize(&mut self) -> usize;
     fn read_u128(&mut self) -> u128;
     fn read_u64(&mut self) -> u64;
     fn read_u32(&mut self) -> u32;
     fn read_u16(&mut self) -> u16;
     fn read_u8(&mut self) -> u8;
+
     fn read_isize(&mut self) -> isize;
     fn read_i128(&mut self) -> i128;
     fn read_i64(&mut self) -> i64;
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index c897275bee2..a8fe560d1a7 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -101,3 +101,5 @@ session_invalid_int_literal_width = invalid width `{$width}` for integer literal
     .help = valid widths are 8, 16, 32, 64 and 128
 
 session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
+
+session_nul_in_c_str = null characters in C string literals are not supported
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index cfdba1120ec..d80cc0aa043 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -518,6 +518,12 @@ pub struct ExternEntry {
     /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
     /// suppress `unused-crate-dependencies` warnings.
     pub nounused_dep: bool,
+    /// If the extern entry is not referenced in the crate, force it to be resolved anyway.
+    ///
+    /// Allows a dependency satisfying, for instance, a missing panic handler to be injected
+    /// without modifying source:
+    /// `--extern force:extras=/path/to/lib/libstd.rlib`
+    pub force: bool,
 }
 
 #[derive(Clone, Debug)]
@@ -556,7 +562,13 @@ impl Externs {
 
 impl ExternEntry {
     fn new(location: ExternLocation) -> ExternEntry {
-        ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
+        ExternEntry {
+            location,
+            is_private_dep: false,
+            add_prelude: false,
+            nounused_dep: false,
+            force: false,
+        }
     }
 
     pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
@@ -1064,37 +1076,76 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
 
 /// The parsed `--check-cfg` options
 pub struct CheckCfg<T = String> {
-    /// The set of all `names()`, if None no name checking is performed
-    pub names_valid: Option<FxHashSet<T>>,
+    /// Is well known names activated
+    pub exhaustive_names: bool,
     /// Is well known values activated
-    pub well_known_values: bool,
-    /// The set of all `values()`
-    pub values_valid: FxHashMap<T, FxHashSet<T>>,
+    pub exhaustive_values: bool,
+    /// All the expected values for a config name
+    pub expecteds: FxHashMap<T, ExpectedValues<T>>,
 }
 
 impl<T> Default for CheckCfg<T> {
     fn default() -> Self {
         CheckCfg {
-            names_valid: Default::default(),
-            values_valid: Default::default(),
-            well_known_values: false,
+            exhaustive_names: false,
+            exhaustive_values: false,
+            expecteds: FxHashMap::default(),
         }
     }
 }
 
 impl<T> CheckCfg<T> {
-    fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
+    fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
         CheckCfg {
-            names_valid: self
-                .names_valid
-                .as_ref()
-                .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
-            values_valid: self
-                .values_valid
-                .iter()
-                .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
+            exhaustive_names: self.exhaustive_names,
+            exhaustive_values: self.exhaustive_values,
+            expecteds: self
+                .expecteds
+                .into_iter()
+                .map(|(name, values)| {
+                    (
+                        f(name),
+                        match values {
+                            ExpectedValues::Some(values) => ExpectedValues::Some(
+                                values.into_iter().map(|b| b.map(|b| f(b))).collect(),
+                            ),
+                            ExpectedValues::Any => ExpectedValues::Any,
+                        },
+                    )
+                })
                 .collect(),
-            well_known_values: self.well_known_values,
+        }
+    }
+}
+
+pub enum ExpectedValues<T> {
+    Some(FxHashSet<Option<T>>),
+    Any,
+}
+
+impl<T: Eq + Hash> ExpectedValues<T> {
+    fn insert(&mut self, value: T) -> bool {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
+            ExpectedValues::Any => false,
+        }
+    }
+}
+
+impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
+            ExpectedValues::Any => {}
+        }
+    }
+}
+
+impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
+    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
+            ExpectedValues::Any => {}
         }
     }
 }
@@ -1103,58 +1154,27 @@ impl<T> CheckCfg<T> {
 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
 /// but the symbol interner is not yet set up then, so we must convert it later.
 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
-    cfg.map_data(|s| Symbol::intern(s))
+    cfg.map_data(|s| Symbol::intern(&s))
 }
 
 impl CrateCheckConfig {
-    /// Fills a `CrateCheckConfig` with well-known configuration names.
-    fn fill_well_known_names(&mut self) {
-        // NOTE: This should be kept in sync with `default_configuration` and
-        // `fill_well_known_values`
-        const WELL_KNOWN_NAMES: &[Symbol] = &[
-            // rustc
-            sym::unix,
-            sym::windows,
-            sym::target_os,
-            sym::target_family,
-            sym::target_arch,
-            sym::target_endian,
-            sym::target_pointer_width,
-            sym::target_env,
-            sym::target_abi,
-            sym::target_vendor,
-            sym::target_thread_local,
-            sym::target_has_atomic_load_store,
-            sym::target_has_atomic,
-            sym::target_has_atomic_equal_alignment,
-            sym::target_feature,
-            sym::panic,
-            sym::sanitize,
-            sym::debug_assertions,
-            sym::proc_macro,
-            sym::test,
-            sym::feature,
-            // rustdoc
-            sym::doc,
-            sym::doctest,
-            // miri
-            sym::miri,
-        ];
-
-        // We only insert well-known names if `names()` was activated
-        if let Some(names_valid) = &mut self.names_valid {
-            names_valid.extend(WELL_KNOWN_NAMES);
-        }
-    }
-
-    /// Fills a `CrateCheckConfig` with well-known configuration values.
-    fn fill_well_known_values(&mut self, current_target: &Target) {
-        if !self.well_known_values {
+    pub fn fill_well_known(&mut self, current_target: &Target) {
+        if !self.exhaustive_values && !self.exhaustive_names {
             return;
         }
 
-        // NOTE: This should be kept in sync with `default_configuration` and
-        // `fill_well_known_names`
+        let no_values = || {
+            let mut values = FxHashSet::default();
+            values.insert(None);
+            ExpectedValues::Some(values)
+        };
+
+        let empty_values = || {
+            let values = FxHashSet::default();
+            ExpectedValues::Some(values)
+        };
+
+        // NOTE: This should be kept in sync with `default_configuration`
 
         let panic_values = &PanicStrategy::all();
 
@@ -1174,6 +1194,9 @@ impl CrateCheckConfig {
         // Unknown possible values:
         //  - `feature`
         //  - `target_feature`
+        for name in [sym::feature, sym::target_feature] {
+            self.expecteds.entry(name).or_insert(ExpectedValues::Any);
+        }
 
         // No-values
         for name in [
@@ -1187,20 +1210,23 @@ impl CrateCheckConfig {
             sym::debug_assertions,
             sym::target_thread_local,
         ] {
-            self.values_valid.entry(name).or_default();
+            self.expecteds.entry(name).or_insert_with(no_values);
         }
 
         // Pre-defined values
-        self.values_valid.entry(sym::panic).or_default().extend(panic_values);
-        self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
-        self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
-        self.values_valid
+        self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values);
+        self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values);
+        self.expecteds
+            .entry(sym::target_has_atomic)
+            .or_insert_with(no_values)
+            .extend(atomic_values);
+        self.expecteds
             .entry(sym::target_has_atomic_load_store)
-            .or_default()
+            .or_insert_with(no_values)
             .extend(atomic_values);
-        self.values_valid
+        self.expecteds
             .entry(sym::target_has_atomic_equal_alignment)
-            .or_default()
+            .or_insert_with(no_values)
             .extend(atomic_values);
 
         // Target specific values
@@ -1218,47 +1244,50 @@ impl CrateCheckConfig {
 
             // Initialize (if not already initialized)
             for &e in VALUES {
-                self.values_valid.entry(e).or_default();
+                let entry = self.expecteds.entry(e);
+                if !self.exhaustive_values {
+                    entry.or_insert(ExpectedValues::Any);
+                } else {
+                    entry.or_insert_with(empty_values);
+                }
             }
 
-            // Get all values map at once otherwise it would be costly.
-            // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
-            let [
-                values_target_os,
-                values_target_family,
-                values_target_arch,
-                values_target_endian,
-                values_target_env,
-                values_target_abi,
-                values_target_vendor,
-                values_target_pointer_width,
-            ] = self
-                .values_valid
-                .get_many_mut(VALUES)
-                .expect("unable to get all the check-cfg values buckets");
-
-            for target in TARGETS
-                .iter()
-                .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
-                .chain(iter::once(current_target.clone()))
-            {
-                values_target_os.insert(Symbol::intern(&target.options.os));
-                values_target_family
-                    .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
-                values_target_arch.insert(Symbol::intern(&target.arch));
-                values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
-                values_target_env.insert(Symbol::intern(&target.options.env));
-                values_target_abi.insert(Symbol::intern(&target.options.abi));
-                values_target_vendor.insert(Symbol::intern(&target.options.vendor));
-                values_target_pointer_width.insert(sym::integer(target.pointer_width));
+            if self.exhaustive_values {
+                // Get all values map at once otherwise it would be costly.
+                // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
+                let [
+                    values_target_os,
+                    values_target_family,
+                    values_target_arch,
+                    values_target_endian,
+                    values_target_env,
+                    values_target_abi,
+                    values_target_vendor,
+                    values_target_pointer_width,
+                ] = self
+                    .expecteds
+                    .get_many_mut(VALUES)
+                    .expect("unable to get all the check-cfg values buckets");
+
+                for target in TARGETS
+                    .iter()
+                    .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+                    .chain(iter::once(current_target.clone()))
+                {
+                    values_target_os.insert(Symbol::intern(&target.options.os));
+                    values_target_family.extend(
+                        target.options.families.iter().map(|family| Symbol::intern(family)),
+                    );
+                    values_target_arch.insert(Symbol::intern(&target.arch));
+                    values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
+                    values_target_env.insert(Symbol::intern(&target.options.env));
+                    values_target_abi.insert(Symbol::intern(&target.options.abi));
+                    values_target_vendor.insert(Symbol::intern(&target.options.vendor));
+                    values_target_pointer_width.insert(sym::integer(target.pointer_width));
+                }
             }
         }
     }
-
-    pub fn fill_well_known(&mut self, current_target: &Target) {
-        self.fill_well_known_names();
-        self.fill_well_known_values(current_target);
-    }
 }
 
 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
@@ -2244,6 +2273,7 @@ pub fn parse_externs(
         let mut is_private_dep = false;
         let mut add_prelude = true;
         let mut nounused_dep = false;
+        let mut force = false;
         if let Some(opts) = options {
             if !is_unstable_enabled {
                 early_error(
@@ -2266,6 +2296,7 @@ pub fn parse_externs(
                         }
                     }
                     "nounused" => nounused_dep = true,
+                    "force" => force = true,
                     _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
                 }
             }
@@ -2276,6 +2307,8 @@ pub fn parse_externs(
         entry.is_private_dep |= is_private_dep;
         // likewise `nounused`
         entry.nounused_dep |= nounused_dep;
+        // and `force`
+        entry.force |= force;
         // If any flag is missing `noprelude`, then add to the prelude.
         entry.add_prelude |= add_prelude;
     }
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 0df62c2064e..546c0fa8e03 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_ast::token;
 use rustc_ast::util::literal::LitError;
 use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
 use rustc_macros::Diagnostic;
-use rustc_span::{Span, Symbol};
+use rustc_span::{BytePos, Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(Diagnostic)]
@@ -323,6 +323,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_nul_in_c_str)]
+pub(crate) struct NulInCStr {
+    #[primary_span]
+    pub span: Span,
+}
+
 pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
     // Checks if `s` looks like i32 or u1234 etc.
     fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -401,6 +408,12 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             };
             sess.emit_err(IntLiteralTooLarge { span, limit });
         }
+        LitError::NulInCStr(range) => {
+            let lo = BytePos(span.lo().0 + range.start as u32 + 2);
+            let hi = BytePos(span.lo().0 + range.end as u32 + 2);
+            let span = span.with_lo(lo).with_hi(hi);
+            sess.emit_err(NulInCStr { span });
+        }
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d9e191c00c9..243da98c3c2 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1235,6 +1235,8 @@ options! {
         line-tables-only, limited, or full; default: 0)"),
     default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
         "allow the linker to link its default libraries (default: no)"),
+    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "import library generation tool (ignored except when targeting windows-gnu)"),
     embed_bitcode: bool = (true, parse_bool, [TRACKED],
         "emit bitcode in rlibs (default: yes)"),
     extra_filename: String = (String::new(), parse_string, [UNTRACKED],
@@ -1391,8 +1393,6 @@ options! {
         (default: no)"),
     diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
         "set the current output width for diagnostic truncation"),
-    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
-        "import library generation tool (windows-gnu only)"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml
index fb97ee5bebe..80360a3c73f 100644
--- a/compiler/rustc_smir/Cargo.toml
+++ b/compiler/rustc_smir/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
+rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
 tracing = "0.1"
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 09cb6fd22d5..241cd182059 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -93,10 +93,10 @@ fn rustc_statement_to_statement(
     }
 }
 
-fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Operand {
+fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Rvalue {
     use rustc_middle::mir::Rvalue::*;
     match rvalue {
-        Use(op) => rustc_op_to_op(op),
+        Use(op) => stable_mir::mir::Rvalue::Use(rustc_op_to_op(op)),
         Repeat(_, _) => todo!(),
         Ref(_, _, _) => todo!(),
         ThreadLocalRef(_) => todo!(),
@@ -104,9 +104,15 @@ fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir:
         Len(_) => todo!(),
         Cast(_, _, _) => todo!(),
         BinaryOp(_, _) => todo!(),
-        CheckedBinaryOp(_, _) => todo!(),
+        CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
+            rustc_bin_op_to_bin_op(bin_op),
+            rustc_op_to_op(&ops.0),
+            rustc_op_to_op(&ops.1),
+        ),
         NullaryOp(_, _) => todo!(),
-        UnaryOp(_, _) => todo!(),
+        UnaryOp(un_op, op) => {
+            stable_mir::mir::Rvalue::UnaryOp(rustc_un_op_to_un_op(un_op), rustc_op_to_op(op))
+        }
         Discriminant(_) => todo!(),
         Aggregate(_, _) => todo!(),
         ShallowInitBox(_, _) => todo!(),
@@ -124,8 +130,10 @@ fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Opera
 }
 
 fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place {
-    assert_eq!(&place.projection[..], &[]);
-    stable_mir::mir::Place { local: place.local.as_usize() }
+    stable_mir::mir::Place {
+        local: place.local.as_usize(),
+        projection: format!("{:?}", place.projection),
+    }
 }
 
 fn rustc_unwind_to_unwind(
@@ -140,6 +148,96 @@ fn rustc_unwind_to_unwind(
     }
 }
 
+fn rustc_assert_msg_to_msg<'tcx>(
+    assert_message: &rustc_middle::mir::AssertMessage<'tcx>,
+) -> stable_mir::mir::AssertMessage {
+    use rustc_middle::mir::AssertKind;
+    match assert_message {
+        AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
+            len: rustc_op_to_op(len),
+            index: rustc_op_to_op(index),
+        },
+        AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
+            rustc_bin_op_to_bin_op(bin_op),
+            rustc_op_to_op(op1),
+            rustc_op_to_op(op2),
+        ),
+        AssertKind::OverflowNeg(op) => {
+            stable_mir::mir::AssertMessage::OverflowNeg(rustc_op_to_op(op))
+        }
+        AssertKind::DivisionByZero(op) => {
+            stable_mir::mir::AssertMessage::DivisionByZero(rustc_op_to_op(op))
+        }
+        AssertKind::RemainderByZero(op) => {
+            stable_mir::mir::AssertMessage::RemainderByZero(rustc_op_to_op(op))
+        }
+        AssertKind::ResumedAfterReturn(generator) => {
+            stable_mir::mir::AssertMessage::ResumedAfterReturn(rustc_generator_to_generator(
+                generator,
+            ))
+        }
+        AssertKind::ResumedAfterPanic(generator) => {
+            stable_mir::mir::AssertMessage::ResumedAfterPanic(rustc_generator_to_generator(
+                generator,
+            ))
+        }
+        AssertKind::MisalignedPointerDereference { required, found } => {
+            stable_mir::mir::AssertMessage::MisalignedPointerDereference {
+                required: rustc_op_to_op(required),
+                found: rustc_op_to_op(found),
+            }
+        }
+    }
+}
+
+fn rustc_bin_op_to_bin_op(bin_op: &rustc_middle::mir::BinOp) -> stable_mir::mir::BinOp {
+    use rustc_middle::mir::BinOp;
+    match bin_op {
+        BinOp::Add => stable_mir::mir::BinOp::Add,
+        BinOp::Sub => stable_mir::mir::BinOp::Sub,
+        BinOp::Mul => stable_mir::mir::BinOp::Mul,
+        BinOp::Div => stable_mir::mir::BinOp::Div,
+        BinOp::Rem => stable_mir::mir::BinOp::Rem,
+        BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
+        BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
+        BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
+        BinOp::Shl => stable_mir::mir::BinOp::Shl,
+        BinOp::Shr => stable_mir::mir::BinOp::Shr,
+        BinOp::Eq => stable_mir::mir::BinOp::Eq,
+        BinOp::Lt => stable_mir::mir::BinOp::Lt,
+        BinOp::Le => stable_mir::mir::BinOp::Le,
+        BinOp::Ne => stable_mir::mir::BinOp::Ne,
+        BinOp::Ge => stable_mir::mir::BinOp::Ge,
+        BinOp::Gt => stable_mir::mir::BinOp::Gt,
+        BinOp::Offset => stable_mir::mir::BinOp::Offset,
+    }
+}
+
+fn rustc_un_op_to_un_op(unary_op: &rustc_middle::mir::UnOp) -> stable_mir::mir::UnOp {
+    use rustc_middle::mir::UnOp;
+    match unary_op {
+        UnOp::Not => stable_mir::mir::UnOp::Not,
+        UnOp::Neg => stable_mir::mir::UnOp::Neg,
+    }
+}
+
+fn rustc_generator_to_generator(
+    generator: &rustc_hir::GeneratorKind,
+) -> stable_mir::mir::GeneratorKind {
+    use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
+    match generator {
+        GeneratorKind::Async(async_gen) => {
+            let async_gen = match async_gen {
+                AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block,
+                AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure,
+                AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn,
+            };
+            stable_mir::mir::GeneratorKind::Async(async_gen)
+        }
+        GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen,
+    }
+}
+
 fn rustc_terminator_to_terminator(
     terminator: &rustc_middle::mir::Terminator<'_>,
 ) -> stable_mir::mir::Terminator {
@@ -162,7 +260,11 @@ fn rustc_terminator_to_terminator(
         Terminate => Terminator::Abort,
         Return => Terminator::Return,
         Unreachable => Terminator::Unreachable,
-        Drop { .. } => todo!(),
+        Drop { place, target, unwind } => Terminator::Drop {
+            place: rustc_place_to_place(place),
+            target: target.as_usize(),
+            unwind: rustc_unwind_to_unwind(unwind),
+        },
         Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => {
             Terminator::Call {
                 func: rustc_op_to_op(func),
@@ -172,9 +274,15 @@ fn rustc_terminator_to_terminator(
                 unwind: rustc_unwind_to_unwind(unwind),
             }
         }
-        Assert { .. } => todo!(),
+        Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
+            cond: rustc_op_to_op(cond),
+            expected: *expected,
+            msg: rustc_assert_msg_to_msg(msg),
+            target: target.as_usize(),
+            unwind: rustc_unwind_to_unwind(unwind),
+        },
         Yield { .. } => todo!(),
-        GeneratorDrop => todo!(),
+        GeneratorDrop => Terminator::GeneratorDrop,
         FalseEdge { .. } => todo!(),
         FalseUnwind { .. } => todo!(),
         InlineAsm { .. } => todo!(),
diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs
index bd5e6b68a12..4baf3f1f75e 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/body.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs
@@ -26,7 +26,7 @@ pub enum Terminator {
     Drop {
         place: Place,
         target: usize,
-        unwind: Option<usize>,
+        unwind: UnwindAction,
     },
     Call {
         func: Operand,
@@ -38,10 +38,11 @@ pub enum Terminator {
     Assert {
         cond: Operand,
         expected: bool,
-        msg: String,
+        msg: AssertMessage,
         target: usize,
-        cleanup: Option<usize>,
+        unwind: UnwindAction,
     },
+    GeneratorDrop,
 }
 
 #[derive(Clone, Debug)]
@@ -53,11 +54,71 @@ pub enum UnwindAction {
 }
 
 #[derive(Clone, Debug)]
+pub enum AssertMessage {
+    BoundsCheck { len: Operand, index: Operand },
+    Overflow(BinOp, Operand, Operand),
+    OverflowNeg(Operand),
+    DivisionByZero(Operand),
+    RemainderByZero(Operand),
+    ResumedAfterReturn(GeneratorKind),
+    ResumedAfterPanic(GeneratorKind),
+    MisalignedPointerDereference { required: Operand, found: Operand },
+}
+
+#[derive(Clone, Debug)]
+pub enum BinOp {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    BitXor,
+    BitAnd,
+    BitOr,
+    Shl,
+    Shr,
+    Eq,
+    Lt,
+    Le,
+    Ne,
+    Ge,
+    Gt,
+    Offset,
+}
+
+#[derive(Clone, Debug)]
+pub enum UnOp {
+    Not,
+    Neg,
+}
+
+#[derive(Clone, Debug)]
+pub enum GeneratorKind {
+    Async(AsyncGeneratorKind),
+    Gen,
+}
+
+#[derive(Clone, Debug)]
+pub enum AsyncGeneratorKind {
+    Block,
+    Closure,
+    Fn,
+}
+
+#[derive(Clone, Debug)]
 pub enum Statement {
-    Assign(Place, Operand),
+    Assign(Place, Rvalue),
     Nop,
 }
 
+// FIXME this is incomplete
+#[derive(Clone, Debug)]
+pub enum Rvalue {
+    Use(Operand),
+    CheckedBinaryOp(BinOp, Operand, Operand),
+    UnaryOp(UnOp, Operand),
+}
+
 #[derive(Clone, Debug)]
 pub enum Operand {
     Copy(Place),
@@ -68,6 +129,7 @@ pub enum Operand {
 #[derive(Clone, Debug)]
 pub struct Place {
     pub local: usize,
+    pub projection: String,
 }
 
 #[derive(Clone, Debug)]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 341cc61fd1c..7bbab34c69a 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1744,6 +1744,28 @@ impl SourceFile {
         BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
     }
 
+    /// Calculates a normalized byte position from a byte offset relative to the
+    /// start of the file.
+    ///
+    /// When we get an inline assembler error from LLVM during codegen, we
+    /// import the expanded assembly code as a new `SourceFile`, which can then
+    /// be used for error reporting with spans. However the byte offsets given
+    /// to us by LLVM are relative to the start of the original buffer, not the
+    /// normalized one. Hence we need to convert those offsets to the normalized
+    /// form when constructing spans.
+    pub fn normalized_byte_pos(&self, offset: u32) -> BytePos {
+        let diff = match self
+            .normalized_pos
+            .binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
+        {
+            Ok(i) => self.normalized_pos[i].diff,
+            Err(i) if i == 0 => 0,
+            Err(i) => self.normalized_pos[i - 1].diff,
+        };
+
+        BytePos::from_u32(self.start_pos.0 + offset - diff)
+    }
+
     /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
     pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
         // The number of extra bytes due to multibyte chars in the `SourceFile`.
@@ -2199,6 +2221,7 @@ pub struct ErrorGuaranteed(());
 impl ErrorGuaranteed {
     /// To be used only if you really know what you are doing... ideally, we would find a way to
     /// eliminate all calls to this method.
+    #[deprecated = "`Session::delay_span_bug` should be preferred over this function"]
     pub fn unchecked_claim_error_was_emitted() -> Self {
         ErrorGuaranteed(())
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1140a922f9f..b97ec6c684b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -441,6 +441,7 @@ symbols! {
         bridge,
         bswap,
         c_str,
+        c_str_literals,
         c_unwind,
         c_variadic,
         c_void,
@@ -1206,6 +1207,7 @@ symbols! {
         require,
         residual,
         result,
+        resume,
         return_position_impl_trait_in_trait,
         return_type_notation,
         rhs,
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 266691b2c88..705966f5237 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -839,6 +839,7 @@ pub enum InlineAsmClobberAbi {
     AArch64,
     AArch64NoX18,
     RiscV,
+    LoongArch,
 }
 
 impl InlineAsmClobberAbi {
@@ -880,6 +881,10 @@ impl InlineAsmClobberAbi {
                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
                 _ => Err(&["C", "system", "efiapi"]),
             },
+            InlineAsmArch::LoongArch64 => match name {
+                "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::LoongArch),
+                _ => Err(&["C", "system", "efiapi"]),
+            },
             _ => Err(&[]),
         }
     }
@@ -1022,6 +1027,21 @@ impl InlineAsmClobberAbi {
                     v24, v25, v26, v27, v28, v29, v30, v31,
                 }
             },
+            InlineAsmClobberAbi::LoongArch => clobbered_regs! {
+                LoongArch LoongArchInlineAsmReg {
+                    // ra
+                    r1,
+                    // a0-a7
+                    r4, r5, r6, r7, r8, r9, r10, r11,
+                    // t0-t8
+                    r12, r13, r14, r15, r16, r17, r18, r19, r20,
+                    // fa0-fa7
+                    f0, f1, f2, f3, f4, f5, f6, f7,
+                    // ft0-ft15
+                    f8, f9, f10, f11, f12, f13, f14, f15,
+                    f16, f17, f18, f19, f20, f21, f22, f23,
+                }
+            },
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
deleted file mode 100644
index 7e1dba4ed26..00000000000
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-use crate::infer::InferCtxt;
-
-use rustc_infer::infer::ObligationEmittingRelation;
-use rustc_infer::traits::PredicateObligations;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
-pub struct CollectAllMismatches<'a, 'tcx> {
-    pub infcx: &'a InferCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
-    pub errors: Vec<TypeError<'tcx>>,
-}
-
-impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
-    fn tag(&self) -> &'static str {
-        "CollectAllMismatches"
-    }
-
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        _: ty::Variance,
-        _: ty::VarianceDiagInfo<'tcx>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        self.relate(a, b)
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        _b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        Ok(a)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        self.infcx.probe(|_| {
-            if a.is_ty_var() || b.is_ty_var() {
-                Ok(a)
-            } else {
-                self.infcx.super_combine_tys(self, a, b).or_else(|e| {
-                    self.errors.push(e);
-                    Ok(a)
-                })
-            }
-        })
-    }
-
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        self.infcx.probe(|_| {
-            if a.is_ct_infer() || b.is_ct_infer() {
-                Ok(a)
-            } else {
-                relate::super_relate_consts(self, a, b) // could do something similar here for constants!
-            }
-        })
-    }
-
-    fn binders<T: Relate<'tcx>>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
-        Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
-    }
-}
-
-impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
-    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
-        // FIXME(deferred_projection_equality): We really should get rid of this relation.
-        ty::AliasRelationDirection::Equate
-    }
-
-    fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
-        // FIXME(deferred_projection_equality)
-    }
-
-    fn register_predicates(
-        &mut self,
-        _obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>,
-    ) {
-        // FIXME(deferred_projection_equality)
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 8f2a5d649f0..afb64da8b61 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1,5 +1,4 @@
 mod ambiguity;
-pub mod method_chain;
 pub mod on_unimplemented;
 pub mod suggestions;
 
@@ -559,6 +558,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             suggest_increasing_limit,
             |err| {
                 self.note_obligation_cause_code(
+                    obligation.cause.body_id,
                     err,
                     predicate,
                     obligation.param_env,
@@ -1431,6 +1431,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 | ObligationCauseCode::ExprItemObligation(..) = code
                 {
                     self.note_obligation_cause_code(
+                        error.obligation.cause.body_id,
                         &mut diag,
                         error.obligation.predicate,
                         error.obligation.param_env,
@@ -2544,6 +2545,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
             self.note_obligation_cause_code(
+                obligation.cause.body_id,
                 err,
                 obligation.predicate,
                 obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index d34eb193453..53bf38c0a34 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -25,10 +25,9 @@ use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_hir::{Expr, HirId};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
 use rustc_middle::hir::map;
 use rustc_middle::ty::error::TypeError::{self, Sorts};
-use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
@@ -39,9 +38,9 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
+use std::iter;
 use std::ops::Deref;
 
-use super::method_chain::CollectAllMismatches;
 use super::InferCtxtPrivExt;
 use crate::infer::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -319,6 +318,7 @@ pub trait TypeErrCtxtExt<'tcx> {
 
     fn note_obligation_cause_code<T>(
         &self,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
         predicate: T,
         param_env: ty::ParamEnv<'tcx>,
@@ -359,8 +359,9 @@ pub trait TypeErrCtxtExt<'tcx> {
     );
     fn note_function_argument_obligation(
         &self,
-        arg_hir_id: HirId,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
+        arg_hir_id: HirId,
         parent_code: &ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         predicate: ty::Predicate<'tcx>,
@@ -2742,6 +2743,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // bound that introduced the obligation (e.g. `T: Send`).
         debug!(?next_code);
         self.note_obligation_cause_code(
+            obligation.cause.body_id,
             err,
             obligation.predicate,
             obligation.param_env,
@@ -2753,6 +2755,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
     fn note_obligation_cause_code<T>(
         &self,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
         predicate: T,
         param_env: ty::ParamEnv<'tcx>,
@@ -2790,7 +2793,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::LetElse
             | ObligationCauseCode::BinOp { .. }
             | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
-            | ObligationCauseCode::RustCall => {}
+            | ObligationCauseCode::RustCall
+            | ObligationCauseCode::DropImpl => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
@@ -3152,6 +3156,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     // #74711: avoid a stack overflow
                     ensure_sufficient_stack(|| {
                         self.note_obligation_cause_code(
+                            body_id,
                             err,
                             parent_predicate,
                             param_env,
@@ -3163,6 +3168,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 } else {
                     ensure_sufficient_stack(|| {
                         self.note_obligation_cause_code(
+                            body_id,
                             err,
                             parent_predicate,
                             param_env,
@@ -3292,6 +3298,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // #74711: avoid a stack overflow
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
+                        body_id,
                         err,
                         parent_predicate,
                         param_env,
@@ -3307,6 +3314,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // #74711: avoid a stack overflow
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
+                        body_id,
                         err,
                         parent_predicate,
                         param_env,
@@ -3323,8 +3331,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ..
             } => {
                 self.note_function_argument_obligation(
-                    arg_hir_id,
+                    body_id,
                     err,
+                    arg_hir_id,
                     parent_code,
                     param_env,
                     predicate,
@@ -3332,6 +3341,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 );
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
+                        body_id,
                         err,
                         predicate,
                         param_env,
@@ -3553,8 +3563,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     }
     fn note_function_argument_obligation(
         &self,
-        arg_hir_id: HirId,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
+        arg_hir_id: HirId,
         parent_code: &ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         failed_pred: ty::Predicate<'tcx>,
@@ -3587,7 +3598,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             // to an associated type (as seen from `trait_pred`) in the predicate. Like in
             // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
             let mut type_diffs = vec![];
-
             if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
                 && let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id)
                 && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
@@ -3596,14 +3606,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
                     && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
                 {
-                    let mut c = CollectAllMismatches {
-                        infcx: self.infcx,
-                        param_env,
-                        errors: vec![],
+                    let where_pred = self.instantiate_binder_with_placeholders(where_pred);
+                    let failed_pred = self.instantiate_binder_with_fresh_vars(
+                        expr.span,
+                        LateBoundRegionConversionTime::FnCall,
+                        failed_pred
+                    );
+
+                    let zipped =
+                        iter::zip(where_pred.trait_ref.substs, failed_pred.trait_ref.substs);
+                    for (expected, actual) in zipped {
+                        self.probe(|_| {
+                            match self
+                                .at(&ObligationCause::misc(expr.span, body_id), param_env)
+                                .eq(DefineOpaqueTypes::No, expected, actual)
+                            {
+                                Ok(_) => (), // We ignore nested obligations here for now.
+                                Err(err) => type_diffs.push(err),
+                            }
+                        })
                     };
-                    if let Ok(_) = c.relate(where_pred, failed_pred) {
-                        type_diffs = c.errors;
-                    }
                 } else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
                     && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
                     && let Some(found) = failed_pred.skip_binder().term.ty()
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index eedf459ce8f..b10aaad5f2a 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -177,15 +177,55 @@ fn resolve_associated_item<'tcx>(
 
             Some(ty::Instance::new(leaf_def.item.def_id, substs))
         }
-        traits::ImplSource::Generator(generator_data) => Some(Instance {
-            def: ty::InstanceDef::Item(generator_data.generator_def_id),
-            substs: generator_data.substs,
-        }),
-        traits::ImplSource::Future(future_data) => Some(Instance {
-            def: ty::InstanceDef::Item(future_data.generator_def_id),
-            substs: future_data.substs,
-        }),
+        traits::ImplSource::Generator(generator_data) => {
+            if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
+                // For compiler developers who'd like to add new items to `Generator`,
+                // you either need to generate a shim body, or perhaps return
+                // `InstanceDef::Item` pointing to a trait default method body if
+                // it is given a default implementation by the trait.
+                span_bug!(
+                    tcx.def_span(generator_data.generator_def_id),
+                    "no definition for `{trait_ref}::{}` for built-in generator type",
+                    tcx.item_name(trait_item_id)
+                )
+            }
+            Some(Instance {
+                def: ty::InstanceDef::Item(generator_data.generator_def_id),
+                substs: generator_data.substs,
+            })
+        }
+        traits::ImplSource::Future(future_data) => {
+            if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::poll {
+                // For compiler developers who'd like to add new items to `Future`,
+                // you either need to generate a shim body, or perhaps return
+                // `InstanceDef::Item` pointing to a trait default method body if
+                // it is given a default implementation by the trait.
+                span_bug!(
+                    tcx.def_span(future_data.generator_def_id),
+                    "no definition for `{trait_ref}::{}` for built-in async generator type",
+                    tcx.item_name(trait_item_id)
+                )
+            }
+            Some(Instance {
+                def: ty::InstanceDef::Item(future_data.generator_def_id),
+                substs: future_data.substs,
+            })
+        }
         traits::ImplSource::Closure(closure_data) => {
+            if cfg!(debug_assertions)
+                && ![sym::call, sym::call_mut, sym::call_once]
+                    .contains(&tcx.item_name(trait_item_id))
+            {
+                // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
+                // you either need to generate a shim body, or perhaps return
+                // `InstanceDef::Item` pointing to a trait default method body if
+                // it is given a default implementation by the trait.
+                span_bug!(
+                    tcx.def_span(closure_data.closure_def_id),
+                    "no definition for `{trait_ref}::{}` for built-in closure type",
+                    tcx.item_name(trait_item_id)
+                )
+            }
             let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
             Instance::resolve_closure(
                 tcx,
@@ -195,11 +235,29 @@ fn resolve_associated_item<'tcx>(
             )
         }
         traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
-            ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
-                def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
-                substs: rcvr_substs,
-            }),
-            _ => None,
+            ty::FnDef(..) | ty::FnPtr(..) => {
+                if cfg!(debug_assertions)
+                    && ![sym::call, sym::call_mut, sym::call_once]
+                        .contains(&tcx.item_name(trait_item_id))
+                {
+                    // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
+                    // you either need to generate a shim body, or perhaps return
+                    // `InstanceDef::Item` pointing to a trait default method body if
+                    // it is given a default implementation by the trait.
+                    bug!(
+                        "no definition for `{trait_ref}::{}` for built-in fn type",
+                        tcx.item_name(trait_item_id)
+                    )
+                }
+                Some(Instance {
+                    def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
+                    substs: rcvr_substs,
+                })
+            }
+            _ => bug!(
+                "no built-in definition for `{trait_ref}::{}` for non-fn type",
+                tcx.item_name(trait_item_id)
+            ),
         },
         traits::ImplSource::Object(ref data) => {
             traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index ed513cb3c7f..c4a4cda6801 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty::{
 };
 use rustc_target::abi::*;
 
-use std::cmp;
+use std::assert_matches::assert_matches;
 
 /// Enforce some basic invariants on layouts.
 pub(super) fn sanity_check_layout<'tcx>(
@@ -68,21 +68,31 @@ pub(super) fn sanity_check_layout<'tcx>(
     }
 
     fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) {
+        // Verify the ABI mandated alignment and size.
+        let align = layout.abi.inherent_align(cx).map(|align| align.abi);
+        let size = layout.abi.inherent_size(cx);
+        let Some((align, size)) = align.zip(size) else {
+            assert_matches!(
+                layout.layout.abi(),
+                Abi::Uninhabited | Abi::Aggregate { .. },
+                "ABI unexpectedly missing alignment and/or size in {layout:#?}"
+            );
+            return
+        };
+        assert_eq!(
+            layout.layout.align().abi,
+            align,
+            "alignment mismatch between ABI and layout in {layout:#?}"
+        );
+        assert_eq!(
+            layout.layout.size(),
+            size,
+            "size mismatch between ABI and layout in {layout:#?}"
+        );
+
+        // Verify per-ABI invariants
         match layout.layout.abi() {
-            Abi::Scalar(scalar) => {
-                // No padding in scalars.
-                let size = scalar.size(cx);
-                let align = scalar.align(cx).abi;
-                assert_eq!(
-                    layout.layout.size(),
-                    size,
-                    "size mismatch between ABI and layout in {layout:#?}"
-                );
-                assert_eq!(
-                    layout.layout.align().abi,
-                    align,
-                    "alignment mismatch between ABI and layout in {layout:#?}"
-                );
+            Abi::Scalar(_) => {
                 // Check that this matches the underlying field.
                 let inner = skip_newtypes(cx, layout);
                 assert!(
@@ -135,24 +145,6 @@ pub(super) fn sanity_check_layout<'tcx>(
                 }
             }
             Abi::ScalarPair(scalar1, scalar2) => {
-                // Sanity-check scalar pairs. Computing the expected size and alignment is a bit of work.
-                let size1 = scalar1.size(cx);
-                let align1 = scalar1.align(cx).abi;
-                let size2 = scalar2.size(cx);
-                let align2 = scalar2.align(cx).abi;
-                let align = cmp::max(align1, align2);
-                let field2_offset = size1.align_to(align2);
-                let size = (field2_offset + size2).align_to(align);
-                assert_eq!(
-                    layout.layout.size(),
-                    size,
-                    "size mismatch between ABI and layout in {layout:#?}"
-                );
-                assert_eq!(
-                    layout.layout.align().abi,
-                    align,
-                    "alignment mismatch between ABI and layout in {layout:#?}",
-                );
                 // Check that the underlying pair of fields matches.
                 let inner = skip_newtypes(cx, layout);
                 assert!(
@@ -189,8 +181,9 @@ pub(super) fn sanity_check_layout<'tcx>(
                         "`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}"
                     )
                 });
-                assert!(
-                    fields.next().is_none(),
+                assert_matches!(
+                    fields.next(),
+                    None,
                     "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
                 );
                 // The fields might be in opposite order.
@@ -200,6 +193,10 @@ pub(super) fn sanity_check_layout<'tcx>(
                     (offset2, field2, offset1, field1)
                 };
                 // The fields should be at the right offset, and match the `scalar` layout.
+                let size1 = scalar1.size(cx);
+                let align1 = scalar1.align(cx).abi;
+                let size2 = scalar2.size(cx);
+                let align2 = scalar2.align(cx).abi;
                 assert_eq!(
                     offset1,
                     Size::ZERO,
@@ -213,10 +210,12 @@ pub(super) fn sanity_check_layout<'tcx>(
                     field1.align.abi, align1,
                     "`ScalarPair` first field with bad align in {inner:#?}",
                 );
-                assert!(
-                    matches!(field1.abi, Abi::Scalar(_)),
+                assert_matches!(
+                    field1.abi,
+                    Abi::Scalar(_),
                     "`ScalarPair` first field with bad ABI in {inner:#?}",
                 );
+                let field2_offset = size1.align_to(align2);
                 assert_eq!(
                     offset2, field2_offset,
                     "`ScalarPair` second field at bad offset in {inner:#?}",
@@ -229,27 +228,14 @@ pub(super) fn sanity_check_layout<'tcx>(
                     field2.align.abi, align2,
                     "`ScalarPair` second field with bad align in {inner:#?}",
                 );
-                assert!(
-                    matches!(field2.abi, Abi::Scalar(_)),
+                assert_matches!(
+                    field2.abi,
+                    Abi::Scalar(_),
                     "`ScalarPair` second field with bad ABI in {inner:#?}",
                 );
             }
-            Abi::Vector { count, element } => {
-                // No padding in vectors, except possibly for trailing padding to make the size a multiple of align.
-                let size = element.size(cx) * count;
-                let align = cx.data_layout().vector_align(size).abi;
-                let size = size.align_to(align); // needed e.g. for vectors of size 3
+            Abi::Vector { element, .. } => {
                 assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
-                assert_eq!(
-                    layout.layout.size(),
-                    size,
-                    "size mismatch between ABI and layout in {layout:#?}"
-                );
-                assert_eq!(
-                    layout.layout.align().abi,
-                    align,
-                    "alignment mismatch between ABI and layout in {layout:#?}"
-                );
                 // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
             }
             Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 9d5a72a73cd..73a2f6af579 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,6 +5,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(assert_matches)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
 #![feature(never_type)]
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index efbbc1c2331..2daef82d6f1 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -3079,8 +3079,8 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> {
                 unsafe { self.root.reborrow() }
                     .as_mut()?
                     .borrow_mut()
-                    .first_leaf_edge()
-                    .next_kv()
+                    .last_leaf_edge()
+                    .next_back_kv()
                     .ok()?
                     .into_kv_valmut()
             }
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index da00d83bdbb..7ecffe3eef2 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -8,6 +8,7 @@ use crate::testing::crash_test::{CrashTestDummy, Panic};
 use crate::testing::ord_chaos::{Cyclic3, Governed, Governor};
 use crate::testing::rng::DeterministicRng;
 use crate::vec::Vec;
+use core::assert_matches::assert_matches;
 use std::cmp::Ordering;
 use std::iter;
 use std::mem;
@@ -2448,3 +2449,21 @@ fn test_cursor_mut_insert_after_4() {
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
     cur.insert_after(4, 'd');
 }
+
+#[test]
+fn cursor_peek_prev_agrees_with_cursor_mut() {
+    let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]);
+
+    let cursor = map.lower_bound(Bound::Excluded(&3));
+    assert!(cursor.key().is_none());
+
+    let prev = cursor.peek_prev();
+    assert_matches!(prev, Some((&3, _)));
+
+    // Shadow names so the two parts of this test match.
+    let mut cursor = map.lower_bound_mut(Bound::Excluded(&3));
+    assert!(cursor.key().is_none());
+
+    let prev = cursor.peek_prev();
+    assert_matches!(prev, Some((&3, _)));
+}
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index bd2b2c36c43..07b11814f96 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -79,9 +79,9 @@ use crate::str;
 ///
 /// [str]: prim@str "str"
 #[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
 #[stable(feature = "core_c_str", since = "1.64.0")]
 #[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), lang = "CStr")]
 // FIXME:
 // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
 // on `CStr` being layout-compatible with `[u8]`.
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 520ec9abcf0..2568aaf34f3 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -310,6 +310,7 @@ where
 /// Real logic of both `Flatten` and `FlatMap` which simply delegate to
 /// this type.
 #[derive(Clone, Debug)]
+#[unstable(feature = "trusted_len", issue = "37572")]
 struct FlattenCompat<I, U> {
     iter: Fuse<I>,
     frontiter: Option<U>,
@@ -463,6 +464,7 @@ where
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 impl<I, U> Iterator for FlattenCompat<I, U>
 where
     I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -577,6 +579,7 @@ where
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
 where
     I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -646,6 +649,7 @@ where
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter>
 where
@@ -653,6 +657,7 @@ where
 {
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter>
 where
@@ -660,6 +665,7 @@ where
 {
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter>
 where
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index a535a011aaf..ed0c05a6863 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -107,6 +107,7 @@
 #![feature(const_arguments_as_str)]
 #![feature(const_array_from_ref)]
 #![feature(const_array_into_iter_constructors)]
+#![feature(const_assume)]
 #![feature(const_bigint_helper_methods)]
 #![feature(const_black_box)]
 #![feature(const_caller_location)]
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 5f55f762ad5..4737ff5d756 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1632,8 +1632,8 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
     // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
     // 1, where the method versions of these operations are not inlined.
     use intrinsics::{
-        cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl, unchecked_shr,
-        unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
+        assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl,
+        unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub,
     };
 
     /// Calculate multiplicative modular inverse of `x` modulo `m`.
@@ -1724,12 +1724,18 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
         // in a branch-free way and then bitwise-OR it with whatever result the `-p mod a`
         // computation produces.
 
+        let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a);
+        let byte_offset = wrapping_sub(aligned_address, addr);
+        // FIXME: Remove the assume after <https://github.com/llvm/llvm-project/issues/62502>
+        // SAFETY: Masking by `-a` can only affect the low bits, and thus cannot have reduced
+        // the value by more than `a-1`, so even though the intermediate values might have
+        // wrapped, the byte_offset is always in `[0, a)`.
+        unsafe { assume(byte_offset < a) };
+
         // SAFETY: `stride == 0` case has been handled by the special case above.
         let addr_mod_stride = unsafe { unchecked_rem(addr, stride) };
 
         return if addr_mod_stride == 0 {
-            let aligned_address = wrapping_add(addr, a_minus_one) & wrapping_sub(0, a);
-            let byte_offset = wrapping_sub(aligned_address, addr);
             // SAFETY: `stride` is non-zero. This is guaranteed to divide exactly as well, because
             // addr has been verified to be aligned to the original type’s alignment requirements.
             unsafe { exact_div(byte_offset, stride) }
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index c46c49547f6..2a8403c85a4 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -101,7 +101,7 @@ macro_rules! tuple_impls {
             }
         }
 
-        #[stable(feature = "array_tuple_conv", since = "1.63.0")]
+        #[stable(feature = "array_tuple_conv", since = "CURRENT_RUSTC_VERSION")]
         impl<T> From<[T; ${count(T)}]> for ($(${ignore(T)} T,)+) {
             #[inline]
             #[allow(non_snake_case)]
@@ -111,7 +111,7 @@ macro_rules! tuple_impls {
             }
         }
 
-        #[stable(feature = "array_tuple_conv", since = "1.63.0")]
+        #[stable(feature = "array_tuple_conv", since = "CURRENT_RUSTC_VERSION")]
         impl<T> From<($(${ignore(T)} T,)+)> for [T; ${count(T)}] {
             #[inline]
             #[allow(non_snake_case)]
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 54b11c543f1..caecda1bc63 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -337,6 +337,8 @@ pub enum LitKind {
     StrRaw(u8),
     ByteStr,
     ByteStrRaw(u8),
+    CStr,
+    CStrRaw(u8),
     Err,
 }
 
@@ -350,6 +352,8 @@ rpc_encode_decode!(
         StrRaw(n),
         ByteStr,
         ByteStrRaw(n),
+        CStr,
+        CStrRaw(n),
         Err,
     }
 );
diff --git a/library/std/src/sys/common/thread_local/mod.rs b/library/std/src/sys/common/thread_local/mod.rs
index 951d509ec95..77f64588310 100644
--- a/library/std/src/sys/common/thread_local/mod.rs
+++ b/library/std/src/sys/common/thread_local/mod.rs
@@ -1,5 +1,10 @@
 #![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
 
+// There are three thread-local implementations: "static", "fast", "OS".
+// The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the
+// "fast" key type is accessed via code generated via LLVM, where TLS keys are set up by the linker.
+// "static" is for single-threaded platforms where a global static is sufficient.
+
 cfg_if::cfg_if! {
     if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
         #[doc(hidden)]
diff --git a/library/std/src/sys/common/thread_local/os_local.rs b/library/std/src/sys/common/thread_local/os_local.rs
index d004897df28..5d48ce1e03b 100644
--- a/library/std/src/sys/common/thread_local/os_local.rs
+++ b/library/std/src/sys/common/thread_local/os_local.rs
@@ -18,7 +18,7 @@ pub macro thread_local_inner {
         ) -> $crate::option::Option<&'static $t> {
             const INIT_EXPR: $t = $init;
 
-                        // On platforms without `#[thread_local]` we fall back to the
+            // On platforms without `#[thread_local]` we fall back to the
             // same implementation as below for os thread locals.
             #[inline]
             const fn __init() -> $t { INIT_EXPR }
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index 32ddc4346ee..5440d85df4a 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -40,11 +40,7 @@ impl Timespec {
     }
 
     fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+        let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
@@ -57,11 +53,7 @@ impl Timespec {
     }
 
     fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+        let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
         let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
diff --git a/library/std/src/sys/sgx/abi/entry.S b/library/std/src/sys/sgx/abi/entry.S
index ca79d1d796e..8a063b65dac 100644
--- a/library/std/src/sys/sgx/abi/entry.S
+++ b/library/std/src/sys/sgx/abi/entry.S
@@ -26,7 +26,7 @@ IMAGE_BASE:
 .Lxsave_clear:
 .org .+24
 .Lxsave_mxcsr:
-    .short 0x1f80
+    .short 0x1fbf
 
 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
 
@@ -178,6 +178,7 @@ sgx_entry:
     mov $-1, %rax
     mov $-1, %rdx
     xrstor .Lxsave_clear(%rip)
+    lfence
     mov %r10, %rdx
 
 /*  check if returning from usercall */
@@ -311,6 +312,9 @@ usercall:
     movq $0,%gs:tcsls_last_rsp
 /*  restore callee-saved state, cf. "save" above */
     mov %r11,%rsp
+    /* MCDT mitigation requires an lfence after ldmxcsr _before_ any of the affected  */
+    /* vector instructions is used. We omit the lfence here as one is required before */
+    /* the jmp instruction anyway. */
     ldmxcsr (%rsp)
     fldcw 4(%rsp)
     add $8, %rsp
diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs
index ce31cb45a69..f83f1644fe8 100644
--- a/library/std/src/sys/solid/time.rs
+++ b/library/std/src/sys/solid/time.rs
@@ -47,10 +47,10 @@ impl SystemTime {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?))
+        Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?))
+        Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
     }
 }
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 15070b1f6a7..7307d9b2c86 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -326,6 +326,25 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
         } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
             use crate::ptr;
 
+            #[cfg(target_os = "freebsd")]
+            {
+                let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
+                unsafe {
+                    if libc::cpuset_getaffinity(
+                        libc::CPU_LEVEL_WHICH,
+                        libc::CPU_WHICH_PID,
+                        -1,
+                        mem::size_of::<libc::cpuset_t>(),
+                        &mut set,
+                    ) == 0 {
+                        let count = libc::CPU_COUNT(&set) as usize;
+                        if count > 0 {
+                            return Ok(NonZeroUsize::new_unchecked(count));
+                        }
+                    }
+                }
+            }
+
             let mut cpus: libc::c_uint = 0;
             let mut cpus_size = crate::mem::size_of_val(&cpus);
 
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index a61d926ca8b..a9fbc7ab108 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -113,11 +113,7 @@ impl Timespec {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `i64`
-            .ok()
-            .and_then(|secs| self.tv_sec.checked_add(secs))?;
+        let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
@@ -126,15 +122,11 @@ impl Timespec {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(Timespec::new(secs, nsec as i64))
+        Some(Timespec::new(secs, nsec.into()))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `i64`
-            .ok()
-            .and_then(|secs| self.tv_sec.checked_sub(secs))?;
+        let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
         let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32;
@@ -142,7 +134,7 @@ impl Timespec {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(Timespec::new(secs, nsec as i64))
+        Some(Timespec::new(secs, nsec.into()))
     }
 
     #[allow(dead_code)]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 9cdc17a287c..f712c872708 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -193,22 +193,22 @@ pub use scoped::{scope, Scope, ScopedJoinHandle};
 #[macro_use]
 mod local;
 
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::local::{AccessError, LocalKey};
-
-// Provide the type used by the thread_local! macro to access TLS keys. This
-// needs to be kept in sync with the macro itself (in `local.rs`).
-// There are three types: "static", "fast", "OS". The "OS" thread local key
-// type is accessed via platform-specific API calls and is slow, while the "fast"
-// key type is accessed via code generated via LLVM, where TLS keys are set up
-// by the elf linker. "static" is for single-threaded platforms where a global
-// static is sufficient.
-
-// Implementation details used by the thread_local!{} macro.
-#[doc(hidden)]
-#[unstable(feature = "thread_local_internals", issue = "none")]
-pub mod local_impl {
-    pub use crate::sys::common::thread_local::{thread_local_inner, Key};
+cfg_if::cfg_if! {
+    if #[cfg(test)] {
+        // Avoid duplicating the global state assoicated with thread-locals between this crate and
+        // realstd. Miri relies on this.
+        pub use realstd::thread::{local_impl, AccessError, LocalKey};
+    } else {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub use self::local::{AccessError, LocalKey};
+
+        // Implementation details used by the thread_local!{} macro.
+        #[doc(hidden)]
+        #[unstable(feature = "thread_local_internals", issue = "none")]
+        pub mod local_impl {
+            pub use crate::sys::common::thread_local::{thread_local_inner, Key};
+        }
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 2e64ae59aff..6ed84806e6d 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -1,4 +1,5 @@
 use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
+use core::fmt::Debug;
 #[cfg(not(target_arch = "wasm32"))]
 use test::{black_box, Bencher};
 
@@ -201,6 +202,32 @@ fn since_epoch() {
     assert!(a < hundred_twenty_years);
 }
 
+#[test]
+fn big_math() {
+    // Check that the same result occurs when adding/subtracting each duration one at a time as when
+    // adding/subtracting them all at once.
+    #[track_caller]
+    fn check<T: Eq + Copy + Debug>(start: Option<T>, op: impl Fn(&T, Duration) -> Option<T>) {
+        const DURATIONS: [Duration; 2] =
+            [Duration::from_secs(i64::MAX as _), Duration::from_secs(50)];
+        if let Some(start) = start {
+            assert_eq!(
+                op(&start, DURATIONS.into_iter().sum()),
+                DURATIONS.into_iter().try_fold(start, |t, d| op(&t, d))
+            )
+        }
+    }
+
+    check(SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(100)), SystemTime::checked_add);
+    check(SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(100)), SystemTime::checked_sub);
+
+    let instant = Instant::now();
+    check(instant.checked_sub(Duration::from_secs(100)), Instant::checked_add);
+    check(instant.checked_sub(Duration::from_secs(i64::MAX as _)), Instant::checked_add);
+    check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub);
+    check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub);
+}
+
 macro_rules! bench_instant_threaded {
     ($bench_name:ident, $thread_count:expr) => {
         #[bench]
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 8c49055fce7..f4e97d7dfed 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -1459,6 +1459,28 @@ impl Config {
         git
     }
 
+    pub(crate) fn test_args(&self) -> Vec<&str> {
+        let mut test_args = match self.cmd {
+            Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
+                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
+            }
+            _ => vec![],
+        };
+        test_args.extend(self.free_args.iter().map(|s| s.as_str()));
+        test_args
+    }
+
+    pub(crate) fn args(&self) -> Vec<&str> {
+        let mut args = match self.cmd {
+            Subcommand::Run { ref args, .. } => {
+                args.iter().flat_map(|s| s.split_whitespace()).collect()
+            }
+            _ => vec![],
+        };
+        args.extend(self.free_args.iter().map(|s| s.as_str()));
+        args
+    }
+
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
     /// Return the version it would have used for the given commit.
     pub(crate) fn artifact_version_part(&self, commit: &str) -> String {
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index ab7f7350d5f..9cead7adc8c 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -822,6 +822,8 @@ fn copy_src_dirs(
             "llvm-project\\compiler-rt",
             "llvm-project/cmake",
             "llvm-project\\cmake",
+            "llvm-project/runtimes",
+            "llvm-project\\runtimes",
         ];
         if spath.contains("llvm-project")
             && !spath.ends_with("llvm-project")
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 6d1eb011fc4..c79a1bf9563 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -430,15 +430,6 @@ impl Subcommand {
         }
     }
 
-    pub fn test_args(&self) -> Vec<&str> {
-        match *self {
-            Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
-                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
-            }
-            _ => vec![],
-        }
-    }
-
     pub fn rustc_args(&self) -> Vec<&str> {
         match *self {
             Subcommand::Test { ref rustc_args, .. } => {
@@ -448,15 +439,6 @@ impl Subcommand {
         }
     }
 
-    pub fn args(&self) -> Vec<&str> {
-        match *self {
-            Subcommand::Run { ref args, .. } => {
-                args.iter().flat_map(|s| s.split_whitespace()).collect()
-            }
-            _ => vec![],
-        }
-    }
-
     pub fn fail_fast(&self) -> bool {
         match *self {
             Subcommand::Test { no_fail_fast, .. } => !no_fail_fast,
diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs
index e14440f57a8..cb15d9a6325 100644
--- a/src/bootstrap/run.rs
+++ b/src/bootstrap/run.rs
@@ -105,7 +105,7 @@ impl Step for BumpStage0 {
 
     fn run(self, builder: &Builder<'_>) -> Self::Output {
         let mut cmd = builder.tool_cmd(Tool::BumpStage0);
-        cmd.args(builder.config.cmd.args());
+        cmd.args(builder.config.args());
         builder.run(&mut cmd);
     }
 }
@@ -182,8 +182,7 @@ impl Step for Miri {
         miri.add_rustc_lib_path(builder, compiler);
         // Forward arguments.
         miri.arg("--").arg("--target").arg(target.rustc_target_arg());
-        miri.args(builder.config.cmd.args());
-        miri.args(&builder.config.free_args);
+        miri.args(builder.config.args());
 
         // miri tests need to know about the stage sysroot
         miri.env("MIRI_SYSROOT", &miri_sysroot);
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 7ff3a8e5769..854b7f5bd3a 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -263,7 +263,7 @@ impl Step for Cargotest {
             builder,
             cmd.arg(&cargo)
                 .arg(&out_dir)
-                .args(builder.config.cmd.test_args())
+                .args(builder.config.test_args())
                 .env("RUSTC", builder.rustc(compiler))
                 .env("RUSTDOC", builder.rustdoc(compiler)),
         );
@@ -634,7 +634,7 @@ impl Step for Miri {
             .arg(builder.src.join("src/tools/miri/test-cargo-miri/Cargo.toml"));
         cargo.arg("--target").arg(target.rustc_target_arg());
         cargo.arg("--tests"); // don't run doctests, they are too confused by the staging
-        cargo.arg("--").args(builder.config.cmd.test_args());
+        cargo.arg("--").args(builder.config.test_args());
 
         // Tell `cargo miri` where to find things.
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
@@ -1060,7 +1060,7 @@ impl Step for RustdocGUI {
                 }
             }
         }
-        for test_arg in builder.config.cmd.test_args() {
+        for test_arg in builder.config.test_args() {
             command.arg(test_arg);
         }
         builder.run(&mut command);
@@ -1555,8 +1555,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             .filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
             .collect();
 
-        test_args.append(&mut builder.config.cmd.test_args());
-        test_args.extend(builder.config.free_args.iter().map(|s| s.as_str()));
+        test_args.append(&mut builder.config.test_args());
 
         // On Windows, replace forward slashes in test-args by backslashes
         // so the correct filters are passed to libtest
@@ -1962,7 +1961,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
     cmd.arg(markdown);
     cmd.env("RUSTC_BOOTSTRAP", "1");
 
-    let test_args = builder.config.cmd.test_args().join(" ");
+    let test_args = builder.config.test_args().join(" ");
     cmd.arg("--test-args").arg(test_args);
 
     if builder.config.verbose_tests {
@@ -2099,7 +2098,7 @@ fn prepare_cargo_test(
         cargo.arg("-p").arg(krate);
     }
 
-    cargo.arg("--").args(&builder.config.cmd.test_args()).args(libtest_args);
+    cargo.arg("--").args(&builder.config.test_args()).args(libtest_args);
     if !builder.config.verbose_tests {
         cargo.arg("--quiet");
     }
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
index 9a1b3e3641a..3ac5343aa57 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
@@ -8,7 +8,6 @@ RUN sh /scripts/crosstool-ng.sh
 
 WORKDIR /build
 
-COPY scripts/musl-patch-configure.diff /build/
 COPY scripts/musl-toolchain.sh /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
index 13eaf7fce8c..6f04dcad9a5 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
@@ -25,7 +25,6 @@ WORKDIR /build/
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-COPY scripts/musl-patch-configure.diff /build/
 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" \
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 62e3f627ec0..1dc7b798724 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -33,7 +33,6 @@ RUN curl -sL --output ovmf-ia32.deb http://mirrors.kernel.org/ubuntu/pool/univer
 RUN dpkg -i ovmf-ia32.deb && rm ovmf-ia32.deb
 
 WORKDIR /build/
-COPY scripts/musl-patch-configure.diff /build/
 COPY scripts/musl-toolchain.sh /build/
 RUN bash musl-toolchain.sh x86_64 && rm -rf build
 WORKDIR /
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 69d4916e5a9..8bea8cd4c87 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -169,6 +169,7 @@ if [ "$SCCACHE_BUCKET" != "" ]; then
     args="$args --env SCCACHE_REGION"
     args="$args --env AWS_ACCESS_KEY_ID"
     args="$args --env AWS_SECRET_ACCESS_KEY"
+    args="$args --env AWS_REGION"
 else
     mkdir -p $HOME/.cache/sccache
     args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh
index e358b8139d7..bc1b30e2d31 100644
--- a/src/ci/docker/scripts/musl-toolchain.sh
+++ b/src/ci/docker/scripts/musl-toolchain.sh
@@ -4,7 +4,7 @@
 #
 # Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and
 # musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions.
-# Right now we have: Binutils 2.31.1, GCC 9.2.0, musl 1.1.24.
+# Right now we have: Binutils 2.31.1, GCC 9.2.0, musl 1.2.3.
 
 # ignore-tidy-linelength
 
@@ -32,6 +32,7 @@ TARGET=$ARCH-linux-musl
 
 # Don't depend on the mirrors of sabotage linux that musl-cross-make uses.
 LINUX_HEADERS_SITE=https://ci-mirrors.rust-lang.org/rustc/sabotage-linux-tarballs
+LINUX_VER=headers-4.19.88
 
 OUTPUT=/usr/local
 shift
@@ -44,18 +45,11 @@ export CFLAGS="-fPIC -g1 $CFLAGS"
 
 git clone https://github.com/richfelker/musl-cross-make # -b v0.9.9
 cd musl-cross-make
-# A few commits ahead of v0.9.9 to include the cowpatch fix:
-git checkout a54eb56f33f255dfca60be045f12a5cfaf5a72a9
+# A version that includes support for building musl 1.2.3
+git checkout fe915821b652a7fa37b34a596f47d8e20bc72338
 
-# Fix the cfi detection script in musl's configure so cfi is generated
-# when debug info is asked for. This patch is derived from
-# https://git.musl-libc.org/cgit/musl/commit/?id=c4d4028dde90562f631edf559fbc42d8ec1b29de.
-# When we upgrade to a version that includes this commit, we can remove the patch.
-mkdir patches/musl-1.1.24
-cp ../musl-patch-configure.diff patches/musl-1.1.24/0001-fix-cfi-detection.diff
-
-hide_output make -j$(nproc) TARGET=$TARGET MUSL_VER=1.1.24 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE
-hide_output make install TARGET=$TARGET MUSL_VER=1.1.24 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE OUTPUT=$OUTPUT
+hide_output make -j$(nproc) TARGET=$TARGET MUSL_VER=1.2.3 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE LINUX_VER=$LINUX_VER
+hide_output make install TARGET=$TARGET MUSL_VER=1.2.3 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE LINUX_VER=$LINUX_VER OUTPUT=$OUTPUT
 
 cd -
 
diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh
index 3e5dc4af04a..ece8e6c15c0 100644
--- a/src/ci/docker/scripts/musl.sh
+++ b/src/ci/docker/scripts/musl.sh
@@ -25,7 +25,7 @@ shift
 # Apparently applying `-fPIC` everywhere allows them to link successfully.
 export CFLAGS="-fPIC $CFLAGS"
 
-MUSL=musl-1.1.24
+MUSL=musl-1.2.3
 
 # may have been downloaded in a previous run
 if [ ! -d $MUSL ]; then
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 5661adf6776..7f2d34f8098 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -53,6 +53,7 @@ x--expand-yaml-anchors--remove:
     # (caches, artifacts...).
     CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
     ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+    AWS_REGION: us-west-1
     CACHE_DOMAIN: ci-caches.rust-lang.org
 
   - &dummy-variables
@@ -68,6 +69,7 @@ x--expand-yaml-anchors--remove:
     # (caches, artifacts...).
     CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
     ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
+    AWS_REGION: us-west-1
     CACHE_DOMAIN: ci-caches-gha.rust-lang.org
 
   - &base-job
@@ -158,10 +160,6 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/dump-environment.sh
         <<: *step
 
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        <<: *step
-
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         <<: *step
diff --git a/src/ci/scripts/install-awscli.sh b/src/ci/scripts/install-awscli.sh
deleted file mode 100755
index aa62407eaea..00000000000
--- a/src/ci/scripts/install-awscli.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-# This script downloads and installs awscli from the packages mirrored in our
-# own S3 bucket. This follows the recommendations at:
-#
-#    https://packaging.python.org/guides/index-mirrors-and-caches/#caching-with-pip
-#
-# To create a new mirrored copy you can run the command:
-#
-#    pip wheel awscli
-#
-# Before compressing please make sure all the wheels end with `-none-any.whl`.
-# If that's not the case you'll need to remove the non-cross-platform ones and
-# replace them with the .tar.gz downloaded from https://pypi.org.
-
-set -euo pipefail
-IFS=$'\n\t'
-
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-
-MIRROR="${MIRRORS_BASE}/2023-04-28-awscli.tar"
-DEPS_DIR="/tmp/awscli-deps"
-
-pip="pip"
-pipflags=""
-if isLinux; then
-    pip="pip3"
-    pipflags="--user"
-
-    sudo apt-get install -y python3-setuptools python3-wheel
-    ciCommandAddPath "${HOME}/.local/bin"
-elif isMacOS; then
-    pip="pip3"
-fi
-
-mkdir -p "${DEPS_DIR}"
-curl "${MIRROR}" | tar xf - -C "${DEPS_DIR}"
-"${pip}" install ${pipflags} --no-index "--find-links=${DEPS_DIR}" awscli
-rm -rf "${DEPS_DIR}"
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index d7c6a884fc8..1041d502669 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -90,6 +90,14 @@ It takes one of the following values:
 For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to
 the linker.
 
+## dlltool
+
+On `windows-gnu` targets, this flag controls which dlltool `rustc` invokes to
+generate import libraries when using the [`raw-dylib` link kind](../../reference/items/external-blocks.md#the-link-attribute).
+It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs/binutils/dlltool.html).
+If this flag is not specified, a dlltool executable will be inferred based on
+the host environment and target.
+
 ## embed-bitcode
 
 This flag controls whether or not the compiler embeds LLVM bitcode into object
@@ -574,7 +582,8 @@ change in the future.
 This instructs `rustc` to generate code specifically for a particular processor.
 
 You can run `rustc --print target-cpus` to see the valid options to pass
-here. Each target has a default base CPU. Special values include:
+and the default target CPU for the current buid target.
+Each target has a default base CPU. Special values include:
 
 * `native` can be passed to use the processor of the host machine.
 * `generic` refers to an LLVM target with minimal features but modern tuning.
diff --git a/src/doc/unstable-book/src/language-features/raw-dylib.md b/src/doc/unstable-book/src/language-features/raw-dylib.md
deleted file mode 100644
index 5fd208ae757..00000000000
--- a/src/doc/unstable-book/src/language-features/raw-dylib.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# `raw_dylib`
-
-The tracking issue for this feature is: [#58713]
-
-[#58713]: https://github.com/rust-lang/rust/issues/58713
-
-------------------------
-
-The `raw_dylib` feature allows you to link against the implementations of functions in an `extern`
-block without, on Windows, linking against an import library.
-
-```rust,ignore (partial-example)
-#![feature(raw_dylib)]
-
-#[link(name="library", kind="raw-dylib")]
-extern {
-    fn extern_function(x: i32);
-}
-
-fn main() {
-    unsafe {
-        extern_function(14);
-    }
-}
-```
-
-## Limitations
-
-This feature is unstable for the `x86` architecture, and stable for all other architectures.
-
-This feature is only supported on Windows.
-
-On the `x86` architecture, this feature supports only the `cdecl`, `stdcall`, `system`, `fastcall`, and
-`vectorcall` calling conventions.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 946c85a205f..c94968b4817 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -811,7 +811,9 @@ impl<'src> Classifier<'src> {
                 | LiteralKind::Str { .. }
                 | LiteralKind::ByteStr { .. }
                 | LiteralKind::RawStr { .. }
-                | LiteralKind::RawByteStr { .. } => Class::String,
+                | LiteralKind::RawByteStr { .. }
+                | LiteralKind::CStr { .. }
+                | LiteralKind::RawCStr { .. } => Class::String,
                 // Number literals.
                 LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
             },
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index f5b4a3f5abd..a3be6dd5269 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -391,12 +391,14 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
         clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
             get_index_type_id(type_)
         }
+        // The type parameters are converted to generics in `add_generics_and_bounds_as_types`
+        clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
+        clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
+        // Not supported yet
         clean::BareFunction(_)
         | clean::Generic(_)
         | clean::ImplTrait(_)
         | clean::Tuple(_)
-        | clean::Slice(_)
-        | clean::Array(_, _)
         | clean::QPath { .. }
         | clean::Infer => None,
     }
@@ -563,6 +565,30 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
             }
         }
         insert_ty(res, arg.clone(), ty_generics);
+    } else if let Type::Slice(ref ty) = *arg {
+        let mut ty_generics = Vec::new();
+        add_generics_and_bounds_as_types(
+            self_,
+            generics,
+            &ty,
+            tcx,
+            recurse + 1,
+            &mut ty_generics,
+            cache,
+        );
+        insert_ty(res, arg.clone(), ty_generics);
+    } else if let Type::Array(ref ty, _) = *arg {
+        let mut ty_generics = Vec::new();
+        add_generics_and_bounds_as_types(
+            self_,
+            generics,
+            &ty,
+            tcx,
+            recurse + 1,
+            &mut ty_generics,
+            cache,
+        );
+        insert_ty(res, arg.clone(), ty_generics);
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
         // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 263ce3d93b9..b6eb450d62b 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -156,15 +156,19 @@ pub fn main() {
         }
     }
 
-    rustc_driver::install_ice_hook();
+    rustc_driver::install_ice_hook(
+        "https://github.com/rust-lang/rust/issues/new\
+    ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
+        |_| (),
+    );
 
-    // When using CI artifacts (with `download_stage1 = true`), tracing is unconditionally built
+    // When using CI artifacts with `download-rustc`, tracing is unconditionally built
     // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid
     // this, compile our own version of `tracing` that logs all levels.
     // NOTE: this compiles both versions of tracing unconditionally, because
     // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
-    // - Otherwise, there's no warning that logging is being ignored when `download_stage1 = true`.
-    // NOTE: The reason this doesn't show double logging when `download_stage1 = false` and
+    // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
+    // NOTE: The reason this doesn't show double logging when `download-rustc = false` and
     // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
     // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
     init_logging();
@@ -172,7 +176,11 @@ pub fn main() {
 
     let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
         Some(args) => main_args(&args),
-        _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()),
+        _ =>
+        {
+            #[allow(deprecated)]
+            Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+        }
     });
     process::exit(exit_code);
 }
@@ -725,6 +733,7 @@ fn main_args(at_args: &[String]) -> MainResult {
             return if code == 0 {
                 Ok(())
             } else {
+                #[allow(deprecated)]
                 Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
             };
         }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject ac84010322a31f4a581dafe26258aa4ac8dea9c
+Subproject 569b648b5831ae8a515e90c80843a5287c3304e
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 116058b7c75..0bc2f49f5e9 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -36,6 +36,12 @@ jobs:
     - name: Check *.md files
       run: git ls-files -z '*.md' | xargs -0 -n 1 -I {} ./node_modules/.bin/remark {} -u lint -f > /dev/null
 
+    - name: Linkcheck book
+      run: |
+        rustup toolchain install nightly --component rust-docs
+        curl https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh -o linkcheck.sh
+        sh linkcheck.sh clippy --path ./book
+        
     - name: Build mdbook
       run: mdbook build book
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d7102d2474e..ebf5b58a586 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -44,7 +44,7 @@ Current stable, released 2023-04-20
 
 ### Enhancements
 
-* [`arithmetic_side_effects`]: No longer lints, if safe constant values are used.
+* [`arithmetic_side_effects`]: No longer lints if safe constant values are used.
   [#10310](https://github.com/rust-lang/rust-clippy/pull/10310)
 * [`needless_lifetimes`]: Now works in local macros
   [#10257](https://github.com/rust-lang/rust-clippy/pull/10257)
@@ -60,39 +60,39 @@ Current stable, released 2023-04-20
 
 ### False Positive Fixes
 
-* [`explicit_auto_deref`]: Now considers projections, when determining if auto deref is applicable
+* [`explicit_auto_deref`]: Now considers projections when determining if auto deref is applicable
   [#10386](https://github.com/rust-lang/rust-clippy/pull/10386)
-* [`manual_let_else`]: Now considers side effects of branches, before linting 
+* [`manual_let_else`]: Now considers side effects of branches before linting
   [#10336](https://github.com/rust-lang/rust-clippy/pull/10336)
 * [`uninlined_format_args`]: No longer lints for arguments with generic parameters
   [#10343](https://github.com/rust-lang/rust-clippy/pull/10343)
-* [`needless_lifetimes`]: No longer lints signatures in macros, if the lifetime is a metavariable
+* [`needless_lifetimes`]: No longer lints signatures in macros if the lifetime is a metavariable
   [#10380](https://github.com/rust-lang/rust-clippy/pull/10380)
-* [`len_without_is_empty`]: No longer lints, if `len` as a non-default signature
+* [`len_without_is_empty`]: No longer lints if `len` as a non-default signature
   [#10255](https://github.com/rust-lang/rust-clippy/pull/10255)
-* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes, to reduce false
+* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes to reduce false
   positives
   [#10353](https://github.com/rust-lang/rust-clippy/pull/10353)
 * [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent
   [#10332](https://github.com/rust-lang/rust-clippy/pull/10332)
 * [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint
-  in test functions, if `allow-expect-in-tests` is set
+  in test functions if `allow-expect-in-tests` is set
   [#10391](https://github.com/rust-lang/rust-clippy/pull/10391)
 * [`unnecessary_safety_comment`]: No longer lints code inside macros
   [#10106](https://github.com/rust-lang/rust-clippy/pull/10106)
-* [`never_loop`]: No longer lints, for statements following break statements for outer blocks.
+* [`never_loop`]: No longer lints statements following break statements for outer blocks.
   [#10311](https://github.com/rust-lang/rust-clippy/pull/10311)
 
 ### Suggestion Fixes/Improvements
 
-* [`box_default`]: The suggestion now includes the type for trait objects, when needed
+* [`box_default`]: The suggestion now includes the type for trait objects when needed
   [#10382](https://github.com/rust-lang/rust-clippy/pull/10382)
 * [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint
   [#10038](https://github.com/rust-lang/rust-clippy/pull/10038)
 * [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will
   now show the complete error
   [#10231](https://github.com/rust-lang/rust-clippy/pull/10231)
-* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works, if the base type is borrowed
+* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works if the base type is borrowed
   [#10193](https://github.com/rust-lang/rust-clippy/pull/10193)
 * [`needless_return`]: Now removes all semicolons on the same line
   [#10187](https://github.com/rust-lang/rust-clippy/pull/10187)
@@ -113,7 +113,7 @@ Current stable, released 2023-04-20
 
 ### ICE Fixes
 
-* [`needless_pass_by_value`]: Fixed an ICE, caused by how late bounds were handled
+* [`needless_pass_by_value`]: Fixed an ICE caused by how late bounds were handled
   [#10328](https://github.com/rust-lang/rust-clippy/pull/10328)
 * [`needless_borrow`]: No longer panics on ambiguous projections
   [#10403](https://github.com/rust-lang/rust-clippy/pull/10403)
@@ -4582,6 +4582,7 @@ Released 2018-09-13
 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
+[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs
 [`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty
 [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
 [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
@@ -4797,6 +4798,7 @@ Released 2018-09-13
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
+[`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 [`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
@@ -4864,6 +4866,7 @@ Released 2018-09-13
 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 [`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
+[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign
 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 4db15ddb283..3c72bb62ed1 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 85798e0e80c..6745e15c006 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -91,7 +91,8 @@ cargo clippy
 
 #### Automatically applying Clippy suggestions
 
-Clippy can automatically apply some lint suggestions, just like the compiler.
+Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
+`--all-targets`, so it can fix as much code as it can.
 
 ```terminal
 cargo clippy --fix
diff --git a/src/tools/clippy/book/src/development/lint_passes.md b/src/tools/clippy/book/src/development/lint_passes.md
index 131f6455fde..621fc20972e 100644
--- a/src/tools/clippy/book/src/development/lint_passes.md
+++ b/src/tools/clippy/book/src/development/lint_passes.md
@@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we
 mean when we say `EarlyLintPass` deals with only syntax on the AST level.
 
 Alternatively, think of the `foo_functions` lint we mentioned in
-define new lints chapter.
+define new lints <!-- FIXME: add link --> chapter.
 
 We want the `foo_functions` lint to detect functions with `foo` as their name.
 Writing a lint that only checks for the name of a function means that we only
diff --git a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
index 36d722609f4..285488cec55 100644
--- a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
+++ b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
@@ -139,7 +139,7 @@ whether the pattern matched.
 
 ## Pattern syntax
 
-The following examples demonstate the pattern syntax:
+The following examples demonstrate the pattern syntax:
 
 
 #### Any (`_`)
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index a702226e861..5646c9b1520 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand.
 | [msrv](#msrv) | `None` |
 | [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
 | [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
+| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` |
+| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` |
 | [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
 | [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
 | [type-complexity-threshold](#type-complexity-threshold) | `250` |
@@ -203,6 +205,22 @@ default configuration of Clippy. By default, any configuration will replace the
 * [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
 
 
+### semicolon-inside-block-ignore-singleline
+Whether to lint only if it's multiline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block)
+
+
+### semicolon-outside-block-ignore-multiline
+Whether to lint only if it's singleline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block)
+
+
 ### doc-valid-idents
 The list of words this lint should not consider as identifiers needing ticks. The value
 `".."` can be used as part of the list to indicate, that the configured values should be appended to the
diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md
index 32084a9199b..36448e4cccf 100644
--- a/src/tools/clippy/book/src/usage.md
+++ b/src/tools/clippy/book/src/usage.md
@@ -111,7 +111,8 @@ fn main() {
 
 ### Automatically applying Clippy suggestions
 
-Clippy can automatically apply some lint suggestions, just like the compiler.
+Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
+`--all-targets`, so it can fix as much code as it can.
 
 ```terminal
 cargo clippy --fix
diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs
index b69e9f649ec..a0d57f5ab48 100644
--- a/src/tools/clippy/clippy_dev/src/dogfood.rs
+++ b/src/tools/clippy/clippy_dev/src/dogfood.rs
@@ -1,4 +1,4 @@
-use crate::clippy_project_root;
+use crate::{clippy_project_root, exit_if_err};
 use std::process::Command;
 
 /// # Panics
@@ -10,7 +10,7 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
     cmd.current_dir(clippy_project_root())
         .args(["test", "--test", "dogfood"])
         .args(["--features", "internal"])
-        .args(["--", "dogfood_clippy"]);
+        .args(["--", "dogfood_clippy", "--nocapture"]);
 
     let mut dogfood_args = Vec::new();
     if fix {
@@ -27,7 +27,5 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
 
     cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" "));
 
-    let output = cmd.output().expect("failed to run command");
-
-    println!("{}", String::from_utf8_lossy(&output.stdout));
+    exit_if_err(cmd.status());
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 3a8b070d735..56a269288c0 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -10,7 +10,9 @@
 extern crate rustc_driver;
 extern crate rustc_lexer;
 
+use std::io;
 use std::path::PathBuf;
+use std::process::{self, ExitStatus};
 
 pub mod bless;
 pub mod dogfood;
@@ -58,3 +60,14 @@ pub fn clippy_project_root() -> PathBuf {
     }
     panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
 }
+
+pub fn exit_if_err(status: io::Result<ExitStatus>) {
+    match status.expect("failed to run command").code() {
+        Some(0) => {},
+        Some(n) => process::exit(n),
+        None => {
+            eprintln!("Killed by signal");
+            process::exit(1);
+        },
+    }
+}
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index aafd0f71a59..a19be1bca6c 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -1,17 +1,6 @@
-use crate::cargo_clippy_path;
-use std::process::{self, Command, ExitStatus};
-use std::{fs, io};
-
-fn exit_if_err(status: io::Result<ExitStatus>) {
-    match status.expect("failed to run command").code() {
-        Some(0) => {},
-        Some(n) => process::exit(n),
-        None => {
-            eprintln!("Killed by signal");
-            process::exit(1);
-        },
-    }
-}
+use crate::{cargo_clippy_path, exit_if_err};
+use std::fs;
+use std::process::{self, Command};
 
 pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
     let is_file = match fs::metadata(path) {
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index dd90a38f757..7213c9dfede 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -36,60 +36,6 @@ pub enum UpdateMode {
 pub fn update(update_mode: UpdateMode) {
     let (lints, deprecated_lints, renamed_lints) = gather_all();
     generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
-    remove_old_files(update_mode);
-}
-
-/// Remove files no longer needed after <https://github.com/rust-lang/rust-clippy/pull/9541>
-/// that may be reintroduced unintentionally
-///
-/// FIXME: This is a temporary measure that should be removed when there are no more PRs that
-/// include the stray files
-fn remove_old_files(update_mode: UpdateMode) {
-    let mut failed = false;
-    let mut remove_file = |path: &Path| match update_mode {
-        UpdateMode::Check => {
-            if path.exists() {
-                failed = true;
-                println!("unexpected file: {}", path.display());
-            }
-        },
-        UpdateMode::Change => {
-            if fs::remove_file(path).is_ok() {
-                println!("removed file: {}", path.display());
-            }
-        },
-    };
-
-    let files = [
-        "clippy_lints/src/lib.register_all.rs",
-        "clippy_lints/src/lib.register_cargo.rs",
-        "clippy_lints/src/lib.register_complexity.rs",
-        "clippy_lints/src/lib.register_correctness.rs",
-        "clippy_lints/src/lib.register_internal.rs",
-        "clippy_lints/src/lib.register_lints.rs",
-        "clippy_lints/src/lib.register_nursery.rs",
-        "clippy_lints/src/lib.register_pedantic.rs",
-        "clippy_lints/src/lib.register_perf.rs",
-        "clippy_lints/src/lib.register_restriction.rs",
-        "clippy_lints/src/lib.register_style.rs",
-        "clippy_lints/src/lib.register_suspicious.rs",
-        "src/docs.rs",
-    ];
-
-    for file in files {
-        remove_file(Path::new(file));
-    }
-
-    if let Ok(docs_dir) = fs::read_dir("src/docs") {
-        for doc_file in docs_dir {
-            let path = doc_file.unwrap().path();
-            remove_file(&path);
-        }
-    }
-
-    if failed {
-        exit_with_failure();
-    }
 }
 
 fn generate_lint_files(
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 18e8bf77225..37e1e6a742f 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index b984132acf5..add73d0aeee 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -2,7 +2,8 @@ use ast::AttrStyle;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast as ast;
 use rustc_errors::Applicability;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute {
     // Separate each crate's features.
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
         if_chain! {
+            if !in_external_macro(cx.sess(), attr.span);
             if cx.tcx.features().lint_reasons;
             if let AttrStyle::Outer = attr.style;
             if let Some(ident) = attr.ident();
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d74bd57fe45..cfeb75eed3b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -638,7 +638,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.66.0"]
     pub AS_PTR_CAST_MUT,
     nursery,
-    "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
+    "casting the result of the `&self`-taking `as_ptr` to a mutable pointer"
 }
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 7e23318076c..804ae841100 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -141,9 +141,9 @@ fn lint_unnecessary_cast(
 
 fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
     match expr.kind {
-        ExprKind::Lit(ref lit) => Some(lit),
+        ExprKind::Lit(lit) => Some(lit),
         ExprKind::Unary(UnOp::Neg, e) => {
-            if let ExprKind::Lit(ref lit) = e.kind {
+            if let ExprKind::Lit(lit) = e.kind {
                 Some(lit)
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 970f5004993..1c321f46e2d 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De
         conds,
         |e| hash_expr(cx, e),
         |lhs, rhs| {
-            // Ignore eq_expr side effects iff one of the expressin kind is a method call
+            // Ignore eq_expr side effects iff one of the expression kind is a method call
             // and the caller is not a mutable, including inner mutable type.
             if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
                 if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index fa726a64937..79d0f6f3607 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -105,6 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::dbg_macro::DBG_MACRO_INFO,
     crate::default::DEFAULT_TRAIT_ACCESS_INFO,
     crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
+    crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO,
     crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
     crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
     crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
@@ -249,6 +250,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::loops::MANUAL_FIND_INFO,
     crate::loops::MANUAL_FLATTEN_INFO,
     crate::loops::MANUAL_MEMCPY_INFO,
+    crate::loops::MANUAL_WHILE_LET_SOME_INFO,
     crate::loops::MISSING_SPIN_LOOP_INFO,
     crate::loops::MUT_RANGE_BOUND_INFO,
     crate::loops::NEEDLESS_RANGE_LOOP_INFO,
@@ -445,6 +447,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
     crate::needless_bool::BOOL_COMPARISON_INFO,
     crate::needless_bool::NEEDLESS_BOOL_INFO,
+    crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
     crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
     crate::needless_continue::NEEDLESS_CONTINUE_INFO,
     crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..e529d81a7e9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -0,0 +1,72 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths};
+use hir::{def::Res, ExprKind};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for construction on unit struct using `default`.
+    ///
+    /// ### Why is this bad?
+    /// This adds code complexity and an unnecessary function call.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// #[derive(Default)]
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData::default()
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData
+    /// };
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+    complexity,
+    "unit structs can be contructed without calling `default`"
+}
+declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
+
+impl LateLintPass<'_> for DefaultConstructedUnitStructs {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        if_chain!(
+            // make sure we have a call to `Default::default`
+            if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
+            if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
+            if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
+            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            // make sure we have a struct with no fields (unit struct)
+            if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
+            if def.is_struct();
+            if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
+            if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+                    expr.span.with_lo(qpath.qself_span().hi()),
+                    "use of `default` to create a unit struct",
+                    "remove this call to `default`",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+            }
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 6615f9c9953..a51a8ee09f6 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -92,10 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
                     if trait_item.id.owner_id.def_id == fn_def_id {
                         // be sure we have `self` parameter in this function
                         if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
-                            trait_self_ty = Some(
-                                TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
-                                    .self_ty(),
-                            );
+                            trait_self_ty =
+                                Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
                         }
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 6fee7fb308c..93bf50fd5e7 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
         let ty = cx.typeck_results().expr_ty(expr);
         if_chain! {
             if let ty::Float(fty) = *ty.kind();
-            if let hir::ExprKind::Lit(ref lit) = expr.kind;
+            if let hir::ExprKind::Lit(lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
             then {
                 let sym_str = sym.as_str();
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index f95b628e6c3..a1a2c398a8a 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -2,9 +2,10 @@ use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -677,7 +678,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -703,7 +704,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -730,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // All of these operations are currently not const.
+        // All of these operations are currently not const and are in std.
         if in_constant(cx, expr.hir_id) {
             return;
         }
@@ -738,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
         if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
-            if recv_ty.is_floating_point() {
+            if recv_ty.is_floating_point() && !is_no_std_crate(cx) {
                 match path.ident.name.as_str() {
                     "ln" => check_ln1p(cx, expr, receiver),
                     "log" => check_log_base(cx, expr, receiver, args),
@@ -749,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
                 }
             }
         } else {
-            check_expm1(cx, expr);
-            check_mul_add(cx, expr);
-            check_custom_abs(cx, expr);
-            check_log_division(cx, expr);
+            if !is_no_std_crate(cx) {
+                check_expm1(cx, expr);
+                check_mul_add(cx, expr);
+                check_custom_abs(cx, expr);
+                check_log_division(cx, expr);
+            }
             check_radians(cx, expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index bd66ace4500..10ce2a0f0c7 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
                         );
                     }
 
-                    let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
+                    let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
                     if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
                         diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index e5945939e60..b244b913314 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
     };
 
     // Body must be &(mut) <self_data>.name
-    // self_data is not neccessarilly self, to also lint sub-getters, etc…
+    // self_data is not necessarily self, to also lint sub-getters, etc…
 
     let block_expr = if_chain! {
         if let ExprKind::Block(block,_) = body.value.kind;
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ac2d253fe83..ee10334c67f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -252,6 +252,11 @@ declare_clippy_lint! {
     /// A `Result` is at least as large as the `Err`-variant. While we
     /// expect that variant to be seldomly used, the compiler needs to reserve
     /// and move that much memory every single time.
+    /// Furthermore, errors are often simply passed up the call-stack, making
+    /// use of the `?`-operator and its type-conversion mechanics. If the
+    /// `Err`-variant further up the call-stack stores the `Err`-variant in
+    /// question (as library code often does), it itself needs to be at least
+    /// as large, propagating the problem.
     ///
     /// ### Known problems
     /// The size determined by Clippy is platform-dependent.
@@ -330,7 +335,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints when `impl Trait` is being used in a function's paremeters.
+    /// Lints when `impl Trait` is being used in a function's parameters.
     /// ### Why is this bad?
     /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index 57e6caa8711..012aa5a1d1d 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
             if expr1.span.ctxt() == ctxt;
             if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
             if BinOpKind::Add == op1.node;
-            if let ExprKind::Lit(ref lit) = value.kind;
+            if let ExprKind::Lit(lit) = value.kind;
             if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
             if block.expr.is_none();
             then {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 0c7aea6da8f..1e99b6faa6c 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                 // Get the variable name
                 let var_name = ares_path.segments[0].ident.name.as_str();
                 match cond_num_val.kind {
-                    ExprKind::Lit(ref cond_lit) => {
+                    ExprKind::Lit(cond_lit) => {
                         // Check if the constant is zero
                         if let LitKind::Int(0, _) = cond_lit.node {
                             if cx.typeck_results().expr_ty(cond_left).is_signed() {
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index c384172fbde..924a361c0f6 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
+                    if constant(cx, cx.typeck_results(), index).is_some() {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
index 52d716feea0..b992d689aa9 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
@@ -64,20 +64,21 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
                 span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
             }};
 
-            if matches!(item.kind, ItemKind::Mod(_)) {
-                for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
-                    if_chain! {
-                        if attr.has_name(sym::cfg);
+            if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
+			// Check that it works the same way, the only I way I've found for #10713
+				for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
+					if_chain! {
+						if attr.has_name(sym::cfg);
                         if let Some(mitems) = attr.meta_item_list();
                         if let [mitem] = &*mitems;
                         if mitem.has_name(sym::test);
                         then {
-                            was_test_mod_visited = true;
+							was_test_mod_visited = true;
                             test_mod_span = Some(item.span);
                         }
                     }
                 }
-            }
+			}
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 1b054481371..0ca31033b16 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
     /// It checks for the size of a `Future` created by `async fn` or `async {}`.
     ///
     /// ### Why is this bad?
-    /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
+    /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
     /// large size of a `Future` may cause stack overflows.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index fec9c6f626c..17bd89efaee 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -532,7 +532,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
 }
 
 fn is_empty_string(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(lit, _) = lit.node {
             let lit = lit.as_str();
             return lit.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 637b7de920e..16772a9d598 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -205,8 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     LET_UNDERSCORE_UNTYPED,
                     local.span,
                     "non-binding `let` without a type annotation",
-                    None,
-                    "consider adding a type annotation or removing the `let` keyword",
+                    Some(
+						Span::new(local.pat.span.hi(),
+						local.pat.span.hi() + BytePos(1),
+						local.pat.span.ctxt(),
+						local.pat.span.parent()
+					)),
+                    "consider adding a type annotation",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 9e65f9ecd16..3517842a01e 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -94,6 +94,7 @@ mod crate_in_macro_def;
 mod create_dir;
 mod dbg_macro;
 mod default;
+mod default_constructed_unit_structs;
 mod default_instead_of_iter_empty;
 mod default_numeric_fallback;
 mod default_union_representation;
@@ -933,7 +934,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
-    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
+    let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
+    store.register_late_pass(move |_| {
+        Box::new(semicolon_block::SemicolonBlock::new(
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        ))
+    });
     store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
@@ -963,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
+    store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index c87fc4f90e2..d4c3f76b864 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -15,7 +15,7 @@ use rustc_span::symbol::sym;
 use std::fmt::Display;
 use std::iter::Iterator;
 
-/// Checks for for loops that sequentially copy items from one slice-like
+/// Checks for `for` loops that sequentially copy items from one slice-like
 /// object to another.
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
new file mode 100644
index 00000000000..cb9c84be4c7
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -0,0 +1,110 @@
+use clippy_utils::{
+    diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
+    match_def_path, paths,
+    source::snippet,
+    SpanlessEq,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::borrow::Cow;
+
+use super::MANUAL_WHILE_LET_SOME;
+
+/// The kind of statement that the `pop()` call appeared in.
+///
+/// Depending on whether the value was assigned to a variable or not changes what pattern
+/// we use for the suggestion.
+#[derive(Copy, Clone)]
+enum PopStmt<'hir> {
+    /// `x.pop().unwrap()` was and assigned to a variable.
+    /// The pattern of this local variable will be used and the local statement
+    /// is deleted in the suggestion.
+    Local(&'hir Pat<'hir>),
+    /// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable.
+    /// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression
+    /// is replaced with that identifier.
+    Anonymous,
+}
+
+fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) {
+    span_lint_and_then(
+        cx,
+        MANUAL_WHILE_LET_SOME,
+        pop_span,
+        "you seem to be trying to pop elements from a `Vec` in a loop",
+        |diag| {
+            let (pat, pop_replacement) = match pop_stmt_kind {
+                PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()),
+                PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()),
+            };
+
+            let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
+            multispan_sugg_with_applicability(
+                diag,
+                "consider using a `while..let` loop",
+                Applicability::MachineApplicable,
+                [(loop_span, loop_replacement), (pop_span, pop_replacement)],
+            );
+        },
+    );
+}
+
+fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool {
+    if let ExprKind::MethodCall(..) = expr.kind
+        && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+    {
+        match_def_path(cx, id, method)
+    } else {
+        false
+    }
+}
+
+fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
+    if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT))
+        && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
+        && match_method_call(cx, unwrap_recv, &paths::VEC_POP)
+        && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
+    {
+        // make sure they're the same `Vec`
+        SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv)
+    } else {
+        false
+    }
+}
+
+fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Local(local) = stmt.kind
+        && let Some(init) = local.init
+        && is_vec_pop_unwrap(cx, init, is_empty_recv)
+    {
+        report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span);
+    }
+}
+
+fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind {
+        if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind {
+            let offending_arg = args
+                .iter()
+                .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
+
+            if let Some(offending_arg) = offending_arg {
+                report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
+            }
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
+    if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
+        && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
+        && match_method_call(cx, cond, &paths::VEC_IS_EMPTY)
+        && let ExprKind::Block(body, _) = body.kind
+        && let Some(stmt) = body.stmts.first()
+    {
+        check_local(cx, stmt, is_empty_recv, loop_span);
+        check_call_arguments(cx, stmt, is_empty_recv, loop_span);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 610a0233eee..f83ad388a74 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -7,6 +7,7 @@ mod iter_next_loop;
 mod manual_find;
 mod manual_flatten;
 mod manual_memcpy;
+mod manual_while_let_some;
 mod missing_spin_loop;
 mod mut_range_bound;
 mod needless_range_loop;
@@ -575,6 +576,36 @@ declare_clippy_lint! {
     "manual implementation of `Iterator::find`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
+    /// in the body as a separate operation.
+    ///
+    /// ### Why is this bad?
+    /// Such loops can be written in a more idiomatic way by using a while-let loop and directly
+    /// pattern matching on the return value of `Vec::pop()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while !numbers.is_empty() {
+    ///     let number = numbers.pop().unwrap();
+    ///     // use `number`
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while let Some(number) = numbers.pop() {
+    ///     // use `number`
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MANUAL_WHILE_LET_SOME,
+    style,
+    "checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
+}
+
 declare_lint_pass!(Loops => [
     MANUAL_MEMCPY,
     MANUAL_FLATTEN,
@@ -594,6 +625,7 @@ declare_lint_pass!(Loops => [
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
     MANUAL_FIND,
+    MANUAL_WHILE_LET_SOME
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -640,9 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         while_let_on_iterator::check(cx, expr);
 
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
+        if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
             missing_spin_loop::check(cx, condition, body);
+            manual_while_let_some::check(cx, condition, body, span);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 5c317c2a5bb..cb446567506 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -208,7 +208,7 @@ fn is_end_eq_array_len<'tcx>(
     indexed_ty: Ty<'tcx>,
 ) -> bool {
     if_chain! {
-        if let ExprKind::Lit(ref lit) = end.kind;
+        if let ExprKind::Lit(lit) = end.kind;
         if let ast::LitKind::Int(end_int, _) = lit.node;
         if let ty::Array(_, arr_len_const) = indexed_ty.kind();
         if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index ce5d657bcf0..45ea5aab4c2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
             };
             let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
             let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
-            // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+            // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block
             span_lint_and_then(
                 cx,
                 MANUAL_ASSERT,
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 98e698c6c2a..1247370b74a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                 if source != MatchSource::Normal {
                     return;
                 }
-                // Any other number than two arms doesn't (neccessarily)
+                // Any other number than two arms doesn't (necessarily)
                 // have a trivial mapping to let else.
                 if arms.len() != 2 {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 72cdb9c1736..5259066eb71 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.64.0"]
     pub MANUAL_RETAIN,
     perf,
-    "`retain()` is simpler and the same functionalitys"
+    "`retain()` is simpler and the same functionalities"
 }
 
 pub struct ManualRetain {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
index df1e585f10b..69105ff0d5c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
@@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
                 if arms.len() == 2 {
                     // no guards
                     let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
-                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
+                        if let ExprKind::Lit(lit) = arm_bool.kind {
                             match lit.node {
                                 LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
                                 LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 158e6caa4de..a48f4c77f85 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -284,6 +284,7 @@ impl<'a> NormalizedPat<'a> {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
                     LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Byte(val) => Self::LitInt(val.into()),
+                    LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val),
                     LitKind::Bool(val) => Self::LitBool(val),
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 7b609ff3df8..af121f317cd 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>(
     // Determine which function should be used, and the type contained by the corresponding
     // variant.
     let (good_method, inner_ty) = match check_pat.kind {
-        PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
-            if let PatKind::Wild = sub_pat.kind {
+        PatKind::TupleStruct(ref qpath, args, rest) => {
+            let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
+            let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
+
+            if is_wildcard || is_rest {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
                 let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
@@ -334,7 +337,7 @@ fn find_good_method_for_match<'a>(
     };
 
     match body_node_pair {
-        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+        (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
             (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
             (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
             _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 27a05337a29..8984b2cf8fd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -18,7 +18,7 @@ pub(super) fn check(
 ) -> bool {
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Lit(ref lit) = info.other.kind;
+        if let hir::ExprKind::Lit(lit) = info.other.kind;
         if let ast::LitKind::Char(c) = lit.node;
         then {
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index 83c1bf20346..e2029da8081 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
                 = higher::Range::hir(index_expr);
-            if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
+            if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 23d23f25f14..bd625a6914c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -42,11 +42,11 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
         if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
             let argument_option = match arguments[0].kind {
-                ExprKind::Lit(ref span) => {
+                ExprKind::Lit(span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
                         ..
-                    } = *span
+                    } = span
                     {
                         if *lit { Argument::True } else { Argument::False }
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index e3f2de3cd46..0284d9dea30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
         if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
-        if let ExprKind::Lit(ref lit) = arg.kind;
+        if let ExprKind::Lit(lit) = arg.kind;
         if let LitKind::Str(ref path_lit, _) = lit.node;
         if let pushed_path = Path::new(path_lit.as_str());
         if let Some(pushed_path_lit) = pushed_path.to_str();
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
index 361a3082f94..c028e954381 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -38,7 +38,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
         match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
         // check if argument of `SeekFrom::Current` is `0`
         if args.len() == 1 &&
-            let ExprKind::Lit(ref lit) = args[0].kind &&
+            let ExprKind::Lit(lit) = args[0].kind &&
             let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
             return true
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 660b7049cce..787e9e0ebd2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
         match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
         args1.len() == 1 &&
-        let ExprKind::Lit(ref lit) = args1[0].kind &&
+        let ExprKind::Lit(lit) = args1[0].kind &&
         let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
     {
         let method_call_span = expr.span.with_lo(name_span.lo());
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index aa87dead38f..5a3d12fd790 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -78,7 +78,7 @@ pub(super) fn check(
     }
 
     // Check if the first argument to .fold is a suitable literal
-    if let hir::ExprKind::Lit(ref lit) = init.kind {
+    if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
             ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index e99081ad062..1adecd2caac 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -12,7 +12,7 @@ declare_clippy_lint! {
     /// Checks if a provided method is used implicitly by a trait
     /// implementation. A usage example would be a wrapper where every method
     /// should perform some operation before delegating to the inner type's
-    /// implemenation.
+    /// implementation.
     ///
     /// This lint should typically be enabled on a specific trait `impl` item
     /// rather than globally.
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index c87059bf61d..71281a0b40b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -3,10 +3,12 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
+use clippy_utils::{
+    get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+};
+use clippy_utils::{higher, SpanlessEq};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
@@ -77,7 +79,39 @@ declare_clippy_lint! {
     "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 }
 
-declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for expressions of the form `if c { x = true } else { x = false }`
+    /// (or vice versa) and suggest assigning the variable directly from the
+    /// condition.
+    ///
+    /// ### Why is this bad?
+    /// Redundant code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// if must_keep(x, y) {
+    ///     skip = false;
+    /// } else {
+    ///     skip = true;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// skip = !must_keep(x, y);
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub NEEDLESS_BOOL_ASSIGN,
+    complexity,
+    "setting the same boolean variable in both branches of an if-statement"
+}
+declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]);
 
 fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
     let mut inner = e;
@@ -173,6 +207,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     _ => (),
                 }
             }
+            if let Some((lhs_a, a)) = fetch_assign(then) &&
+                let Some((lhs_b, b)) = fetch_assign(r#else) &&
+                SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) &&
+                span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty()
+            {
+                let mut applicability = Applicability::MachineApplicable;
+                let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability);
+                let sugg = if a == b {
+                    format!("{cond}; {lhs} = {a:?};")
+                } else {
+                    format!("{lhs} = {};", if a { cond } else { !cond })
+                };
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_BOOL_ASSIGN,
+                    e.span,
+                    "this if-then-else expression assigns a bool literal",
+                    "you can reduce it to",
+                    sugg,
+                    applicability
+                );
+            }
         }
     }
 }
@@ -369,10 +426,18 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
 }
 
 fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
-    if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
+    if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind {
         if let LitKind::Bool(value) = lit_ptr.node {
             return Some(value);
         }
     }
     None
 }
+
+fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> {
+    if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind {
+        fetch_bool_expr(rhs).map(|b| (lhs, b))
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index 6e54b243c03..da1b9d99931 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -49,14 +49,14 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
 
 fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
     if is_start &&
-    let ExprKind::Lit(ref literal) = e.kind &&
+    let ExprKind::Lit(literal) = e.kind &&
     let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
     {
         // don't check floating point literals on the start expression of a range
         return;
     }
     if_chain! {
-        if let ExprKind::Lit(ref literal) = e.kind;
+        if let ExprKind::Lit(literal) = e.kind;
         // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
         if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
         // inspect the source code of the expression for parenthesis
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index ed3e2c6e7f4..db0e22842d1 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
 
 fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::Lit(ref l) = lit.kind;
+        if let ExprKind::Lit(l) = lit.kind;
         if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
         if cx.typeck_results().expr_ty(exp).is_integral();
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index fafcf257094..f72595987ee 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -110,7 +110,7 @@ impl ArithmeticSideEffects {
     /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
     fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
         let actual = peel_hir_expr_unary(expr).0;
-        if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
+        if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
             return Some(n)
         }
         if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 9e6c6c73d4f..b8b32df6cc6 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -180,7 +180,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
         .allow_invalid_utf8(!utf8)
         .build();
 
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(ref r, style) = lit.node {
             let r = r.as_str();
             let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 };
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 34a3e5ddf4f..419d7991f0e 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -64,7 +64,78 @@ declare_clippy_lint! {
     restriction,
     "add a semicolon outside the block"
 }
-declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+#[derive(Copy, Clone)]
+pub struct SemicolonBlock {
+    semicolon_inside_block_ignore_singleline: bool,
+    semicolon_outside_block_ignore_multiline: bool,
+}
+
+impl SemicolonBlock {
+    pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
+        Self {
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        }
+    }
+
+    fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+        let insert_span = tail.span.source_callsite().shrink_to_hi();
+        let remove_span = semi_span.with_lo(block.span.hi());
+
+        if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_INSIDE_BLOCK,
+            semi_span,
+            "consider moving the `;` inside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+
+    fn semicolon_outside_block(
+        self,
+        cx: &LateContext<'_>,
+        block: &Block<'_>,
+        tail_stmt_expr: &Expr<'_>,
+        semi_span: Span,
+    ) {
+        let insert_span = block.span.with_lo(block.span.hi());
+        // account for macro calls
+        let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+        let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+        if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_OUTSIDE_BLOCK,
+            block.span,
+            "consider moving the `;` outside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+}
 
 impl LateLintPass<'_> for SemicolonBlock {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
@@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
                     span,
                     ..
                 } = stmt else { return };
-                semicolon_outside_block(cx, block, expr, span);
+                self.semicolon_outside_block(cx, block, expr, span);
             },
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
                 ..
-            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            }) if !block.span.from_expansion() => {
+                self.semicolon_inside_block(cx, block, tail, stmt.span);
+            },
             _ => (),
         }
     }
 }
 
-fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
-    let insert_span = tail.span.source_callsite().shrink_to_hi();
-    let remove_span = semi_span.with_lo(block.span.hi());
-
-    span_lint_and_then(
-        cx,
-        SEMICOLON_INSIDE_BLOCK,
-        semi_span,
-        "consider moving the `;` inside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
-}
-
-fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
-    let insert_span = block.span.with_lo(block.span.hi());
-    // account for macro calls
-    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
-    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> {
+    if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) {
+        return Some(line.line);
+    }
 
-    span_lint_and_then(
-        cx,
-        SEMICOLON_OUTSIDE_BLOCK,
-        block.span,
-        "consider moving the `;` outside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
+    None
 }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index ae7d19624ba..993f9373d85 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
 
-        if pat.span.desugaring_kind().is_some() {
+        if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index a2109038a05..858135c8d46 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -74,7 +74,7 @@ enum InitializationType<'tcx> {
 
 impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
+        // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index b2f4b310915..5b588e914fd 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
+            if !in_external_macro(cx.sess(), e.span);
             if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
             if let ExprKind::Lit(lit) = &receiver.kind;
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 03324c66e8e..2f2e84fa35a 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
 use clippy_utils::{get_parent_node, match_libc_symbol};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource};
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
                 let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
                 let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
                     "as_bytes"
-                } else if is_type_diagnostic_item(cx, ty, sym::CStr) {
+                } else if is_type_lang_item(cx, ty, LangItem::CStr) {
                     "to_bytes"
                 } else {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 98f5b47f7a0..bb9da3a2047 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
         if let Some(last_field) = data.fields().last();
         if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
-        // Then check if that that array zero-sized
+        // Then check if that array is zero-sized
         let length = Const::from_anon_const(cx.tcx, length.def_id);
         let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
         if let Some(length) = length;
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index c6834a8fdaa..3c873a5901d 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -90,8 +90,8 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// `Option<_>` represents an optional value. `Option<Option<_>>`
-    /// represents an optional optional value which is logically the same thing as an optional
-    /// value but has an unneeded extra level of wrapping.
+    /// represents an optional value which itself wraps an optional. This is logically the
+    /// same thing as an optional value but has an unneeded extra level of wrapping.
     ///
     /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
     /// consider a custom `enum` instead, with clear names for each case.
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index 8980283e5c8..e275bfd37b0 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -76,7 +76,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_
 
 impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let ExprKind::Lit(ref lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind {
             if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
                 check_str(cx, lit.span, expr.hir_id);
             }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index af1c8d83b4f..e7449639f3a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -109,7 +109,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
         // Ignore implementations of traits, because the lint should be on the
-        // trait, not on the implmentation of it.
+        // trait, not on the implementation of it.
         let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
         let ItemKind::Impl(parent) = parent.kind else { return };
         if parent.of_trait.is_some() {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 01927b6b5f1..935ea90d245 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -304,6 +304,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("ByteStr(ref {vec})");
                 chain!(self, "let [{:?}] = **{vec}", vec.value);
             },
+            LitKind::CStr(ref vec, _) => {
+                bind!(self, vec);
+                kind!("CStr(ref {vec})");
+                chain!(self, "let [{:?}] = **{vec}", vec.value);
+            }
             LitKind::Str(s, _) => {
                 bind!(self, s);
                 kind!("Str({s}, _)");
@@ -333,7 +338,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
     #[allow(clippy::too_many_lines)]
     fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
+        if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) {
             bind!(self, condition, body);
             chain!(
                 self,
@@ -561,7 +566,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::OffsetOf(container, ref fields) => {
                 bind!(self, container, fields);
                 kind!("OffsetOf({container}, {fields})");
-            }
+            },
             ExprKind::Struct(qpath, fields, base) => {
                 bind!(self, qpath, fields);
                 opt_bind!(self, base);
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 67bb499c455..5f05d971fce 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -277,6 +277,14 @@ define_Conf! {
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
     (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Lint: SEMICOLON_INSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's multiline.
+    (semicolon_inside_block_ignore_singleline: bool = false),
+    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's singleline.
+    (semicolon_outside_block_ignore_multiline: bool = false),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 124ebd164e6..66a5079fa85 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.70"
+version = "0.1.71"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index d3a6929f67e..9edaae85373 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -117,7 +117,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
         ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
         ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
-        ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+        ExprKind::Lit(lit) => lit_search_pat(&lit.node),
         ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
         ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
         ExprKind::Call(first, [.., last])
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 99bfc4b5717..8075881e3bb 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -211,6 +211,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
         LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
+        LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
@@ -324,7 +325,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
             ExprKind::Block(block, _) => self.block(block),
-            ExprKind::Lit(ref lit) => {
+            ExprKind::Lit(lit) => {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
                     None
                 } else {
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 50bef370930..a61e4c38088 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -311,6 +311,8 @@ pub struct While<'hir> {
     pub condition: &'hir Expr<'hir>,
     /// `while` loop body
     pub body: &'hir Expr<'hir>,
+    /// Span of the loop header
+    pub span: Span,
 }
 
 impl<'hir> While<'hir> {
@@ -336,10 +338,10 @@ impl<'hir> While<'hir> {
             },
             _,
             LoopSource::While,
-            _,
+            span,
         ) = expr.kind
         {
-            return Some(Self { condition, body });
+            return Some(Self { condition, body, span });
         }
         None
     }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index d972ed82c25..9b7408d5133 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -301,7 +301,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
             (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
-            (&ExprKind::OffsetOf(l_container, ref l_fields), &ExprKind::OffsetOf(r_container, ref r_fields)) => {
+            (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
                 self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
             },
             _ => false,
@@ -718,7 +718,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_pat(pat);
             },
             ExprKind::Err(_) => {},
-            ExprKind::Lit(ref l) => {
+            ExprKind::Lit(l) => {
                 l.node.hash(&mut self.s);
             },
             ExprKind::Loop(b, ref i, ..) => {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6b677df4641..964104fc31d 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -86,10 +86,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination,
-    Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
+    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
+    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
     MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
+    TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -197,31 +197,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
 /// }
 /// ```
 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
-    let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
-    match cx.tcx.hir().get_by_def_id(parent_id) {
-        Node::Item(&Item {
-            kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
-            ..
-        })
-        | Node::TraitItem(&TraitItem {
-            kind: TraitItemKind::Const(..),
-            ..
-        })
-        | Node::ImplItem(&ImplItem {
-            kind: ImplItemKind::Const(..),
-            ..
-        })
-        | Node::AnonConst(_) => true,
-        Node::Item(&Item {
-            kind: ItemKind::Fn(ref sig, ..),
-            ..
-        })
-        | Node::ImplItem(&ImplItem {
-            kind: ImplItemKind::Fn(ref sig, _),
-            ..
-        }) => sig.header.constness == Constness::Const,
-        _ => false,
-    }
+    cx.tcx.hir().is_inside_const_context(id)
 }
 
 /// Checks if a `Res` refers to a constructor of a `LangItem`
@@ -846,7 +822,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         },
         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
         ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
-            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
+            if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind;
             if let LitKind::Int(v, _) = const_lit.node;
             if v <= 32 && is_default_equivalent(cx, x);
             then {
@@ -875,7 +851,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
             }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
             ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
             ExprKind::Repeat(_, ArrayLen::Body(len)) => {
-                if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
+                if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind &&
                     let LitKind::Int(v, _) = const_lit.node
                 {
                         return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
@@ -1569,7 +1545,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
 /// Checks whether the given expression is a constant literal of the given value.
 pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
     // FIXME: use constant folding
-    if let ExprKind::Lit(ref spanned) = expr.kind {
+    if let ExprKind::Lit(spanned) = expr.kind {
         if let LitKind::Int(v, _) = spanned.node {
             return v == value;
         }
@@ -2165,10 +2141,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
         .predicates
         .iter()
         .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
-    traits::impossible_predicates(
-        cx.tcx,
-        traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>(),
-    )
+    traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
 }
 
 /// Returns the `DefId` of the callee if the given expression is a function or method call.
@@ -2233,8 +2206,12 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     None
 }
 
-/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
-/// `hash` must be comformed with `eq`
+/// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
+/// and `a` is before `b` in `exprs` for all `a` and `b` in
+/// `exprs`
+///
+/// Given functions `eq` and `hash` such that `eq(a, b) == true`
+/// implies `hash(a) == hash(b)`
 pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 where
     Hash: Fn(&T) -> u64,
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 62d388a5ece..e4a4936ff42 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -362,7 +362,7 @@ thread_local! {
     /// able to access the many features of a [`LateContext`].
     ///
     /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
-    /// assumption that the early pass the populates the map and the later late passes will all be
+    /// assumption that the early pass that populates the map and the later late passes will all be
     /// running on the same thread.
     static AST_FORMAT_ARGS: RefCell<FxHashMap<Span, FormatArgs>> = {
         static CALLED: AtomicBool = AtomicBool::new(false);
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 9be2d0eae80..0f0792fdaa9 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -159,3 +159,7 @@ pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
 pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
 pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
+pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
+pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
+pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
+pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index ecd712f32dc..c0d2c835d63 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -194,7 +194,9 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
+        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => {
+            Ok(())
+        },
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 03cd8e48b9a..14f7f03016f 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -162,7 +162,7 @@ impl<'a> Sugg<'a> {
                 get_snippet(lhs.span),
                 get_snippet(rhs.span),
             ),
-            hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
+            hir::ExprKind::Cast(lhs, ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
             hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
         }
@@ -254,11 +254,7 @@ impl<'a> Sugg<'a> {
                 snippet_with_context(cx, lhs.span, ctxt, default, app).0,
                 snippet_with_context(cx, rhs.span, ctxt, default, app).0,
             ),
-            ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
-                AssocOp::As,
-                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
-                snippet_with_context(cx, ty.span, ctxt, default, app).0,
-            ),
+            ast::ExprKind::Cast(ref lhs, ref ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
             ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
                 AssocOp::As,
@@ -603,8 +599,8 @@ enum Associativity {
 #[must_use]
 fn associativity(op: AssocOp) -> Associativity {
     use rustc_ast::util::parser::AssocOp::{
-        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater,
-        GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
+        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd,
+        LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
     };
 
     match op {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a6572011644..7b4ed77e8ed 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -93,7 +93,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                     for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
-                            // and check substituions to find `U`.
+                            // and check substitutions to find `U`.
                             ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
                                 if trait_predicate
                                     .trait_ref
@@ -837,7 +837,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     if let ty::Adt(adt, _) = ty.kind()
         && let &[krate, .., name] = &*cx.get_def_path(adt.did())
         && let sym::libc | sym::core | sym::std = krate
-        && name.as_str() == "c_void"
+        && name == rustc_span::sym::c_void
     {
         true
     } else {
@@ -1101,7 +1101,7 @@ pub fn make_projection<'tcx>(
 ///
 /// This function is for associated types which are "known" to be valid with the given
 /// substitutions, and as such, will only return `None` when debug assertions are disabled in order
-/// to prevent ICE's. With debug assertions enabled this will check that that type normalization
+/// to prevent ICE's. With debug assertions enabled this will check that type normalization
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index bd26f4fc913..139102798c4 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.70"
+version = "0.1.71"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md
index faf3ce9093a..37cc0453809 100644
--- a/src/tools/clippy/lintcheck/README.md
+++ b/src/tools/clippy/lintcheck/README.md
@@ -79,9 +79,11 @@ is explicitly specified in the options.
 
 ### Fix mode
 You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
-print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).  
+print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). 
 This lets us spot bad suggestions or false positives automatically in some cases.  
 
+> Note: Fix mode implies `--all-targets`, so it can fix as much code as it can.
+
 Please note that the target dir should be cleaned afterwards since clippy will modify
 the downloaded sources which can lead to unexpected results when running lintcheck again afterwards.
 
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 23c85298027..03d1877d6c6 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -421,7 +421,7 @@ impl Crate {
             {
                 let subcrate = &stderr[63..];
                 println!(
-                    "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}",
+                    "ERROR: failed to apply some suggestion to {} / to (sub)crate {subcrate}",
                     self.name
                 );
             }
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 91e8ccea1f4..60b8a5ac071 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-04-06"
+channel = "nightly-2023-05-05"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 205905d5091..59bf447a7cd 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -11,7 +11,6 @@
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
 extern crate rustc_driver;
-extern crate rustc_errors;
 extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
@@ -20,13 +19,10 @@ use rustc_interface::interface;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
 
-use std::borrow::Cow;
 use std::env;
 use std::ops::Deref;
-use std::panic;
 use std::path::Path;
 use std::process::exit;
-use std::sync::LazyLock;
 
 /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
 /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
@@ -198,66 +194,18 @@ You can use tool lints to allow or deny lints from your code, eg.:
 
 const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
 
-type PanicCallback = dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static;
-static ICE_HOOK: LazyLock<Box<PanicCallback>> = LazyLock::new(|| {
-    let hook = panic::take_hook();
-    panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
-    hook
-});
-
-fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
-    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
-    (*ICE_HOOK)(info);
-
-    // Separate the output with an empty line
-    eprintln!();
-
-    let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
-    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
-        rustc_errors::ColorConfig::Auto,
-        None,
-        None,
-        fallback_bundle,
-        false,
-        false,
-        None,
-        false,
-        false,
-        rustc_errors::TerminalUrl::No,
-    ));
-    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
-
-    // a .span_bug or .bug call has already printed what
-    // it wants to print.
-    if !info.payload().is::<rustc_errors::ExplicitBug>() {
-        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
-        handler.emit_diagnostic(&mut d);
-    }
-
-    let version_info = rustc_tools_util::get_version_info!();
-
-    let xs: Vec<Cow<'static, str>> = vec![
-        "the compiler unexpectedly panicked. this is a bug.".into(),
-        format!("we would appreciate a bug report: {bug_report_url}").into(),
-        format!("Clippy version: {version_info}").into(),
-    ];
-
-    for note in &xs {
-        handler.note_without_error(note.as_ref());
-    }
-
-    // If backtraces are enabled, also print the query stack
-    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
-
-    let num_frames = if backtrace { None } else { Some(2) };
-
-    interface::try_print_query_stack(&handler, num_frames);
-}
-
 #[allow(clippy::too_many_lines)]
 pub fn main() {
     rustc_driver::init_rustc_env_logger();
-    LazyLock::force(&ICE_HOOK);
+
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
+        // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
+        // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
+        // accept a generic closure.
+        let version_info = rustc_tools_util::get_version_info!();
+        handler.note_without_error(format!("Clippy version: {version_info}"));
+    });
+
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
         let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index c5e9b96cf3f..188ff87abfc 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -13,7 +13,7 @@ Usage:
 
 Common options:
     --no-deps                Run Clippy only on the given crate, without linting the dependencies
-    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
+    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets`
     -h, --help               Print this message
     -V, --version            Print version info and exit
     --explain LINT           Print the documentation for a given lint
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 68a878e9a3d..afde31face1 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -39,7 +39,7 @@ fn dogfood_clippy() {
     assert!(
         failed_packages.is_empty(),
         "Dogfood failed for packages `{}`",
-        failed_packages.iter().format(", "),
+        failed_packages.iter().join(", "),
     );
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed
new file mode 100644
index 00000000000..fc8038a0907
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs
new file mode 100644
index 00000000000..52ce1f0387e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr
new file mode 100644
index 00000000000..2f58842eab0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr
@@ -0,0 +1,55 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:43:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:44:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/both.rs:49:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:63:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml b/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml
new file mode 100644
index 00000000000..4d03e88deba
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml
@@ -0,0 +1,2 @@
+semicolon-inside-block-ignore-singleline = true
+semicolon-outside-block-ignore-multiline = true
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
new file mode 100644
index 00000000000..23df9830177
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
new file mode 100644
index 00000000000..e8516f79b20
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
new file mode 100644
index 00000000000..2569dc4b4e4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
@@ -0,0 +1,18 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:48:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
new file mode 100644
index 00000000000..7e9055e7110
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
new file mode 100644
index 00000000000..4dc956d8a4b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
new file mode 100644
index 00000000000..6dd3577dd09
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
@@ -0,0 +1,39 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:42:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:43:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:62:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 36b372b36f4..44710b09648 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
+           semicolon-inside-block-ignore-singleline
+           semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
            standard-macro-braces
            suppress-restriction-lint-in-const
diff --git a/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs b/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs
new file mode 100644
index 00000000000..5c3407628be
--- /dev/null
+++ b/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::allow_attributes)]
+#![feature(lint_reasons)]
+#![crate_type = "proc-macro"]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index a9bb61451dc..e5bb906663c 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -22,6 +22,13 @@ macro_rules! string_add {
 }
 
 #[macro_export]
+macro_rules! string_lit_as_bytes {
+    ($s:literal) => {
+        const C: &[u8] = $s.as_bytes();
+    };
+}
+
+#[macro_export]
 macro_rules! mut_mut {
     () => {
         let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index 92c47b41a38..d164dd0e545 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -82,7 +82,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea
                     elided += 1;
 
                     // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
-                    // In order to avoid adding the dependency, get a default span from a non-existent token.
+                    // In order to avoid adding the dependency, get a default span from a nonexistent token.
                     // A default span is needed to mark the code as coming from expansion.
                     let span = Star::default().span();
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
index 9831c3373d4..fbb10a133e2 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![feature(let_chains)]
+#![feature(let_chains, inline_const)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
@@ -79,6 +79,13 @@ fn main() {
 
     pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
 
+    // https://github.com/rust-lang/rust-clippy/issues/10452
+    let should_not_lint = [(); if true { 1 } else { 0 }];
+
+    let should_not_lint = const {
+        if true { 1 } else { 0 }
+    };
+
     some_fn(a);
 }
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
index 5e3047bb32c..709a18d63e4 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![feature(let_chains)]
+#![feature(let_chains, inline_const)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
@@ -111,6 +111,13 @@ fn main() {
 
     pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
 
+    // https://github.com/rust-lang/rust-clippy/issues/10452
+    let should_not_lint = [(); if true { 1 } else { 0 }];
+
+    let should_not_lint = const {
+        if true { 1 } else { 0 }
+    };
+
     some_fn(a);
 }
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
index 5cfb75cc0df..3bdae75cad2 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
@@ -98,7 +98,7 @@ LL | |     };
    = note: `!b as i32` or `(!b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> $DIR/bool_to_int_with_if.rs:119:5
+  --> $DIR/bool_to_int_with_if.rs:126:5
    |
 LL |     if a { 1 } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 6afce208769..e6331290420 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
+#![allow(clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 09365618e63..34a05a29c5a 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
+#![allow(clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index 78e17b9f035..c9834863601 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -1,5 +1,5 @@
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:22:32
+  --> $DIR/box_default.rs:23:32
    |
 LL |     let _string: Box<String> = Box::new(Default::default());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
@@ -7,91 +7,91 @@ LL |     let _string: Box<String> = Box::new(Default::default());
    = note: `-D clippy::box-default` implied by `-D warnings`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:23:17
+  --> $DIR/box_default.rs:24:17
    |
 LL |     let _byte = Box::new(u8::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:24:16
+  --> $DIR/box_default.rs:25:16
    |
 LL |     let _vec = Box::new(Vec::<u8>::new());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:25:17
+  --> $DIR/box_default.rs:26:17
    |
 LL |     let _impl = Box::new(ImplementsDefault::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:26:18
+  --> $DIR/box_default.rs:27:18
    |
 LL |     let _impl2 = Box::new(<ImplementsDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:27:42
+  --> $DIR/box_default.rs:28:42
    |
 LL |     let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:29:28
+  --> $DIR/box_default.rs:30:28
    |
 LL |     let _in_macro = outer!(Box::new(String::new()));
    |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:30:34
+  --> $DIR/box_default.rs:31:34
    |
 LL |     let _string_default = outer!(Box::new(String::from("")));
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:31:46
+  --> $DIR/box_default.rs:32:46
    |
 LL |     let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
    |                                              ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:32:33
+  --> $DIR/box_default.rs:33:33
    |
 LL |     let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:33:25
+  --> $DIR/box_default.rs:34:25
    |
 LL |     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:35:16
+  --> $DIR/box_default.rs:36:16
    |
 LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:40:5
+  --> $DIR/box_default.rs:41:5
    |
 LL |     Box::new(bool::default())
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:57:28
+  --> $DIR/box_default.rs:58:28
    |
 LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:66:17
+  --> $DIR/box_default.rs:67:17
    |
 LL |         let _ = Box::new(WeirdPathed::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:78:18
+  --> $DIR/box_default.rs:79:18
    |
 LL |             Some(Box::new(Foo::default()))
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
diff --git a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs
index 24d7eb28a19..b77f01883bf 100644
--- a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs
@@ -23,7 +23,7 @@ fn main() {
         r_x as *const [i32]
     } as *const [u8];
 
-    // Check that resores of the same size are detected through blocks
+    // Check that resources of the same size are detected through blocks
     let restore_block_1 = { r_x as *const [i32] } as *const [u8] as *const [u32];
     let restore_block_2 = { ({ r_x as *const [i32] }) as *const [u8] } as *const [u32];
     let restore_block_3 = {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10645.rs b/src/tools/clippy/tests/ui/crashes/ice-10645.rs
new file mode 100644
index 00000000000..4d8698d383b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-10645.rs
@@ -0,0 +1,7 @@
+// compile-flags: --cap-lints=warn
+// https://github.com/rust-lang/rust-clippy/issues/10645
+
+#![warn(clippy::future_not_send)]
+pub async fn bar<'a, T: 'a>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.stderr b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
index 59146c23e0d..fc084e30d7f 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5207.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
@@ -1,11 +1,11 @@
 error: future cannot be sent between threads safely
-  --> $DIR/ice-5207.rs:6:35
+  --> $DIR/ice-10645.rs:5:35
    |
 LL | pub async fn bar<'a, T: 'a>(_: T) {}
    |                                   ^ future returned by `bar` is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/ice-5207.rs:6:29
+  --> $DIR/ice-10645.rs:5:29
    |
 LL | pub async fn bar<'a, T: 'a>(_: T) {}
    |                             ^ has type `T` which is not `Send`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs
index 893c15f5d73..0df8b88fea2 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5207.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs
@@ -1,8 +1,4 @@
-// compile-flags: --cap-lints=warn
-// ^ for https://github.com/rust-lang/rust-clippy/issues/10645
-
 // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
-#![warn(clippy::future_not_send)]
 pub async fn bar<'a, T: 'a>(_: T) {}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
index 30e4b11ec0b..30e4b11ec0b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
new file mode 100644
index 00000000000..4c2d1ea48e1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
@@ -0,0 +1,119 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::default_constructed_unit_structs)]
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct UnitStruct;
+
+impl UnitStruct {
+    fn new() -> Self {
+        //should lint
+        Self
+    }
+}
+
+#[derive(Default)]
+struct TupleStruct(usize);
+
+impl TupleStruct {
+    fn new() -> Self {
+        // should not lint
+        Self(Default::default())
+    }
+}
+
+// no lint for derived impl
+#[derive(Default)]
+struct NormalStruct {
+    inner: PhantomData<usize>,
+}
+
+struct NonDefaultStruct;
+
+impl NonDefaultStruct {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+enum SomeEnum {
+    #[default]
+    Unit,
+    Tuple(UnitStruct),
+    Struct {
+        inner: usize,
+    },
+}
+
+impl NormalStruct {
+    fn new() -> Self {
+        // should lint
+        Self {
+            inner: PhantomData,
+        }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self {
+            inner: Default::default(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct GenericStruct<T> {
+    t: T,
+}
+
+impl<T: Default> GenericStruct<T> {
+    fn new() -> Self {
+        // should not lint
+        Self { t: T::default() }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self { t: Default::default() }
+    }
+}
+
+struct FakeDefault;
+impl FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+impl Default for FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct EmptyStruct {}
+
+#[derive(Default)]
+#[non_exhaustive]
+struct NonExhaustiveStruct;
+
+fn main() {
+    // should lint
+    let _ = PhantomData::<usize>;
+    let _: PhantomData<i32> = PhantomData;
+    let _ = UnitStruct;
+
+    // should not lint
+    let _ = TupleStruct::default();
+    let _ = NormalStruct::default();
+    let _ = NonExhaustiveStruct::default();
+    let _ = SomeEnum::default();
+    let _ = NonDefaultStruct::default();
+    let _ = EmptyStruct::default();
+    let _ = FakeDefault::default();
+    let _ = <FakeDefault as Default>::default();
+}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..850793dd5de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
@@ -0,0 +1,119 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::default_constructed_unit_structs)]
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct UnitStruct;
+
+impl UnitStruct {
+    fn new() -> Self {
+        //should lint
+        Self::default()
+    }
+}
+
+#[derive(Default)]
+struct TupleStruct(usize);
+
+impl TupleStruct {
+    fn new() -> Self {
+        // should not lint
+        Self(Default::default())
+    }
+}
+
+// no lint for derived impl
+#[derive(Default)]
+struct NormalStruct {
+    inner: PhantomData<usize>,
+}
+
+struct NonDefaultStruct;
+
+impl NonDefaultStruct {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+enum SomeEnum {
+    #[default]
+    Unit,
+    Tuple(UnitStruct),
+    Struct {
+        inner: usize,
+    },
+}
+
+impl NormalStruct {
+    fn new() -> Self {
+        // should lint
+        Self {
+            inner: PhantomData::default(),
+        }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self {
+            inner: Default::default(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct GenericStruct<T> {
+    t: T,
+}
+
+impl<T: Default> GenericStruct<T> {
+    fn new() -> Self {
+        // should not lint
+        Self { t: T::default() }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self { t: Default::default() }
+    }
+}
+
+struct FakeDefault;
+impl FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+impl Default for FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct EmptyStruct {}
+
+#[derive(Default)]
+#[non_exhaustive]
+struct NonExhaustiveStruct;
+
+fn main() {
+    // should lint
+    let _ = PhantomData::<usize>::default();
+    let _: PhantomData<i32> = PhantomData::default();
+    let _ = UnitStruct::default();
+
+    // should not lint
+    let _ = TupleStruct::default();
+    let _ = NormalStruct::default();
+    let _ = NonExhaustiveStruct::default();
+    let _ = SomeEnum::default();
+    let _ = NonDefaultStruct::default();
+    let _ = EmptyStruct::default();
+    let _ = FakeDefault::default();
+    let _ = <FakeDefault as Default>::default();
+}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
new file mode 100644
index 00000000000..4058943d087
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
@@ -0,0 +1,34 @@
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:13:13
+   |
+LL |         Self::default()
+   |             ^^^^^^^^^^^ help: remove this call to `default`
+   |
+   = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:55:31
+   |
+LL |             inner: PhantomData::default(),
+   |                               ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:106:33
+   |
+LL |     let _ = PhantomData::<usize>::default();
+   |                                 ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:107:42
+   |
+LL |     let _: PhantomData<i32> = PhantomData::default();
+   |                                          ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:108:23
+   |
+LL |     let _ = UnitStruct::default();
+   |                       ^^^^^^^^^^^ help: remove this call to `default`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
new file mode 100644
index 00000000000..a42c6383cce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
@@ -0,0 +1,31 @@
+#![feature(lang_items, start)]
+#![warn(clippy::imprecise_flops)]
+#![warn(clippy::suboptimal_flops)]
+#![no_std]
+
+// The following should not lint, as the suggested methods {f32,f64}.mul_add()
+// and {f32,f64}::abs() are not available in no_std
+
+pub fn mul_add() {
+    let a: f64 = 1234.567;
+    let b: f64 = 45.67834;
+    let c: f64 = 0.0004;
+    let _ = a * b + c;
+}
+
+fn fake_abs1(num: f64) -> f64 {
+    if num >= 0.0 { num } else { -num }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed
index fc6d937060d..d18f9387565 100644
--- a/src/tools/clippy/tests/ui/from_over_into.fixed
+++ b/src/tools/clippy/tests/ui/from_over_into.fixed
@@ -32,7 +32,7 @@ struct SelfKeywords;
 
 impl From<X> for SelfKeywords {
     fn from(val: X) -> Self {
-        let _ = X::default();
+        let _ = X;
         let _ = X::FOO;
         let _: X = val;
 
diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs
index fe1ebee35f1..de8ff0b06bd 100644
--- a/src/tools/clippy/tests/ui/from_over_into.rs
+++ b/src/tools/clippy/tests/ui/from_over_into.rs
@@ -32,7 +32,7 @@ struct SelfKeywords;
 
 impl Into<SelfKeywords> for X {
     fn into(self) -> SelfKeywords {
-        let _ = Self::default();
+        let _ = Self;
         let _ = Self::FOO;
         let _: Self = self;
 
diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr
index 3c4d011d6fb..6039f86fe67 100644
--- a/src/tools/clippy/tests/ui/from_over_into.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into.stderr
@@ -5,7 +5,7 @@ LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::from-over-into` implied by `-D warnings`
-help: replace the `Into` implentation with `From<std::string::String>`
+help: replace the `Into` implementation with `From<std::string::String>`
    |
 LL ~ impl From<String> for StringWrapper {
 LL ~     fn from(val: String) -> Self {
@@ -18,7 +18,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<SelfType> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<std::string::String>`
+help: replace the `Into` implementation with `From<std::string::String>`
    |
 LL ~ impl From<String> for SelfType {
 LL ~     fn from(val: String) -> Self {
@@ -31,11 +31,11 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<SelfKeywords> for X {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<X>`
+help: replace the `Into` implementation with `From<X>`
    |
 LL ~ impl From<X> for SelfKeywords {
 LL ~     fn from(val: X) -> Self {
-LL ~         let _ = X::default();
+LL ~         let _ = X;
 LL ~         let _ = X::FOO;
 LL ~         let _: X = val;
    |
@@ -48,7 +48,7 @@ LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
    |
    = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
-help: replace the `Into` implentation with `From<ExplicitPaths>`
+help: replace the `Into` implementation with `From<ExplicitPaths>`
    |
 LL ~ impl core::convert::From<crate::ExplicitPaths> for bool {
 LL ~     fn from(mut val: crate::ExplicitPaths) -> Self {
@@ -64,7 +64,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<std::vec::Vec<T>>`
+help: replace the `Into` implementation with `From<std::vec::Vec<T>>`
    |
 LL ~     impl<T> From<Vec<T>> for FromOverInto<T> {
 LL ~         fn from(val: Vec<T>) -> Self {
diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
index 6f6ce351921..251f1d84e74 100644
--- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
@@ -4,7 +4,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<InMacro> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: replace the `Into` implentation with `From<std::string::String>`
+   = help: replace the `Into` implementation with `From<std::string::String>`
    = note: `-D clippy::from-over-into` implied by `-D warnings`
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
@@ -13,7 +13,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<WeirdUpperSelf> for &'static [u8] {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: replace the `Into` implentation with `From<&'static [u8]>`
+   = help: replace the `Into` implementation with `From<&'static [u8]>`
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
   --> $DIR/from_over_into_unfixable.rs:28:1
@@ -23,7 +23,7 @@ LL | impl Into<u8> for ContainsVal {
    |
    = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
-   = help: replace the `Into` implentation with `From<ContainsVal>`
+   = help: replace the `Into` implementation with `From<ContainsVal>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/block_module.rs
index 5136b2557ec..5136b2557ec 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module.rs
+++ b/src/tools/clippy/tests/ui/items_after_test_module/block_module.rs
diff --git a/src/tools/clippy/tests/ui/items_after_test_module.stderr b/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
index 8f1616dabc1..597f1b9510c 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module.stderr
+++ b/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
@@ -1,5 +1,5 @@
 error: items were found after the testing module
-  --> $DIR/items_after_test_module.rs:13:1
+  --> $DIR/block_module.rs:13:1
    |
 LL | / mod tests {
 LL | |     #[test]
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs
new file mode 100644
index 00000000000..6a757aef48e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs
@@ -0,0 +1,20 @@
+//@compile-flags: --test
+#![allow(unused)]
+#![warn(clippy::items_after_test_module)]
+
+// Nothing here should lint, as `tests` is an imported module (that has no body).
+
+fn main() {}
+
+fn should_not_lint() {}
+
+#[path = "auxiliary/tests.rs"]
+#[cfg(test)]
+mod tests; // Should not lint
+
+fn should_not_lint2() {}
+
+const SHOULD_ALSO_NOT_LINT: usize = 1;
+macro_rules! should_not_lint {
+    () => {};
+}
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
index 47e76ea1d04..6844cb998f7 100644
--- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
@@ -4,7 +4,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = a();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:36:10
+   |
+LL |     let _ = a();
+   |          ^
    = note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
 
 error: non-binding `let` without a type annotation
@@ -13,7 +17,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = b(1);
    |     ^^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:37:10
+   |
+LL |     let _ = b(1);
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:39:5
@@ -21,7 +29,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = d(&1);
    |     ^^^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:39:10
+   |
+LL |     let _ = d(&1);
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:40:5
@@ -29,7 +41,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = e();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:40:10
+   |
+LL |     let _ = e();
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:41:5
@@ -37,7 +53,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = f();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:41:10
+   |
+LL |     let _ = f();
+   |          ^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.rs b/src/tools/clippy/tests/ui/let_with_type_underscore.rs
index 175718b94c8..7c1835e8cd1 100644
--- a/src/tools/clippy/tests/ui/let_with_type_underscore.rs
+++ b/src/tools/clippy/tests/ui/let_with_type_underscore.rs
@@ -12,7 +12,7 @@ fn main() {
     let _: _ = 2;
     let x: _ = func();
 
-    let x = 1; // Will not lint, Rust inferres this to an integer before Clippy
+    let x = 1; // Will not lint, Rust infers this to an integer before Clippy
     let x = func();
     let x: Vec<_> = Vec::<u32>::new();
     let x: [_; 1] = [1];
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index d3cac666763..09fb0d75852 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -23,8 +23,8 @@ fn main() {
 }
 
 fn binary_heap_retain() {
-    // NOTE: Do not lint now, because binary_heap_retain is nighyly API.
-    // And we need to add a test case for msrv if we update this implmention.
+    // NOTE: Do not lint now, because binary_heap_retain is nightly API.
+    // And we need to add a test case for msrv if we update this implementation.
     // https://github.com/rust-lang/rust/issues/71503
     let mut heap = BinaryHeap::from([1, 2, 3]);
     heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index 34f0c4d5029..7fee4c95cea 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -23,8 +23,8 @@ fn main() {
 }
 
 fn binary_heap_retain() {
-    // NOTE: Do not lint now, because binary_heap_retain is nighyly API.
-    // And we need to add a test case for msrv if we update this implmention.
+    // NOTE: Do not lint now, because binary_heap_retain is nightly API.
+    // And we need to add a test case for msrv if we update this implementation.
     // https://github.com/rust-lang/rust/issues/71503
     let mut heap = BinaryHeap::from([1, 2, 3]);
     heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.fixed b/src/tools/clippy/tests/ui/manual_while_let_some.fixed
new file mode 100644
index 00000000000..8b610919536
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_while_let_some.fixed
@@ -0,0 +1,93 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_while_let_some)]
+
+struct VecInStruct {
+    numbers: Vec<i32>,
+    unrelated: String,
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+fn accept_i32(_: i32) {}
+fn accept_optional_i32(_: Option<i32>) {}
+fn accept_i32_tuple(_: (i32, i32)) {}
+
+fn main() {
+    let mut numbers = vec![1, 2, 3, 4, 5];
+    while let Some(number) = numbers.pop() {
+        
+    }
+
+    let mut val = VecInStruct {
+        numbers: vec![1, 2, 3, 4, 5],
+        unrelated: String::new(),
+    };
+    while let Some(number) = val.numbers.pop() {
+        
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32(element);
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32(element);
+    }
+
+    // This should not warn. It "conditionally" pops elements.
+    while !numbers.is_empty() {
+        if true {
+            accept_i32(numbers.pop().unwrap());
+        }
+    }
+
+    // This should also not warn. It conditionally pops elements.
+    while !numbers.is_empty() {
+        if false {
+            continue;
+        }
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    // This should not warn. It pops elements, but does not unwrap it.
+    // Might handle the Option in some other arbitrary way.
+    while !numbers.is_empty() {
+        accept_optional_i32(numbers.pop());
+    }
+
+    let unrelated_vec: Vec<String> = Vec::new();
+    // This should not warn. It pops elements from a different vector.
+    while !unrelated_vec.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    macro_rules! generate_loop {
+        () => {
+            while !numbers.is_empty() {
+                accept_i32(numbers.pop().unwrap());
+            }
+        };
+    }
+    // Do not warn if the loop comes from a macro.
+    generate_loop!();
+
+    // Try other kinds of patterns
+    let mut numbers = vec![(0, 0), (1, 1), (2, 2)];
+    while let Some((a, b)) = numbers.pop() {
+        
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32_tuple(element);
+    }
+
+    let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
+    while let Some(Foo { a, b }) = results.pop() {
+        
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.rs b/src/tools/clippy/tests/ui/manual_while_let_some.rs
new file mode 100644
index 00000000000..85a0a084a42
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_while_let_some.rs
@@ -0,0 +1,93 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_while_let_some)]
+
+struct VecInStruct {
+    numbers: Vec<i32>,
+    unrelated: String,
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+fn accept_i32(_: i32) {}
+fn accept_optional_i32(_: Option<i32>) {}
+fn accept_i32_tuple(_: (i32, i32)) {}
+
+fn main() {
+    let mut numbers = vec![1, 2, 3, 4, 5];
+    while !numbers.is_empty() {
+        let number = numbers.pop().unwrap();
+    }
+
+    let mut val = VecInStruct {
+        numbers: vec![1, 2, 3, 4, 5],
+        unrelated: String::new(),
+    };
+    while !val.numbers.is_empty() {
+        let number = val.numbers.pop().unwrap();
+    }
+
+    while !numbers.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    while !numbers.is_empty() {
+        accept_i32(numbers.pop().expect(""));
+    }
+
+    // This should not warn. It "conditionally" pops elements.
+    while !numbers.is_empty() {
+        if true {
+            accept_i32(numbers.pop().unwrap());
+        }
+    }
+
+    // This should also not warn. It conditionally pops elements.
+    while !numbers.is_empty() {
+        if false {
+            continue;
+        }
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    // This should not warn. It pops elements, but does not unwrap it.
+    // Might handle the Option in some other arbitrary way.
+    while !numbers.is_empty() {
+        accept_optional_i32(numbers.pop());
+    }
+
+    let unrelated_vec: Vec<String> = Vec::new();
+    // This should not warn. It pops elements from a different vector.
+    while !unrelated_vec.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    macro_rules! generate_loop {
+        () => {
+            while !numbers.is_empty() {
+                accept_i32(numbers.pop().unwrap());
+            }
+        };
+    }
+    // Do not warn if the loop comes from a macro.
+    generate_loop!();
+
+    // Try other kinds of patterns
+    let mut numbers = vec![(0, 0), (1, 1), (2, 2)];
+    while !numbers.is_empty() {
+        let (a, b) = numbers.pop().unwrap();
+    }
+
+    while !numbers.is_empty() {
+        accept_i32_tuple(numbers.pop().unwrap());
+    }
+
+    let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
+    while !results.is_empty() {
+        let Foo { a, b } = results.pop().unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.stderr b/src/tools/clippy/tests/ui/manual_while_let_some.stderr
new file mode 100644
index 00000000000..633fe05c49b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_while_let_some.stderr
@@ -0,0 +1,87 @@
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:23:9
+   |
+LL |         let number = numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::manual-while-let-some` implied by `-D warnings`
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(number) = numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:31:9
+   |
+LL |         let number = val.numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(number) = val.numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:35:20
+   |
+LL |         accept_i32(numbers.pop().unwrap());
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:39:20
+   |
+LL |         accept_i32(numbers.pop().expect(""));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:82:9
+   |
+LL |         let (a, b) = numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some((a, b)) = numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:86:26
+   |
+LL |         accept_i32_tuple(numbers.pop().unwrap());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32_tuple(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:91:9
+   |
+LL |         let Foo { a, b } = results.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(Foo { a, b }) = results.pop() {
+LL ~         
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.fixed b/src/tools/clippy/tests/ui/needless_bool_assign.fixed
new file mode 100644
index 00000000000..3ed31d4d711
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool_assign.fixed
@@ -0,0 +1,33 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::needless_bool_assign)]
+
+fn random() -> bool {
+    true
+}
+
+fn main() {
+    struct Data {
+        field: bool,
+    };
+    let mut a = Data { field: false };
+    a.field = random() && random();
+    a.field = !(random() && random());
+    // Do not lint…
+    if random() {
+        a.field = false;
+    } else {
+        // …to avoid losing this comment
+        a.field = true
+    }
+    // This one also triggers lint `clippy::if_same_then_else`
+    // which does not suggest a rewrite.
+    random(); a.field = true;
+    let mut b = false;
+    if random() {
+        a.field = false;
+    } else {
+        b = true;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.rs b/src/tools/clippy/tests/ui/needless_bool_assign.rs
new file mode 100644
index 00000000000..efaeb67fa45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool_assign.rs
@@ -0,0 +1,45 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::needless_bool_assign)]
+
+fn random() -> bool {
+    true
+}
+
+fn main() {
+    struct Data {
+        field: bool,
+    };
+    let mut a = Data { field: false };
+    if random() && random() {
+        a.field = true;
+    } else {
+        a.field = false
+    }
+    if random() && random() {
+        a.field = false;
+    } else {
+        a.field = true
+    }
+    // Do not lint…
+    if random() {
+        a.field = false;
+    } else {
+        // …to avoid losing this comment
+        a.field = true
+    }
+    // This one also triggers lint `clippy::if_same_then_else`
+    // which does not suggest a rewrite.
+    if random() {
+        a.field = true;
+    } else {
+        a.field = true;
+    }
+    let mut b = false;
+    if random() {
+        a.field = false;
+    } else {
+        b = true;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.stderr b/src/tools/clippy/tests/ui/needless_bool_assign.stderr
new file mode 100644
index 00000000000..601bbed5493
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool_assign.stderr
@@ -0,0 +1,53 @@
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:15:5
+   |
+LL | /     if random() && random() {
+LL | |         a.field = true;
+LL | |     } else {
+LL | |         a.field = false
+LL | |     }
+   | |_____^ help: you can reduce it to: `a.field = random() && random();`
+   |
+   = note: `-D clippy::needless-bool-assign` implied by `-D warnings`
+
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:20:5
+   |
+LL | /     if random() && random() {
+LL | |         a.field = false;
+LL | |     } else {
+LL | |         a.field = true
+LL | |     }
+   | |_____^ help: you can reduce it to: `a.field = !(random() && random());`
+
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:34:5
+   |
+LL | /     if random() {
+LL | |         a.field = true;
+LL | |     } else {
+LL | |         a.field = true;
+LL | |     }
+   | |_____^ help: you can reduce it to: `random(); a.field = true;`
+
+error: this `if` has identical blocks
+  --> $DIR/needless_bool_assign.rs:34:17
+   |
+LL |       if random() {
+   |  _________________^
+LL | |         a.field = true;
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/needless_bool_assign.rs:36:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         a.field = true;
+LL | |     }
+   | |_____^
+   = note: `#[deny(clippy::if_same_then_else)]` on by default
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
index a04f9ec651e..92572942bc0 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -110,7 +110,7 @@ fn should_not_lint() {
         }),
     }
 
-    // `for_each` is in a let bingind.
+    // `for_each` is in a let binding.
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
index 4975c705081..95acbdff8cc 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -110,7 +110,7 @@ fn should_not_lint() {
         }),
     }
 
-    // `for_each` is in a let bingind.
+    // `for_each` is in a let binding.
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
index b32e721110e..818119f7be5 100644
--- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
@@ -25,7 +25,7 @@ fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lin
     0
 }
 
-// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"`
 #[no_mangle]
 #[rustfmt::skip]
 extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 9aebcf47100..57f341e0276 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -97,7 +97,7 @@ enum DummyEnum {
     Two,
 }
 
-// should not warn since there is a compled complex subpat
+// should not warn since there is a complex subpat
 // see #7991
 fn complex_subpat() -> DummyEnum {
     let x = Some(DummyEnum::One(1));
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index b40b324902a..19f9f704517 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -120,7 +120,7 @@ enum DummyEnum {
     Two,
 }
 
-// should not warn since there is a compled complex subpat
+// should not warn since there is a complex subpat
 // see #7991
 fn complex_subpat() -> DummyEnum {
     let x = Some(DummyEnum::One(1));
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index 87100b97288..d62f7d26a35 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -54,6 +54,8 @@ fn main() {
     } else {
         3
     };
+
+    if gen_opt().is_some() {}
 }
 
 fn gen_opt() -> Option<()> {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 0b69e13f655..d6429426573 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -63,6 +63,8 @@ fn main() {
     } else {
         3
     };
+
+    if let Some(..) = gen_opt() {}
 }
 
 fn gen_opt() -> Option<()> {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 27ff812ba45..7c5a047e455 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -89,31 +89,37 @@ LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:80:12
+  --> $DIR/redundant_pattern_matching_option.rs:67:12
+   |
+LL |     if let Some(..) = gen_opt() {}
+   |     -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:82:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:82:12
+  --> $DIR/redundant_pattern_matching_option.rs:84:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:84:15
+  --> $DIR/redundant_pattern_matching_option.rs:86:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:86:15
+  --> $DIR/redundant_pattern_matching_option.rs:88:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:88:5
+  --> $DIR/redundant_pattern_matching_option.rs:90:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -122,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:93:5
+  --> $DIR/redundant_pattern_matching_option.rs:95:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -131,16 +137,16 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:101:12
+  --> $DIR/redundant_pattern_matching_option.rs:103:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:102:12
+  --> $DIR/redundant_pattern_matching_option.rs:104:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index ff19a042825..42a59f6d43d 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -27,6 +27,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 38b1647c0cc..4d173e8cbbf 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -27,6 +27,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 70d15408b9f..0da4ed7520c 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,253 +7,253 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs
index daef95a425c..f31a7e33c4b 100644
--- a/src/tools/clippy/tests/ui/same_name_method.rs
+++ b/src/tools/clippy/tests/ui/same_name_method.rs
@@ -62,7 +62,7 @@ mod should_lint {
         impl T1 for S {}
     }
 
-    mod multiply_conflicit_trait {
+    mod multiple_conflicting_traits {
         use crate::{T1, T2};
 
         struct S;
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 03337ec3564..2c0fc3e3fd8 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -8,6 +8,12 @@ extern crate proc_macro_derive;
 #[derive(proc_macro_derive::ShadowDerive)]
 pub struct Nothing;
 
+macro_rules! reuse {
+    ($v:ident) => {
+        let $v = $v + 1;
+    };
+}
+
 fn shadow_same() {
     let x = 1;
     let x = x;
@@ -33,6 +39,12 @@ fn shadow_reuse() -> Option<()> {
     None
 }
 
+fn shadow_reuse_macro() {
+    let x = 1;
+    // this should not warn
+    reuse!(x);
+}
+
 fn shadow_unrelated() {
     let x = 1;
     let x = 2;
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index 92bb937d086..8321f6df224 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
 error: `x` is shadowed by itself in `x`
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:19:9
    |
 LL |     let x = x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:12:9
+  --> $DIR/shadow.rs:18:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-same` implied by `-D warnings`
 
 error: `mut x` is shadowed by itself in `&x`
-  --> $DIR/shadow.rs:14:13
+  --> $DIR/shadow.rs:20:13
    |
 LL |     let mut x = &x;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:19:9
    |
 LL |     let x = x;
    |         ^
 
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:21:9
    |
 LL |     let x = &mut x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:14:9
+  --> $DIR/shadow.rs:20:9
    |
 LL |     let mut x = &x;
    |         ^^^^^
 
 error: `x` is shadowed by itself in `*x`
-  --> $DIR/shadow.rs:16:9
+  --> $DIR/shadow.rs:22:9
    |
 LL |     let x = *x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:21:9
    |
 LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = x.0;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:20:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = ([[0]], ());
    |         ^
    = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:28:9
    |
 LL |     let x = x[0];
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = x.0;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:23:10
+  --> $DIR/shadow.rs:29:10
    |
 LL |     let [x] = x;
    |          ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:28:9
    |
 LL |     let x = x[0];
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = Some(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:23:10
+  --> $DIR/shadow.rs:29:10
    |
 LL |     let [x] = x;
    |          ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = foo(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = Some(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = || x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = foo(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = Some(1).map(|_| x)?;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = || x;
    |         ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:29:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let y = match y {
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:34:9
    |
 LL |     let y = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:38:9
+  --> $DIR/shadow.rs:50:9
    |
 LL |     let x = 2;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:37:9
+  --> $DIR/shadow.rs:49:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:43:13
+  --> $DIR/shadow.rs:55:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:42:10
+  --> $DIR/shadow.rs:54:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:48:14
+  --> $DIR/shadow.rs:60:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:49:17
+  --> $DIR/shadow.rs:61:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:48:14
+  --> $DIR/shadow.rs:60:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:53:17
+  --> $DIR/shadow.rs:65:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:54:20
+  --> $DIR/shadow.rs:66:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:55:15
+  --> $DIR/shadow.rs:67:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:56:13
+  --> $DIR/shadow.rs:68:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:55:15
+  --> $DIR/shadow.rs:67:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:59:17
+  --> $DIR/shadow.rs:71:17
    |
 LL |     if let Some(y) = y {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:58:9
+  --> $DIR/shadow.rs:70:9
    |
 LL |     let y = Some(1);
    |         ^
 
 error: `_b` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:95:9
+  --> $DIR/shadow.rs:107:9
    |
 LL |     let _b = _a;
    |         ^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:94:28
+  --> $DIR/shadow.rs:106:28
    |
 LL | pub async fn foo2(_a: i32, _b: i64) {
    |                            ^^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:101:21
+  --> $DIR/shadow.rs:113:21
    |
 LL |         if let Some(x) = Some(1) { x } else { 1 }
    |                     ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:100:13
+  --> $DIR/shadow.rs:112:13
    |
 LL |         let x = 1;
    |             ^
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
index 058f2aa54da..3fc11b8b088 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = b"warning";
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = b"hello there";
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = b"lit to string".to_vec();
     let bs = b"lit to owned".to_vec();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
index b550bea001f..7d54acf630e 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = $b.as_bytes();
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = "hello there".as_bytes();
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = "lit to string".to_string().into_bytes();
     let bs = "lit to owned".to_owned().into_bytes();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
index f47d6161c6c..61b4e210e0f 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
@@ -1,5 +1,5 @@
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:7:14
+  --> $DIR/string_lit_as_bytes.rs:17:14
    |
 LL |     let bs = "hello there".as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
@@ -7,34 +7,45 @@ LL |     let bs = "hello there".as_bytes();
    = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:9:14
+  --> $DIR/string_lit_as_bytes.rs:19:14
    |
 LL |     let bs = r###"raw string with 3# plus " ""###.as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:11:14
+  --> $DIR/string_lit_as_bytes.rs:21:14
    |
 LL |     let bs = "lit to string".to_string().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:12:14
+  --> $DIR/string_lit_as_bytes.rs:22:14
    |
 LL |     let bs = "lit to owned".to_owned().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()`
 
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:12:26
+   |
+LL |         const B: &[u8] = $b.as_bytes();
+   |                          ^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"warning"`
+...
+LL |     b!("warning");
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: calling `as_bytes()` on `include_str!(..)`
-  --> $DIR/string_lit_as_bytes.rs:25:22
+  --> $DIR/string_lit_as_bytes.rs:39:22
    |
 LL |     let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:27:13
+  --> $DIR/string_lit_as_bytes.rs:41:13
    |
 LL |     let _ = "string with newline/t/n".as_bytes();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"`
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs
index 8e3749eef35..928475b5f35 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.rs
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs
@@ -144,7 +144,7 @@ struct ReprCAlign {
 
 // NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen
 #[repr(C)]
-enum DontLintAnonymousStructsFromDesuraging {
+enum DontLintAnonymousStructsFromDesugaring {
     A(u32),
     B(f32, [u64; 0]),
     C { x: u32, y: [u64; 0] },
diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs
index c996de89422..2d567630e15 100644
--- a/src/tools/clippy/tests/ui/uninit.rs
+++ b/src/tools/clippy/tests/ui/uninit.rs
@@ -17,10 +17,10 @@ fn main() {
     // This is OK, because `MaybeUninit` allows uninitialized data.
     let _: MaybeUninit<usize> = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // This is OK, because all constitutent types are uninit-compatible.
+    // This is OK, because all constituent types are uninit-compatible.
     let _: (MaybeUninit<usize>, MaybeUninit<bool>) = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // This is OK, because all constitutent types are uninit-compatible.
+    // This is OK, because all constituent types are uninit-compatible.
     let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
 
     // This is OK, because our own MaybeUninit is just as fine as the one from core.
diff --git a/src/tools/clippy/tests/ui/use_self_trait.fixed b/src/tools/clippy/tests/ui/use_self_trait.fixed
index 4623aeeb0eb..20138a29fd1 100644
--- a/src/tools/clippy/tests/ui/use_self_trait.fixed
+++ b/src/tools/clippy/tests/ui/use_self_trait.fixed
@@ -33,7 +33,7 @@ impl SelfTrait for Bad {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
@@ -70,7 +70,7 @@ impl SelfTrait for Good {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/use_self_trait.rs b/src/tools/clippy/tests/ui/use_self_trait.rs
index d7d76dd9623..bf697b01a42 100644
--- a/src/tools/clippy/tests/ui/use_self_trait.rs
+++ b/src/tools/clippy/tests/ui/use_self_trait.rs
@@ -33,7 +33,7 @@ impl SelfTrait for Bad {
     fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
 
     fn vals(_: Bad) -> Bad {
-        Bad::default()
+        Bad
     }
 }
 
@@ -70,7 +70,7 @@ impl SelfTrait for Good {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr
index 090729b9c3d..6257f802dd8 100644
--- a/src/tools/clippy/tests/ui/use_self_trait.stderr
+++ b/src/tools/clippy/tests/ui/use_self_trait.stderr
@@ -63,7 +63,7 @@ LL |     fn vals(_: Bad) -> Bad {
 error: unnecessary structure name repetition
   --> $DIR/use_self_trait.rs:36:9
    |
-LL |         Bad::default()
+LL |         Bad
    |         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index e46ad2c6e0e..8791debad72 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -564,7 +564,7 @@ Otherwise, have a great day =^.^=
     </div>
 
     <a href="https://github.com/rust-lang/rust-clippy">
-        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on Github"/>
+        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"/>
     </a>
 
     <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/12.3.2/markdown-it.min.js"></script>
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 81179480ed8..4a57c61406c 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -116,6 +116,11 @@ pub(super) fn handle_needs(
             ignore_reason: "ignored when dlltool for x86_64 is not present",
         },
         Need {
+            name: "needs-dlltool",
+            condition: cache.dlltool,
+            ignore_reason: "ignored when dlltool for the current architecture is not present",
+        },
+        Need {
             name: "needs-git-hash",
             condition: config.git_hash,
             ignore_reason: "ignored when git hashes have been omitted for building",
@@ -183,6 +188,7 @@ pub(super) struct CachedNeedsConditions {
     rust_lld: bool,
     i686_dlltool: bool,
     x86_64_dlltool: bool,
+    dlltool: bool,
 }
 
 impl CachedNeedsConditions {
@@ -190,6 +196,17 @@ impl CachedNeedsConditions {
         let path = std::env::var_os("PATH").expect("missing PATH environment variable");
         let path = std::env::split_paths(&path).collect::<Vec<_>>();
 
+        // On Windows, dlltool.exe is used for all architectures.
+        #[cfg(windows)]
+        let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file());
+
+        // For non-Windows, there are architecture specific dlltool binaries.
+        #[cfg(not(windows))]
+        let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file());
+        #[cfg(not(windows))]
+        let x86_64_dlltool =
+            path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file());
+
         let target = &&*config.target;
         Self {
             sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
@@ -225,17 +242,26 @@ impl CachedNeedsConditions {
                 .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
                 .exists(),
 
-            // On Windows, dlltool.exe is used for all architectures.
             #[cfg(windows)]
-            i686_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()),
+            i686_dlltool: dlltool,
             #[cfg(windows)]
-            x86_64_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()),
+            x86_64_dlltool: dlltool,
+            #[cfg(windows)]
+            dlltool,
 
             // For non-Windows, there are architecture specific dlltool binaries.
             #[cfg(not(windows))]
-            i686_dlltool: path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()),
+            i686_dlltool,
+            #[cfg(not(windows))]
+            x86_64_dlltool,
             #[cfg(not(windows))]
-            x86_64_dlltool: path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()),
+            dlltool: if config.matches_arch("x86") {
+                i686_dlltool
+            } else if config.matches_arch("x86_64") {
+                x86_64_dlltool
+            } else {
+                false
+            },
         }
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a4be7af886b..4ede4603789 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1483,7 +1483,16 @@ impl<'test> TestCx<'test> {
     }
 
     fn compile_test(&self, will_execute: WillExecute, emit: Emit) -> ProcRes {
-        self.compile_test_general(will_execute, emit, self.props.local_pass_mode())
+        self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), Vec::new())
+    }
+
+    fn compile_test_with_passes(
+        &self,
+        will_execute: WillExecute,
+        emit: Emit,
+        passes: Vec<String>,
+    ) -> ProcRes {
+        self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), passes)
     }
 
     fn compile_test_general(
@@ -1491,6 +1500,7 @@ impl<'test> TestCx<'test> {
         will_execute: WillExecute,
         emit: Emit,
         local_pm: Option<PassMode>,
+        passes: Vec<String>,
     ) -> ProcRes {
         // Only use `make_exe_name` when the test ends up being executed.
         let output_file = match will_execute {
@@ -1527,6 +1537,7 @@ impl<'test> TestCx<'test> {
             emit,
             allow_unused,
             LinkToAux::Yes,
+            passes,
         );
 
         self.compose_and_run_compiler(rustc, None)
@@ -1777,6 +1788,7 @@ impl<'test> TestCx<'test> {
             Emit::None,
             AllowUnused::No,
             LinkToAux::No,
+            Vec::new(),
         );
 
         for key in &aux_props.unset_rustc_env {
@@ -1908,6 +1920,7 @@ impl<'test> TestCx<'test> {
         emit: Emit,
         allow_unused: AllowUnused,
         link_to_aux: LinkToAux,
+        passes: Vec<String>, // Vec of passes under mir-opt test to be dumped
     ) -> Command {
         let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary");
         let is_rustdoc = self.is_rustdoc() && !is_aux;
@@ -2008,9 +2021,18 @@ impl<'test> TestCx<'test> {
                 rustc.arg("-Cstrip=debuginfo");
             }
             MirOpt => {
+                // We check passes under test to minimize the mir-opt test dump
+                // if files_for_miropt_test parses the passes, we dump only those passes
+                // otherwise we conservatively pass -Zdump-mir=all
+                let zdump_arg = if !passes.is_empty() {
+                    format!("-Zdump-mir={}", passes.join(" | "))
+                } else {
+                    "-Zdump-mir=all".to_string()
+                };
+
                 rustc.args(&[
                     "-Copt-level=1",
-                    "-Zdump-mir=all",
+                    &zdump_arg,
                     "-Zvalidate-mir",
                     "-Zdump-mir-exclude-pass-number",
                     "-Zmir-pretty-relative-line-numbers=yes",
@@ -2333,6 +2355,7 @@ impl<'test> TestCx<'test> {
             Emit::LlvmIr,
             AllowUnused::No,
             LinkToAux::Yes,
+            Vec::new(),
         );
 
         self.compose_and_run_compiler(rustc, None)
@@ -2364,8 +2387,14 @@ impl<'test> TestCx<'test> {
             None => self.fatal("missing 'assembly-output' header"),
         }
 
-        let rustc =
-            self.make_compile_args(input_file, output_file, emit, AllowUnused::No, LinkToAux::Yes);
+        let rustc = self.make_compile_args(
+            input_file,
+            output_file,
+            emit,
+            AllowUnused::No,
+            LinkToAux::Yes,
+            Vec::new(),
+        );
 
         (self.compose_and_run_compiler(rustc, None), output_path)
     }
@@ -2496,6 +2525,7 @@ impl<'test> TestCx<'test> {
             Emit::None,
             AllowUnused::Yes,
             LinkToAux::Yes,
+            Vec::new(),
         );
         new_rustdoc.build_all_auxiliary(&mut rustc);
 
@@ -3310,7 +3340,8 @@ impl<'test> TestCx<'test> {
         if let Some(FailMode::Build) = self.props.fail_mode {
             // Make sure a build-fail test cannot fail due to failing analysis (e.g. typeck).
             let pm = Some(PassMode::Check);
-            let proc_res = self.compile_test_general(WillExecute::No, Emit::Metadata, pm);
+            let proc_res =
+                self.compile_test_general(WillExecute::No, Emit::Metadata, pm, Vec::new());
             self.check_if_test_should_compile(&proc_res, pm);
         }
 
@@ -3479,6 +3510,7 @@ impl<'test> TestCx<'test> {
                 emit_metadata,
                 AllowUnused::No,
                 LinkToAux::Yes,
+                Vec::new(),
             );
             let res = self.compose_and_run_compiler(rustc, None);
             if !res.status.success() {
@@ -3497,14 +3529,14 @@ impl<'test> TestCx<'test> {
         let pm = self.pass_mode();
         let should_run = self.should_run(pm);
         let emit_metadata = self.should_emit_metadata(pm);
-        let proc_res = self.compile_test(should_run, emit_metadata);
+        let passes = self.get_passes();
 
+        let proc_res = self.compile_test_with_passes(should_run, emit_metadata, passes);
+        self.check_mir_dump();
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
-        self.check_mir_dump();
-
         if let WillExecute::Yes = should_run {
             let proc_res = self.exec_compiled_test();
 
@@ -3514,6 +3546,26 @@ impl<'test> TestCx<'test> {
         }
     }
 
+    fn get_passes(&self) -> Vec<String> {
+        let files = miropt_test_tools::files_for_miropt_test(
+            &self.testpaths.file,
+            self.config.get_pointer_width(),
+        );
+
+        let mut out = Vec::new();
+
+        for miropt_test_tools::MiroptTestFiles {
+            from_file: _,
+            to_file: _,
+            expected_file: _,
+            passes,
+        } in files
+        {
+            out.extend(passes);
+        }
+        out
+    }
+
     fn check_mir_dump(&self) {
         let test_file_contents = fs::read_to_string(&self.testpaths.file).unwrap();
 
@@ -3543,8 +3595,9 @@ impl<'test> TestCx<'test> {
             &self.testpaths.file,
             self.config.get_pointer_width(),
         );
-
-        for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file } in files {
+        for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file, passes: _ } in
+            files
+        {
             let dumped_string = if let Some(after) = to_file {
                 self.diff_mir_files(from_file.into(), after.into())
             } else {
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index e4ca40570b7..65bc004fc4a 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -286,11 +286,10 @@ fn main() {
     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
     let env_snapshot = env::vars_os().collect::<Vec<_>>();
 
-    // Earliest rustc setup.
-    rustc_driver::install_ice_hook();
-
     // If the environment asks us to actually be rustc, then do that.
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
+        // Earliest rustc setup.
+        rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
         rustc_driver::init_rustc_env_logger();
 
         let target_crate = if crate_kind == "target" {
@@ -309,6 +308,9 @@ fn main() {
         )
     }
 
+    // Add an ICE bug report hook.
+    rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
+
     // Init loggers the Miri way.
     init_early_loggers();
 
diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs
index cfba7d583b1..f86c3ce0afe 100644
--- a/src/tools/miropt-test-tools/src/lib.rs
+++ b/src/tools/miropt-test-tools/src/lib.rs
@@ -4,6 +4,8 @@ pub struct MiroptTestFiles {
     pub expected_file: std::path::PathBuf,
     pub from_file: String,
     pub to_file: Option<String>,
+    /// Vec of passes under test to be dumped
+    pub passes: Vec<String>,
 }
 
 pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<MiroptTestFiles> {
@@ -28,9 +30,11 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
             let mut expected_file;
             let from_file;
             let to_file;
+            let mut passes = Vec::new();
 
             if test_name.ends_with(".diff") {
                 let trimmed = test_name.trim_end_matches(".diff");
+                passes.push(trimmed.split('.').last().unwrap().to_owned());
                 let test_against = format!("{}.after.mir", trimmed);
                 from_file = format!("{}.before.mir", trimmed);
                 expected_file = format!("{}{}.diff", trimmed, bit_width);
@@ -38,7 +42,14 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
                 to_file = Some(test_against);
             } else if let Some(first_pass) = test_names.next() {
                 let second_pass = test_names.next().unwrap();
+                if let Some((first_pass_name, _)) = first_pass.split_once('.') {
+                    passes.push(first_pass_name.to_owned());
+                }
+                if let Some((second_pass_name, _)) = second_pass.split_once('.') {
+                    passes.push(second_pass_name.to_owned());
+                }
                 assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff");
+
                 expected_file =
                     format!("{}{}.{}-{}.diff", test_name, bit_width, first_pass, second_pass);
                 let second_file = format!("{}.{}.mir", test_name, second_pass);
@@ -51,18 +62,24 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
                     .next()
                     .expect("test_name has an invalid extension");
                 let extension = cap.get(1).unwrap().as_str();
+
                 expected_file =
                     format!("{}{}{}", test_name.trim_end_matches(extension), bit_width, extension,);
                 from_file = test_name.to_string();
                 assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump");
                 to_file = None;
+                // the pass name is the third to last string in the test name
+                // this gets pushed into passes
+                passes.push(
+                    test_name.split('.').rev().nth(2).expect("invalid test format").to_string(),
+                );
             };
             if !expected_file.starts_with(&test_crate) {
                 expected_file = format!("{}.{}", test_crate, expected_file);
             }
             let expected_file = test_dir.join(expected_file);
 
-            out.push(MiroptTestFiles { expected_file, from_file, to_file });
+            out.push(MiroptTestFiles { expected_file, from_file, to_file, passes });
         }
     }
 
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index be64559e877..47846424b06 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use anyhow::{format_err, Result};
 
 use io::Error as IoError;
@@ -19,7 +21,14 @@ use crate::rustfmt::{
     FormatReportFormatterBuilder, Input, Session, Verbosity,
 };
 
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rustfmt/issues/new?labels=bug";
+
+// N.B. these crates are loaded from the sysroot, so they need extern crate.
+extern crate rustc_driver;
+
 fn main() {
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |_| ());
+
     env_logger::Builder::from_env("RUSTFMT_LOG").init();
     let opts = make_opts();
 
diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs
index d8166ead8c4..a84e78254f2 100644
--- a/src/tools/suggest-tests/src/static_suggestions.rs
+++ b/src/tools/suggest-tests/src/static_suggestions.rs
@@ -15,7 +15,7 @@ static_suggestions! {
 
     "compiler/*" => [
         sug!("check"),
-        sug!("test", 1, ["src/test/ui", "src/test/run-make"])
+        sug!("test", 1, ["tests/ui", "tests/run-make"])
     ],
 
     "src/librustdoc/*" => [
diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs
index 5bc1a7df7ca..b4149136fa3 100644
--- a/src/tools/suggest-tests/src/tests.rs
+++ b/src/tools/suggest-tests/src/tests.rs
@@ -12,7 +12,7 @@ macro_rules! sugg_test {
 
 sugg_test! {
     test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] =>
-        ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test src/test/ui src/test/run-make 1"],
+        ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"],
 
     test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"],
 
diff --git a/tests/codegen/align-offset.rs b/tests/codegen/align-offset.rs
new file mode 100644
index 00000000000..7c7660c5a55
--- /dev/null
+++ b/tests/codegen/align-offset.rs
@@ -0,0 +1,78 @@
+// compile-flags: -O
+// min-llvm-version: 15.0 (because we're using opaque pointers)
+// ignore-debug (debug assertions in `slice::from_raw_parts` block optimizations)
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @align8
+#[no_mangle]
+pub fn align8(p: *const u8) -> bool {
+    // CHECK: ret i1 true
+    p.align_offset(8) < 8
+}
+
+#[repr(align(4))]
+pub struct Align4([u8; 4]);
+
+// CHECK-LABEL: @align_to4
+#[no_mangle]
+pub fn align_to4(x: &[u8]) -> bool {
+    // CHECK: ret i1 true
+    let (prefix, _middle, suffix) = unsafe { x.align_to::<Align4>() };
+    prefix.len() < 4 && suffix.len() < 4
+}
+
+// CHECK-LABEL: @align_offset_byte_ptr(ptr{{.+}}%ptr)
+#[no_mangle]
+pub fn align_offset_byte_ptr(ptr: *const u8) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE:i[0-9]+]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[OFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+
+    // Since we're offsetting a byte pointer, there's no further fixups
+    // CHECK-NOT: shr
+    // CHECK-NOT: div
+    // CHECK-NOT: select
+
+    // CHECK: ret [[USIZE]] %[[OFFSET]]
+    ptr.align_offset(32)
+}
+
+// CHECK-LABEL: @align_offset_word_slice(ptr{{.+}}align 4{{.+}}%slice.0
+#[no_mangle]
+pub fn align_offset_word_slice(slice: &[Align4]) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %slice.0 to [[USIZE]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+    // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2
+
+    // Slices are known to be aligned, so we don't need the "maybe -1" path
+    // CHECK-NOT: select
+
+    // CHECK: ret [[USIZE]] %[[OFFSET]]
+    slice.as_ptr().align_offset(32)
+}
+
+
+// CHECK-LABEL: @align_offset_word_ptr(ptr{{.+}}%ptr
+#[no_mangle]
+pub fn align_offset_word_ptr(ptr: *const Align4) -> usize {
+    // CHECK: %[[ADDR:.+]] = ptrtoint ptr %ptr to [[USIZE]]
+    // CHECK: %[[UP:.+]] = add [[USIZE]] %[[ADDR]], 31
+    // CHECK: %[[ALIGNED:.+]] = and [[USIZE]] %[[UP]], -32
+    // CHECK: %[[BOFFSET:.+]] = sub [[USIZE]] %[[ALIGNED]], %[[ADDR]]
+
+    // While we can always get a *byte* offset that will work, if the original
+    // pointer is unaligned it might be impossible to return an *element* offset
+    // that will make it aligned. We want it to be a `select`, not a `br`, so
+    // that the assembly will be branchless.
+    // CHECK: %[[LOW:.+]] = and [[USIZE]] %[[ADDR]], 3
+    // CHECK: %[[ORIGINAL_ALIGNED:.+]] = icmp eq [[USIZE]] %[[LOW]], 0
+    // CHECK: %[[OFFSET:.+]] = lshr exact [[USIZE]] %[[BOFFSET]], 2
+    // CHECK: %[[R:.+]] = select i1 %[[ORIGINAL_ALIGNED]], [[USIZE]] %[[OFFSET]], [[USIZE]] -1
+
+    // CHECK: ret [[USIZE]] %[[R]]
+    ptr.align_offset(32)
+}
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
index 9b69f79c28e..169e99deee7 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
@@ -21,42 +21,42 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 4) {
-    ╾─alloc18─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc19─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc18 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc5──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc19 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc6──╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc5 (size: 0, align: 4) {}
+alloc6 (size: 0, align: 4) {}
 
-alloc8 (size: 16, align: 4) {
-    ╾─alloc9──╼ 03 00 00 00 ╾─alloc10─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+alloc9 (size: 16, align: 4) {
+    ╾─alloc10─╼ 03 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ╾──╼....╾──╼....
 }
 
-alloc9 (size: 3, align: 1) {
+alloc10 (size: 3, align: 1) {
     66 6f 6f                                        │ foo
 }
 
-alloc10 (size: 3, align: 1) {
+alloc11 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc13 (size: 24, align: 4) {
-    0x00 │ ╾─alloc14─╼ 03 00 00 00 ╾─alloc15─╼ 03 00 00 00 │ ╾──╼....╾──╼....
-    0x10 │ ╾─alloc16─╼ 04 00 00 00                         │ ╾──╼....
+alloc14 (size: 24, align: 4) {
+    0x00 │ ╾─alloc15─╼ 03 00 00 00 ╾─alloc16─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    0x10 │ ╾─alloc17─╼ 04 00 00 00                         │ ╾──╼....
 }
 
-alloc14 (size: 3, align: 1) {
+alloc15 (size: 3, align: 1) {
     6d 65 68                                        │ meh
 }
 
-alloc15 (size: 3, align: 1) {
+alloc16 (size: 3, align: 1) {
     6d 6f 70                                        │ mop
 }
 
-alloc16 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     6d c3 b6 70                                     │ m..p
 }
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
index d0f196e7245..db1f9648843 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
@@ -21,46 +21,46 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc18───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc19───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc18 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc5────────╼ │ ....░░░░╾──────╼
+alloc19 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc6────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc9────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc14───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc5 (size: 0, align: 8) {}
+alloc6 (size: 0, align: 8) {}
 
-alloc8 (size: 32, align: 8) {
-    0x00 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc9 (size: 32, align: 8) {
+    0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc11───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc9 (size: 3, align: 1) {
+alloc10 (size: 3, align: 1) {
     66 6f 6f                                        │ foo
 }
 
-alloc10 (size: 3, align: 1) {
+alloc11 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc13 (size: 48, align: 8) {
-    0x00 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x20 │ ╾───────alloc16───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+alloc14 (size: 48, align: 8) {
+    0x00 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc16───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x20 │ ╾───────alloc17───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc14 (size: 3, align: 1) {
+alloc15 (size: 3, align: 1) {
     6d 65 68                                        │ meh
 }
 
-alloc15 (size: 3, align: 1) {
+alloc16 (size: 3, align: 1) {
     6d 6f 70                                        │ mop
 }
 
-alloc16 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     6d c3 b6 70                                     │ m..p
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
index aab005c52d6..999acb48afe 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
@@ -21,41 +21,41 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 4) {
-    ╾─alloc22─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc23─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc22 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc20─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc23 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc10─╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc15─╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc9 (size: 0, align: 4) {}
+alloc10 (size: 0, align: 4) {}
 
-alloc14 (size: 8, align: 4) {
-    ╾─alloc12─╼ ╾─alloc13─╼                         │ ╾──╼╾──╼
+alloc15 (size: 8, align: 4) {
+    ╾─alloc13─╼ ╾─alloc14─╼                         │ ╾──╼╾──╼
 }
 
-alloc12 (size: 1, align: 1) {
+alloc13 (size: 1, align: 1) {
     05                                              │ .
 }
 
-alloc13 (size: 1, align: 1) {
+alloc14 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc20 (size: 12, align: 4) {
-    ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a19+0x2─╼             │ ╾──╼╾──╼╾──╼
+alloc21 (size: 12, align: 4) {
+    ╾─a18+0x3─╼ ╾─alloc19─╼ ╾─a20+0x2─╼             │ ╾──╼╾──╼╾──╼
 }
 
-alloc17 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc18 (size: 1, align: 1) {
+alloc19 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc19 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
index 0eff9474c20..30311890eee 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
@@ -21,44 +21,44 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc22───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc22 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc9────────╼ │ ....░░░░╾──────╼
+alloc23 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc10───────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc20───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc15───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc9 (size: 0, align: 8) {}
+alloc10 (size: 0, align: 8) {}
 
-alloc14 (size: 16, align: 8) {
-    ╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼
+alloc15 (size: 16, align: 8) {
+    ╾───────alloc13───────╼ ╾───────alloc14───────╼ │ ╾──────╼╾──────╼
 }
 
-alloc12 (size: 1, align: 1) {
+alloc13 (size: 1, align: 1) {
     05                                              │ .
 }
 
-alloc13 (size: 1, align: 1) {
+alloc14 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc20 (size: 24, align: 8) {
-    0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼
-    0x10 │ ╾─────alloc19+0x2─────╼                         │ ╾──────╼
+alloc21 (size: 24, align: 8) {
+    0x00 │ ╾─────alloc18+0x3─────╼ ╾───────alloc19───────╼ │ ╾──────╼╾──────╼
+    0x10 │ ╾─────alloc20+0x2─────╼                         │ ╾──────╼
 }
 
-alloc17 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc18 (size: 1, align: 1) {
+alloc19 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc19 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
index 55c6db5d0ce..d592e59fafd 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
@@ -21,30 +21,30 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 4, align: 4) {
-    ╾─alloc11─╼                                     │ ╾──╼
+    ╾─alloc12─╼                                     │ ╾──╼
 }
 
-alloc11 (size: 168, align: 1) {
+alloc12 (size: 168, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc6──╼ │ ............╾──╼
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc7──╼ │ ............╾──╼
     0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc8──╼ 00 00 │ ..........╾──╼..
-    0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
+    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc9──╼ 00 00 │ ..........╾──╼..
+    0x90 │ ╾a10+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
     0xa0 │ 00 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc6 (size: 4, align: 4) {
+alloc7 (size: 4, align: 4) {
     2a 00 00 00                                     │ *...
 }
 
-alloc8 (fn: main)
+alloc9 (fn: main)
 
-alloc9 (size: 100, align: 1) {
+alloc10 (size: 100, align: 1) {
     0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
index 27492a7fd22..ca53b28be7c 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
@@ -21,12 +21,12 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 8) {
-    ╾───────alloc11───────╼                         │ ╾──────╼
+    ╾───────alloc12───────╼                         │ ╾──────╼
 }
 
-alloc11 (size: 180, align: 1) {
+alloc12 (size: 180, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc6── │ ............╾───
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc7── │ ............╾───
     0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
@@ -34,18 +34,18 @@ alloc11 (size: 180, align: 1) {
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
-    0x90 │ ─────alloc8─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼
+    0x90 │ ─────alloc9─────╼ 00 00 ╾────alloc10+0x63─────╼ │ ─────╼..╾──────╼
     0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0xb0 │ 00 00 00 00                                     │ ....
 }
 
-alloc6 (size: 4, align: 4) {
+alloc7 (size: 4, align: 4) {
     2a 00 00 00                                     │ *...
 }
 
-alloc8 (fn: main)
+alloc9 (fn: main)
 
-alloc9 (size: 100, align: 1) {
+alloc10 (size: 100, align: 1) {
     0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff
new file mode 100644
index 00000000000..d50b12044ce
--- /dev/null
+++ b/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff
@@ -0,0 +1,46 @@
+- // MIR for `fn0` before ConstProp
++ // MIR for `fn0` after ConstProp
+  
+  fn fn0() -> bool {
+      let mut _0: bool;                    // return place in scope 0 at $DIR/address_of_pair.rs:+0:17: +0:21
+      let mut _1: !;                       // in scope 0 at $DIR/address_of_pair.rs:+0:22: +9:2
+      let mut _2: (i32, bool);             // in scope 0 at $DIR/address_of_pair.rs:+1:9: +1:17
+      let _4: ();                          // in scope 0 at $DIR/address_of_pair.rs:+4:5: +6:6
+      let mut _6: bool;                    // in scope 0 at $DIR/address_of_pair.rs:+7:16: +7:22
+      scope 1 {
+          debug pair => _2;                // in scope 1 at $DIR/address_of_pair.rs:+1:9: +1:17
+          let _3: *mut bool;               // in scope 1 at $DIR/address_of_pair.rs:+2:9: +2:12
+          scope 2 {
+              debug ptr => _3;             // in scope 2 at $DIR/address_of_pair.rs:+2:9: +2:12
+              let _5: bool;                // in scope 2 at $DIR/address_of_pair.rs:+7:9: +7:12
+              scope 3 {
+              }
+              scope 4 {
+                  debug ret => _5;         // in scope 4 at $DIR/address_of_pair.rs:+7:9: +7:12
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/address_of_pair.rs:+1:9: +1:17
+          _2 = (const 1_i32, const false); // scope 0 at $DIR/address_of_pair.rs:+1:20: +1:30
+          StorageLive(_3);                 // scope 1 at $DIR/address_of_pair.rs:+2:9: +2:12
+          _3 = &raw mut (_2.1: bool);      // scope 1 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+          _2 = (const 1_i32, const false); // scope 2 at $DIR/address_of_pair.rs:+3:5: +3:22
+          StorageLive(_4);                 // scope 2 at $DIR/address_of_pair.rs:+4:5: +6:6
+          (*_3) = const true;              // scope 3 at $DIR/address_of_pair.rs:+5:9: +5:20
+          _4 = const ();                   // scope 3 at $DIR/address_of_pair.rs:+4:5: +6:6
+          StorageDead(_4);                 // scope 2 at $DIR/address_of_pair.rs:+6:5: +6:6
+          StorageLive(_5);                 // scope 2 at $DIR/address_of_pair.rs:+7:9: +7:12
+          StorageLive(_6);                 // scope 2 at $DIR/address_of_pair.rs:+7:16: +7:22
+          _6 = (_2.1: bool);               // scope 2 at $DIR/address_of_pair.rs:+7:16: +7:22
+          _5 = Not(move _6);               // scope 2 at $DIR/address_of_pair.rs:+7:15: +7:22
+          StorageDead(_6);                 // scope 2 at $DIR/address_of_pair.rs:+7:21: +7:22
+          _0 = _5;                         // scope 4 at $DIR/address_of_pair.rs:+8:12: +8:15
+          StorageDead(_5);                 // scope 2 at $DIR/address_of_pair.rs:+9:1: +9:2
+          StorageDead(_3);                 // scope 1 at $DIR/address_of_pair.rs:+9:1: +9:2
+          StorageDead(_2);                 // scope 0 at $DIR/address_of_pair.rs:+9:1: +9:2
+          return;                          // scope 0 at $DIR/address_of_pair.rs:+9:2: +9:2
+      }
+  }
+  
diff --git a/tests/mir-opt/const_prop/address_of_pair.rs b/tests/mir-opt/const_prop/address_of_pair.rs
new file mode 100644
index 00000000000..43dc9bae625
--- /dev/null
+++ b/tests/mir-opt/const_prop/address_of_pair.rs
@@ -0,0 +1,17 @@
+// unit-test: ConstProp
+
+// EMIT_MIR address_of_pair.fn0.ConstProp.diff
+pub fn fn0() -> bool {
+    let mut pair = (1, false);
+    let ptr = core::ptr::addr_of_mut!(pair.1);
+    pair = (1, false);
+    unsafe {
+        *ptr = true;
+    }
+    let ret = !pair.1;
+    return ret;
+}
+
+pub fn main() {
+    println!("{}", fn0());
+}
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
index bedfa5992ad..85d6b5e3d00 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
@@ -18,29 +18,35 @@
       }
   
       bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10
           _1 = const 0_i32;                // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11
--         _4 = Eq(_1, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+-         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+-         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb1: {
--         _5 = Eq(_1, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
--         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb2: {
--         _2 = Rem(const 1_i32, _1);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          _2 = Rem(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          StorageDead(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+          _0 = const ();                   // scope 0 at $DIR/bad_op_mod_by_zero.rs:+0:11: +3:2
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
+          StorageDead(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
index a1078472cbf..93d558250ea 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
 #[allow(unconditional_panic)]
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
index e711babf035..f63ee705d92 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
@@ -6,16 +6,17 @@
       let _1: *const [i32];                // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
       let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-      let _5: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-      let mut _6: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _8: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
+      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           scope 2 {
-              let _4: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               scope 3 {
-                  debug _b => _4;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               }
           }
       }
@@ -23,27 +24,31 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _9 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
-                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:9:25: 9:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _3 = &(*_9);                     // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
-          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         _7 = Lt(_5, _6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         _7 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _7 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
       }
   
       bb1: {
-          _4 = (*_1)[_5];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
-          StorageDead(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+          _0 = const ();                   // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
       }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
index e711babf035..f63ee705d92 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
@@ -6,16 +6,17 @@
       let _1: *const [i32];                // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
       let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-      let _5: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-      let mut _6: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _8: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
+      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           scope 2 {
-              let _4: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               scope 3 {
-                  debug _b => _4;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               }
           }
       }
@@ -23,27 +24,31 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _9 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
-                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:9:25: 9:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _3 = &(*_9);                     // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
-          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         _7 = Lt(_5, _6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         _7 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _7 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
       }
   
       bb1: {
-          _4 = (*_1)[_5];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
-          StorageDead(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+          _0 = const ();                   // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
       }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
index 3d252f2d221..ef148d16dc2 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
@@ -1,4 +1,7 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
+// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
+
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
 #[allow(unconditional_panic)]
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
index 85dedf68ce9..1752d222fe7 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
@@ -7,13 +7,17 @@
       let mut _2: main::InvalidChar;       // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
       let mut _4: E;                       // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
       let mut _5: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
+      let mut _7: Empty;                   // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
+      let mut _8: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
       scope 1 {
           debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
           let _3: [E; 1];                  // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
           scope 3 {
               debug _invalid_tag => _3;    // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
+              let _6: [Empty; 1];          // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
               scope 5 {
                   debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
+                  let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
                   scope 7 {
                       debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
                   }
@@ -39,17 +43,25 @@
           StorageLive(_5);                 // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
           _5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
 -         _4 = (_5.1: E);                  // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
--         _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
 +         _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
 +                                          // mir::Constant
 +                                          // + span: no-location
 +                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
-+         _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
-+                                          // mir::Constant
-+                                          // + span: no-location
-+                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
+          _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
           StorageDead(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
           StorageDead(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
+          StorageLive(_8);                 // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
+          _8 = NoVariants { int: const 0_u32 }; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
+          nop;                             // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
+          StorageDead(_8);                 // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
+          nop;                             // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+          nop;                             // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
+          nop;                             // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
           return;                          // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs
index eb6172cdff9..bdbc5a1990e 100644
--- a/tests/mir-opt/const_prop/invalid_constant.rs
+++ b/tests/mir-opt/const_prop/invalid_constant.rs
@@ -1,3 +1,5 @@
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+RemoveZsts
 // Verify that we can pretty print invalid constants.
 
 #![feature(adt_const_params)]
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
index 5331e5b8212..36336d967a9 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
@@ -18,17 +18,19 @@
           _2 = [const 0_u8; 5000];         // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29
           StorageLive(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
           _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
-          _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
+-         _4 = Len(_2);                    // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 +         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
       }
   
       bb1: {
           _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
           StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
           StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
+          _0 = const ();                   // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
       }
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
index 5331e5b8212..36336d967a9 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
@@ -18,17 +18,19 @@
           _2 = [const 0_u8; 5000];         // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29
           StorageLive(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
           _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
-          _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
+-         _4 = Len(_2);                    // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 +         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
       }
   
       bb1: {
           _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
           StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
           StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
+          _0 = const ();                   // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
       }
diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs
index 073f9849568..0876445bf2c 100644
--- a/tests/mir-opt/const_prop/large_array_index.rs
+++ b/tests/mir-opt/const_prop/large_array_index.rs
@@ -1,4 +1,6 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
+// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR large_array_index.main.ConstProp.diff
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
index 15c93f270d7..077b9bf8304 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
@@ -3,21 +3,26 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +0:11
-      let mut _1: usize;                   // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-      let mut _2: fn();                    // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+      let mut _1: *const fn();             // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
+      let mut _2: usize;                   // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+      let mut _3: fn();                    // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
       scope 1 {
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-          StorageLive(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
-          _2 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+          StorageLive(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
+          StorageLive(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+          StorageLive(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+          _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
                                            // mir::Constant
-                                           // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
+                                           // + span: $DIR/reify_fn_ptr.rs:5:13: 5:17
                                            // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
-          _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-          StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
-          StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
+          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+          StorageDead(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
+          _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
+          StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
+          StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:41: +1:42
+          _0 = const ();                   // scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/reify_fn_ptr.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index bfe2563ad8a..5f63820669b 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR reify_fn_ptr.main.ConstProp.diff
 
 fn main() {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
index 636032adb81..6641220db69 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];          // scope 0 at $DIR/repeat.rs:+1:18: +1:25
           StorageLive(_4);                 // scope 0 at $DIR/repeat.rs:+1:26: +1:27
           _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:+1:26: +1:27
-          _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
+-         _5 = Len(_3);                    // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         _6 = Lt(_4, _5);                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 +         _6 = const true;                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
       }
   
       bb1: {
@@ -35,6 +36,7 @@
           StorageDead(_2);                 // scope 0 at $DIR/repeat.rs:+1:31: +1:32
           StorageDead(_4);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
+          _0 = const ();                   // scope 0 at $DIR/repeat.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/repeat.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/repeat.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
index 636032adb81..6641220db69 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];          // scope 0 at $DIR/repeat.rs:+1:18: +1:25
           StorageLive(_4);                 // scope 0 at $DIR/repeat.rs:+1:26: +1:27
           _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:+1:26: +1:27
-          _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
+-         _5 = Len(_3);                    // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         _6 = Lt(_4, _5);                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 +         _6 = const true;                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
       }
   
       bb1: {
@@ -35,6 +36,7 @@
           StorageDead(_2);                 // scope 0 at $DIR/repeat.rs:+1:31: +1:32
           StorageDead(_4);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
+          _0 = const ();                   // scope 0 at $DIR/repeat.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/repeat.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/repeat.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs
index 2f3b7d2c502..9c11dbc5b66 100644
--- a/tests/mir-opt/const_prop/repeat.rs
+++ b/tests/mir-opt/const_prop/repeat.rs
@@ -1,7 +1,8 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
-// compile-flags: -O
-
+// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR repeat.main.ConstProp.diff
 fn main() {
     let x: u32 = [42; 8][2] + 0;
diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir
index ececd994283..b12d84fa479 100644
--- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir
+++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir
@@ -2,8 +2,14 @@
 
 fn add() -> u32 {
     let mut _0: u32;                     // return place in scope 0 at $DIR/return_place.rs:+0:13: +0:16
+    let mut _1: (u32, bool);             // in scope 0 at $DIR/return_place.rs:+1:5: +1:10
 
     bb0: {
+        _1 = const (4_u32, false);       // scope 0 at $DIR/return_place.rs:+1:5: +1:10
+        assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:+1:5: +1:10
+    }
+
+    bb1: {
         _0 = const 4_u32;                // scope 0 at $DIR/return_place.rs:+1:5: +1:10
         return;                          // scope 0 at $DIR/return_place.rs:+2:2: +2:2
     }
diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs
index ae119df8518..0e68309f036 100644
--- a/tests/mir-opt/const_prop/return_place.rs
+++ b/tests/mir-opt/const_prop/return_place.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -C overflow-checks=on
 
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
index a091b4ace20..c2f97a0f622 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
@@ -11,15 +11,23 @@
       }
   
       bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10
           _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
--         _2 = consume(_1) -> bb1;         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-+         _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
+          StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
+          StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+-         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
++         _3 = const 1_u32;                // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+          _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
                                            // mir::Constant
-                                           // + span: $DIR/scalar_literal_propagation.rs:5:5: 5:12
+                                           // + span: $DIR/scalar_literal_propagation.rs:6:5: 6:12
                                            // + literal: Const { ty: fn(u32) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
+          StorageDead(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
+          StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
+          _0 = const ();                   // scope 0 at $DIR/scalar_literal_propagation.rs:+0:11: +3:2
+          StorageDead(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
       }
   }
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.rs b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
index e13e352f8a1..fc33cc2d021 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR scalar_literal_propagation.main.ConstProp.diff
 fn main() {
diff --git a/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff b/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
index 85704c48a2c..664b7839ffc 100644
--- a/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
@@ -15,14 +15,14 @@
       bb1: {
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:+3:14: +3:21
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:10:14: 10:17
+                                           // + span: $DIR/switch_int.rs:12:14: 12:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:+2:14: +2:20
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:9:14: 9:17
+                                           // + span: $DIR/switch_int.rs:11:14: 11:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
index 0864db22523..ef2c4d5faa6 100644
--- a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
@@ -15,14 +15,14 @@
       bb1: {
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:+3:14: +3:21
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:10:14: 10:17
+                                           // + span: $DIR/switch_int.rs:12:14: 12:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:+2:14: +2:20
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:9:14: 9:17
+                                           // + span: $DIR/switch_int.rs:11:14: 11:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/const_prop/switch_int.rs b/tests/mir-opt/const_prop/switch_int.rs
index 2a2322e43a9..7158ea4d2bd 100644
--- a/tests/mir-opt/const_prop/switch_int.rs
+++ b/tests/mir-opt/const_prop/switch_int.rs
@@ -1,3 +1,5 @@
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+SimplifyConstCondition-after-const-prop
 // ignore-wasm32 compiled with panic=abort by default
 #[inline(never)]
 fn foo(_: i32) { }
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index 12313b6c58d..e4a7c0d1e72 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -11,15 +11,24 @@
       }
   
       bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:+1:9: +1:10
 -         _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
 +         _1 = const (1_u32, 2_u32);       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
-          _2 = consume(_1) -> bb1;         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
+          StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
+          StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
+-         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
++         _3 = const (1_u32, 2_u32);       // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
+          _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
                                            // mir::Constant
-                                           // + span: $DIR/tuple_literal_propagation.rs:6:5: 6:12
+                                           // + span: $DIR/tuple_literal_propagation.rs:7:5: 7:12
                                            // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
+          StorageDead(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:14: +3:15
+          StorageDead(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
+          _0 = const ();                   // scope 0 at $DIR/tuple_literal_propagation.rs:+0:11: +4:2
+          StorageDead(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
       }
   }
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
index edd748d00ab..f342ae2700e 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR tuple_literal_propagation.main.ConstProp.diff
 fn main() {
diff --git a/tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff b/tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff
index a4f2d8c84d8..37732421870 100644
--- a/tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
+++ b/tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff
@@ -4,8 +4,13 @@
   fn change_loop_body() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
       let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-      let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
-      let mut _3: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
+      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
+      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
+      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
+      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
+      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
           scope 2 {
@@ -15,29 +20,33 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
           _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
-          StorageLive(_2);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          _2 = Option::<u32>::None;        // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
--         _3 = discriminant(_2);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _3) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         _3 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          StorageLive(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+          _3 = Option::<u32>::None;        // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+-         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+-         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
 +         switchInt(const 0_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb1: {
-          switchInt(((_2 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb2: {
           _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
+          _0 = const ();                   // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
           goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
       }
   
       bb3: {
+          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+          _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
           goto -> bb4;                     // scope 1 at no-location
       }
   
       bb4: {
-          StorageDead(_2);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
           StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
       }
diff --git a/tests/mir-opt/while_let_loops.rs b/tests/mir-opt/const_prop/while_let_loops.rs
index fc56cd6985d..595a94b88be 100644
--- a/tests/mir-opt/while_let_loops.rs
+++ b/tests/mir-opt/const_prop/while_let_loops.rs
@@ -1,5 +1,5 @@
+// unit-test: ConstProp
 // EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
-// EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir
 
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
index def9fc6428f..a5f52d08957 100644
--- a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
+++ b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
@@ -19,8 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
--         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-+         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
+          _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
           StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
           _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
diff --git a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
index b54c10a140f..42ddc2a5620 100644
--- a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
+++ b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
@@ -16,8 +16,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
--         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-+         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
+          _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14
           _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14
           (*_2) = const 5_i32;             // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +2:18
diff --git a/tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir b/tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
deleted file mode 100644
index 15b0aece8f5..00000000000
--- a/tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-    scope 1 {
-        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-        return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-    }
-}
diff --git a/tests/run-make/issue-109934-lto-debuginfo/Makefile b/tests/run-make/issue-109934-lto-debuginfo/Makefile
new file mode 100644
index 00000000000..3b7a99d3dbc
--- /dev/null
+++ b/tests/run-make/issue-109934-lto-debuginfo/Makefile
@@ -0,0 +1,12 @@
+# ignore-cross-compile
+include ../tools.mk
+
+# With the upgrade to LLVM 16, this was getting:
+#
+#   error: Cannot represent a difference across sections
+#
+# The error stemmed from DI function definitions under type scopes, fixed by
+# only declaring in type scope and defining the subprogram elsewhere.
+
+all:
+	$(RUSTC) lib.rs --test -C lto=fat -C debuginfo=2 -C incremental=$(TMPDIR)/inc-fat
diff --git a/tests/run-make/issue-109934-lto-debuginfo/lib.rs b/tests/run-make/issue-109934-lto-debuginfo/lib.rs
new file mode 100644
index 00000000000..c405928bd18
--- /dev/null
+++ b/tests/run-make/issue-109934-lto-debuginfo/lib.rs
@@ -0,0 +1,9 @@
+extern crate alloc;
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn something_alloc() {
+        assert_eq!(Vec::<u32>::new(), Vec::<u32>::new());
+    }
+}
diff --git a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
index 22f222c12c3..dcb5fee9ecc 100644
--- a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -1,5 +1,4 @@
 #![feature(abi_vectorcall)]
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[repr(C)]
 #[derive(Clone)]
diff --git a/tests/run-make/raw-dylib-c/lib.rs b/tests/run-make/raw-dylib-c/lib.rs
index 5fb1204037c..f17125f308c 100644
--- a/tests/run-make/raw-dylib-c/lib.rs
+++ b/tests/run-make/raw-dylib-c/lib.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 #[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
 extern {
     fn extern_fn_1();
diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs
index 51bf2ec6b6e..3338ac0a0b5 100644
--- a/tests/run-make/raw-dylib-cross-compilation/lib.rs
+++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs
@@ -1,4 +1,3 @@
-#![feature(raw_dylib)]
 #![feature(no_core, lang_items)]
 #![no_std]
 #![no_core]
diff --git a/tests/run-make/raw-dylib-custom-dlltool/Makefile b/tests/run-make/raw-dylib-custom-dlltool/Makefile
new file mode 100644
index 00000000000..f5d5360a3fb
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/Makefile
@@ -0,0 +1,11 @@
+# Test using -Cdlltool to change where raw-dylib looks for the dlltool binary.
+
+# only-windows
+# only-gnu
+# needs-dlltool
+
+include ../tools.mk
+
+all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs -Cdlltool=$(CURDIR)/script.cmd
+	$(DIFF) output.txt "$(TMPDIR)"/output.txt
diff --git a/tests/run-make/raw-dylib-custom-dlltool/lib.rs b/tests/run-make/raw-dylib-custom-dlltool/lib.rs
new file mode 100644
index 00000000000..2f3f497a00d
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/lib.rs
@@ -0,0 +1,10 @@
+#[link(name = "extern_1", kind = "raw-dylib")]
+extern {
+    fn extern_fn_1();
+}
+
+pub fn library_function() {
+    unsafe {
+        extern_fn_1();
+    }
+}
diff --git a/tests/run-make/raw-dylib-custom-dlltool/output.txt b/tests/run-make/raw-dylib-custom-dlltool/output.txt
new file mode 100644
index 00000000000..6dd9466d26d
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/output.txt
@@ -0,0 +1 @@
+Called dlltool via script.cmd
diff --git a/tests/run-make/raw-dylib-custom-dlltool/script.cmd b/tests/run-make/raw-dylib-custom-dlltool/script.cmd
new file mode 100644
index 00000000000..95f85c61c67
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/script.cmd
@@ -0,0 +1,2 @@
+echo Called dlltool via script.cmd> %TMPDIR%\output.txt
+dlltool.exe %*
diff --git a/tests/run-make/raw-dylib-import-name-type/driver.rs b/tests/run-make/raw-dylib-import-name-type/driver.rs
index 9a3cd9ebe1b..6c1c212f187 100644
--- a/tests/run-make/raw-dylib-import-name-type/driver.rs
+++ b/tests/run-make/raw-dylib-import-name-type/driver.rs
@@ -1,4 +1,3 @@
-#![feature(raw_dylib)]
 #![feature(abi_vectorcall)]
 
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
index f72ded7d9f6..0c3125be6f5 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 extern crate raw_dylib_test;
 extern crate raw_dylib_test_wrapper;
 
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
index 00c2c1c42d1..4877cb80aea 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 #[link(name = "extern_1", kind = "raw-dylib")]
 extern {
     fn extern_fn_1();
diff --git a/tests/run-make/raw-dylib-link-ordinal/lib.rs b/tests/run-make/raw-dylib-link-ordinal/lib.rs
index bb25ac64c61..1bbb45bbc77 100644
--- a/tests/run-make/raw-dylib-link-ordinal/lib.rs
+++ b/tests/run-make/raw-dylib-link-ordinal/lib.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "exporter", kind = "raw-dylib")]
 extern {
     #[link_ordinal(13)]
diff --git a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
index b7921396a0f..74c5c7f8250 100644
--- a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
+++ b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "exporter", kind = "raw-dylib")]
 extern "stdcall" {
     #[link_ordinal(15)]
diff --git a/tests/rustdoc-js/slice-array.js b/tests/rustdoc-js/slice-array.js
new file mode 100644
index 00000000000..8c21e06dc4e
--- /dev/null
+++ b/tests/rustdoc-js/slice-array.js
@@ -0,0 +1,65 @@
+// exact-check
+
+const QUERY = [
+    'R<primitive:slice<P>>',
+    'primitive:slice<R<P>>',
+    'R<primitive:slice<Q>>',
+    'primitive:slice<R<Q>>',
+    'R<primitive:array<Q>>',
+    'primitive:array<R<Q>>',
+    'primitive:array<TraitCat>',
+    'primitive:array<TraitDog>',
+];
+
+const EXPECTED = [
+    {
+        // R<primitive:slice<P>>
+        'returned': [],
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'alpha' },
+        ],
+    },
+    {
+        // primitive:slice<R<P>>
+        'returned': [
+            { 'path': 'slice_array', 'name': 'alef' },
+        ],
+        'in_args': [],
+    },
+    {
+        // R<primitive:slice<Q>>
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        // primitive:slice<R<Q>>
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        // R<primitive:array<Q>>
+        'returned': [
+            { 'path': 'slice_array', 'name': 'bet' },
+        ],
+        'in_args': [],
+    },
+    {
+        // primitive:array<R<Q>>
+        'returned': [],
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'beta' },
+        ],
+    },
+    {
+        // primitive::array<TraitCat>
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'gamma' },
+        ],
+    },
+    {
+        // primitive::array<TraitDog>
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'gamma' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/slice-array.rs b/tests/rustdoc-js/slice-array.rs
new file mode 100644
index 00000000000..2523b21cfaa
--- /dev/null
+++ b/tests/rustdoc-js/slice-array.rs
@@ -0,0 +1,16 @@
+pub struct P;
+pub struct Q;
+pub struct R<T>(T);
+
+// returns test
+pub fn alef() -> &'static [R<P>] { loop {} }
+pub fn bet() -> R<[Q; 32]> { loop {} }
+
+// in_args test
+pub fn alpha(_x: R<&'static [P]>) { loop {} }
+pub fn beta(_x: [R<Q>; 32]) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: [T; 32]) {}
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.stderr b/tests/rustdoc-ui/check-cfg/check-cfg.stderr
index 1db8e1d91c2..03fb6f96fb5 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg.stderr
+++ b/tests/rustdoc-ui/check-cfg/check-cfg.stderr
@@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name
   --> $DIR/check-cfg.rs:5:7
    |
 LL | #[cfg(uniz)]
-   |       ^^^^ help: did you mean: `unix`
+   |       ^^^^ help: there is a config with a similar name: `unix`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.stderr b/tests/rustdoc-ui/doctest/check-cfg-test.stderr
index 9770be2f191..f84543c2072 100644
--- a/tests/rustdoc-ui/doctest/check-cfg-test.stderr
+++ b/tests/rustdoc-ui/doctest/check-cfg-test.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "invalid")]
    |       ^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: test
+   = note: expected values for `feature` are: `test`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/rustdoc-ui/ice-bug-report-url.rs b/tests/rustdoc-ui/ice-bug-report-url.rs
new file mode 100644
index 00000000000..cc066447d31
--- /dev/null
+++ b/tests/rustdoc-ui/ice-bug-report-url.rs
@@ -0,0 +1,14 @@
+// compile-flags: -Ztreat-err-as-bug
+// failure-status: 101
+// error-pattern: aborting due to
+// error-pattern: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
+
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}"
+// normalize-stderr-test "thread.*panicked at .*, compiler.*" -> "thread panicked at 'aborting due to `-Z treat-err-as-bug`'"
+// normalize-stderr-test "\s*\d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s at .*\n" -> ""
+// normalize-stderr-test ".*note: Some details are omitted.*\n" -> ""
+
+fn wrong()
+//~^ ERROR expected one of
diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr
new file mode 100644
index 00000000000..cfb73a9b919
--- /dev/null
+++ b/tests/rustdoc-ui/ice-bug-report-url.stderr
@@ -0,0 +1,16 @@
+error: expected one of `->`, `where`, or `{`, found `<eof>`
+  --> $DIR/ice-bug-report-url.rs:13:10
+   |
+LL | fn wrong()
+   |          ^ expected one of `->`, `where`, or `{`
+
+thread panicked at 'aborting due to `-Z treat-err-as-bug`'
+stack backtrace:
+error: the compiler unexpectedly panicked. this is a bug.
+
+note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
+
+note: rustc {version} running on {platform}
+
+query stack during panic:
+end of query stack
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 95f27efa771..1454d6dde6c 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -60,6 +60,24 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
         stable_mir::mir::Terminator::Call { .. } => {}
         other => panic!("{other:?}"),
     }
+
+    let drop = get_item(tcx, &items, (DefKind::Fn, "drop")).unwrap();
+    let body = drop.body();
+    assert_eq!(body.blocks.len(), 2);
+    let block = &body.blocks[0];
+    match &block.terminator {
+        stable_mir::mir::Terminator::Drop { .. } => {}
+        other => panic!("{other:?}"),
+    }
+
+    let assert = get_item(tcx, &items, (DefKind::Fn, "assert")).unwrap();
+    let body = assert.body();
+    assert_eq!(body.blocks.len(), 2);
+    let block = &body.blocks[0];
+    match &block.terminator {
+        stable_mir::mir::Terminator::Assert { .. } => {}
+        other => panic!("{other:?}"),
+    }
 }
 
 // Use internal API to find a function in a crate.
@@ -131,6 +149,12 @@ fn generate_input(path: &str) -> std::io::Result<()> {
         let x_64 = foo::bar(x);
         let y_64 = foo::bar(y);
         x_64.wrapping_add(y_64)
+    }}
+
+    pub fn drop(_: String) {{}}
+
+    pub fn assert(x: i32) -> i32 {{
+        x + 1
     }}"#
     )?;
     Ok(())
diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr
index 5ca4d3b3de7..70a967c0e5f 100644
--- a/tests/ui/check-cfg/compact-values.stderr
+++ b/tests/ui/check-cfg/compact-values.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target(os = "linux", arch = "X"))]
    |                            ^^^^^^^^^^
    |
-   = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, loongarch64, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64
+   = note: expected values for `target_arch` are: `aarch64`, `arm`, `avr`, `bpf`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips64`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
new file mode 100644
index 00000000000..49e127d079a
--- /dev/null
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -0,0 +1,31 @@
+// check-pass
+// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --check-cfg=values(no_values) -Z unstable-options
+
+#[cfg(featur)]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(featur = "foo")]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(featur = "fo")]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(feature = "foo")]
+fn feature() {}
+
+#[cfg(no_value)]
+//~^ WARNING unexpected `cfg` condition name
+fn no_values() {}
+
+#[cfg(no_value = "foo")]
+//~^ WARNING unexpected `cfg` condition name
+fn no_values() {}
+
+#[cfg(no_values = "bar")]
+//~^ WARNING unexpected `cfg` condition value
+fn no_values() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/diagnotics.stderr b/tests/ui/check-cfg/diagnotics.stderr
new file mode 100644
index 00000000000..8b9fef09d09
--- /dev/null
+++ b/tests/ui/check-cfg/diagnotics.stderr
@@ -0,0 +1,62 @@
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:4:7
+   |
+LL | #[cfg(featur)]
+   |       ^^^^^^ help: there is a config with a similar name: `feature`
+   |
+   = help: expected values for `feature` are: `foo`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:8:7
+   |
+LL | #[cfg(featur = "foo")]
+   |       ^^^^^^^^^^^^^^
+   |
+   = help: expected values for `feature` are: `foo`
+help: there is a config with a similar name and value
+   |
+LL | #[cfg(feature = "foo")]
+   |       ~~~~~~~
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:12:7
+   |
+LL | #[cfg(featur = "fo")]
+   |       ^^^^^^^^^^^^^
+   |
+   = help: expected values for `feature` are: `foo`
+help: there is a config with a similar name and different values
+   |
+LL | #[cfg(feature = "foo")]
+   |       ~~~~~~~~~~~~~~~
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:19:7
+   |
+LL | #[cfg(no_value)]
+   |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:23:7
+   |
+LL | #[cfg(no_value = "foo")]
+   |       ^^^^^^^^^^^^^^^^
+   |
+help: there is a config with a similar name and no value
+   |
+LL | #[cfg(no_values)]
+   |       ~~~~~~~~~
+
+warning: unexpected `cfg` condition value
+  --> $DIR/diagnotics.rs:27:7
+   |
+LL | #[cfg(no_values = "bar")]
+   |       ^^^^^^^^^--------
+   |                |
+   |                help: remove the value
+   |
+   = note: no expected value for `no_values`
+
+warning: 6 warnings emitted
+
diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/invalid-cfg-name.stderr
index 2bd1821c942..ed09f8cb66d 100644
--- a/tests/ui/check-cfg/invalid-cfg-name.stderr
+++ b/tests/ui/check-cfg/invalid-cfg-name.stderr
@@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name
   --> $DIR/invalid-cfg-name.rs:7:7
    |
 LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: did you mean: `windows`
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/invalid-cfg-value.stderr
index 83383ea61a4..776d264a7ad 100644
--- a/tests/ui/check-cfg/invalid-cfg-value.stderr
+++ b/tests/ui/check-cfg/invalid-cfg-value.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "sedre")]
    |       ^^^^^^^^^^-------
    |                 |
-   |                 help: did you mean: `"serde"`
+   |                 help: there is a expected value with a similar name: `"serde"`
    |
-   = note: expected values for `feature` are: full, serde
+   = note: expected values for `feature` are: `full`, `serde`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: full, serde
+   = note: expected values for `feature` are: `full`, `serde`
 
 warning: unexpected condition value `rand` for condition name `feature`
    |
diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs
index 4e488fc03ec..9adf5c46e43 100644
--- a/tests/ui/check-cfg/mix.rs
+++ b/tests/ui/check-cfg/mix.rs
@@ -12,6 +12,10 @@ fn do_windows_stuff() {}
 //~^ WARNING unexpected `cfg` condition name
 fn do_windows_stuff() {}
 
+#[cfg(feature)]
+//~^ WARNING unexpected `cfg` condition value
+fn no_feature() {}
+
 #[cfg(feature = "foo")]
 fn use_foo() {}
 
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 9cf887ec788..07c514aed52 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -2,28 +2,36 @@ warning: unexpected `cfg` condition name
   --> $DIR/mix.rs:11:7
    |
 LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: did you mean: `windows`
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:18:7
+  --> $DIR/mix.rs:15:7
+   |
+LL | #[cfg(feature)]
+   |       ^^^^^^^- help: specify a config value: `= "foo"`
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:22:7
    |
 LL | #[cfg(feature = "bar")]
    |       ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:22:7
+  --> $DIR/mix.rs:26:7
    |
 LL | #[cfg(feature = "zebra")]
    |       ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:26:12
+  --> $DIR/mix.rs:30:12
    |
 LL | #[cfg_attr(uu, test)]
    |            ^^
@@ -37,146 +45,146 @@ warning: unexpected `unknown_name` as condition name
    = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:35:10
+  --> $DIR/mix.rs:39:10
    |
 LL |     cfg!(widnows);
-   |          ^^^^^^^ help: did you mean: `windows`
+   |          ^^^^^^^ help: there is a config with a similar name: `windows`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:38:10
+  --> $DIR/mix.rs:42:10
    |
 LL |     cfg!(feature = "bar");
    |          ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:40:10
+  --> $DIR/mix.rs:44:10
    |
 LL |     cfg!(feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:42:10
+  --> $DIR/mix.rs:46:10
    |
 LL |     cfg!(xxx = "foo");
    |          ^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:44:10
+  --> $DIR/mix.rs:48:10
    |
 LL |     cfg!(xxx);
    |          ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:46:14
+  --> $DIR/mix.rs:50:14
    |
 LL |     cfg!(any(xxx, windows));
    |              ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:48:14
+  --> $DIR/mix.rs:52:14
    |
 LL |     cfg!(any(feature = "bad", windows));
    |              ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:50:23
+  --> $DIR/mix.rs:54:23
    |
 LL |     cfg!(any(windows, xxx));
    |                       ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:52:20
+  --> $DIR/mix.rs:56:20
    |
 LL |     cfg!(all(unix, xxx));
    |                    ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:54:14
+  --> $DIR/mix.rs:58:14
    |
 LL |     cfg!(all(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:54:18
+  --> $DIR/mix.rs:58:18
    |
 LL |     cfg!(all(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:57:14
+  --> $DIR/mix.rs:61:14
    |
 LL |     cfg!(any(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:57:18
+  --> $DIR/mix.rs:61:18
    |
 LL |     cfg!(any(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:60:20
+  --> $DIR/mix.rs:64:20
    |
 LL |     cfg!(any(unix, feature = "zebra"));
    |                    ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:62:14
+  --> $DIR/mix.rs:66:14
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |              ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:62:19
+  --> $DIR/mix.rs:66:19
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |                   ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:65:14
+  --> $DIR/mix.rs:69:14
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |              ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:65:25
+  --> $DIR/mix.rs:69:25
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |                         ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:14
+  --> $DIR/mix.rs:72:14
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |              ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:33
+  --> $DIR/mix.rs:72:33
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                 ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:52
+  --> $DIR/mix.rs:72:52
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                                    ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
-warning: 27 warnings emitted
+warning: 28 warnings emitted
 
diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-values.stderr
index 8c926d187fe..ffa87dc58f2 100644
--- a/tests/ui/check-cfg/no-values.stderr
+++ b/tests/ui/check-cfg/no-values.stderr
@@ -2,7 +2,9 @@ warning: unexpected `cfg` condition value
   --> $DIR/no-values.rs:6:7
    |
 LL | #[cfg(feature = "foo")]
-   |       ^^^^^^^^^^^^^^^
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
    |
    = note: no expected value for `feature`
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr
index b58d2970773..eb81535e3ed 100644
--- a/tests/ui/check-cfg/values-target-json.stderr
+++ b/tests/ui/check-cfg/values-target-json.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_os = "linuz")]
    |       ^^^^^^^^^^^^-------
    |                   |
-   |                   help: did you mean: `"linux"`
+   |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, ericos, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index bdbe4d29d30..34c5d6172d9 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name
 LL | #[cfg(target_oz = "linux")]
    |       ---------^^^^^^^^^^
    |       |
-   |       help: did you mean: `target_os`
+   |       help: there is a config with a similar name: `target_os`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
@@ -14,13 +14,13 @@ warning: unexpected `cfg` condition name
 LL | #[cfg(features = "foo")]
    |       --------^^^^^^^^
    |       |
-   |       help: did you mean: `feature`
+   |       help: there is a config with a similar name: `feature`
 
 warning: unexpected `cfg` condition name
   --> $DIR/well-known-names.rs:20:7
    |
 LL | #[cfg(uniw)]
-   |       ^^^^ help: did you mean: `unix`
+   |       ^^^^ help: there is a config with a similar name: `unix`
 
 warning: 3 warnings emitted
 
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 69d799783a9..2d18cb82e03 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_os = "linuz")]
    |       ^^^^^^^^^^^^-------
    |                   |
-   |                   help: did you mean: `"linux"`
+   |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
@@ -15,9 +15,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_has_atomic = "0")]
    |       ^^^^^^^^^^^^^^^^^^^^---
    |                           |
-   |                           help: did you mean: `"8"`
+   |                           help: there is a expected value with a similar name: `"8"`
    |
-   = note: expected values for `target_has_atomic` are: 128, 16, 32, 64, 8, ptr
+   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
 
 warning: unexpected `cfg` condition value
   --> $DIR/well-known-values.rs:21:7
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad1.stderr b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
new file mode 100644
index 00000000000..3b506c7e7ec
--- /dev/null
+++ b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:27:18
+   |
+LL | impl<T> Drop for DropMe<T>
+   |                  ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider further restricting type parameter `T`
+   |
+LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
+   |                 ~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:32:13
+   |
+LL |     fn drop(&mut self) {}
+   |             ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider further restricting type parameter `T`
+   |
+LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
+   |                 ~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad2.stderr b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
new file mode 100644
index 00000000000..832af3e521a
--- /dev/null
+++ b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:37:18
+   |
+LL | impl<T> Drop for DropMe<T>
+   |                  ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::marker::Copy> Drop for DropMe<T>
+   |       +++++++++++++++++++
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:40:13
+   |
+LL |     fn drop(&mut self) {}
+   |             ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::marker::Copy> Drop for DropMe<T>
+   |       +++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dropck/explicit-drop-bounds.rs b/tests/ui/dropck/explicit-drop-bounds.rs
new file mode 100644
index 00000000000..ab6f33c0999
--- /dev/null
+++ b/tests/ui/dropck/explicit-drop-bounds.rs
@@ -0,0 +1,44 @@
+// revisions: good1 good2 bad1 bad2
+//[good1] check-pass
+//[good2] check-pass
+
+use std::ops::Drop;
+
+struct DropMe<T: Copy>(T);
+
+#[cfg(good1)]
+impl<T> Drop for DropMe<T>
+where
+    T: Copy + Clone,
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good2)]
+impl<T> Drop for DropMe<T>
+where
+    T: Copy,
+    [T; 1]: Copy, // Trivial bound implied by `T: Copy`
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad1)]
+impl<T> Drop for DropMe<T>
+//[bad1]~^ ERROR the trait bound `T: Copy` is not satisfied
+where
+    [T; 1]: Copy, // But `[T; 1]: Copy` does not imply `T: Copy`
+{
+    fn drop(&mut self) {}
+    //[bad1]~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+#[cfg(bad2)]
+impl<T> Drop for DropMe<T>
+//[bad2]~^ ERROR the trait bound `T: Copy` is not satisfied
+{
+    fn drop(&mut self) {}
+    //[bad2]~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/explicit-implied-outlives.bad1.stderr b/tests/ui/dropck/explicit-implied-outlives.bad1.stderr
new file mode 100644
index 00000000000..bf6d70e7d37
--- /dev/null
+++ b/tests/ui/dropck/explicit-implied-outlives.bad1.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
+  --> $DIR/explicit-implied-outlives.rs:28:8
+   |
+LL |     T: 'static,
+   |        ^^^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/explicit-implied-outlives.rs:7:1
+   |
+LL | struct DropMe<'a, T>(&'a T);
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/dropck/explicit-implied-outlives.bad2.stderr b/tests/ui/dropck/explicit-implied-outlives.bad2.stderr
new file mode 100644
index 00000000000..27a15170bdd
--- /dev/null
+++ b/tests/ui/dropck/explicit-implied-outlives.bad2.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `'a: 'static` but the struct it is implemented for does not
+  --> $DIR/explicit-implied-outlives.rs:37:9
+   |
+LL |     'a: 'static,
+   |         ^^^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/explicit-implied-outlives.rs:7:1
+   |
+LL | struct DropMe<'a, T>(&'a T);
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/dropck/explicit-implied-outlives.rs b/tests/ui/dropck/explicit-implied-outlives.rs
new file mode 100644
index 00000000000..fa446591f3d
--- /dev/null
+++ b/tests/ui/dropck/explicit-implied-outlives.rs
@@ -0,0 +1,43 @@
+// revisions: good1 good2 bad1 bad2
+//[good1] check-pass
+//[good2] check-pass
+
+use std::ops::Drop;
+
+struct DropMe<'a, T>(&'a T);
+
+#[cfg(good1)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    T: 'a, // Implied by struct, explicit on impl
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good2)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    'static: 'a, // Trivial bound
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad1)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    T: 'static,
+    //[bad1]~^ ERROR `Drop` impl requires `T: 'static`
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad2)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    'a: 'static,
+    //[bad2]~^ ERROR `Drop` impl requires `'a: 'static`
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/transitive-outlives-2.rs b/tests/ui/dropck/transitive-outlives-2.rs
new file mode 100644
index 00000000000..87154e25d40
--- /dev/null
+++ b/tests/ui/dropck/transitive-outlives-2.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+use std::marker::PhantomData;
+use std::ops::Drop;
+
+// a >= b >= c >= a implies a = b = c
+struct DropMe<'a: 'b, 'b: 'c, 'c: 'a>(
+    PhantomData<&'a ()>,
+    PhantomData<&'b ()>,
+    PhantomData<&'c ()>,
+);
+
+// a >= b, a >= c, b >= a, c >= a implies a = b = c
+impl<'a: 'b + 'c, 'b: 'a, 'c: 'a> Drop for DropMe<'a, 'b, 'c> {
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/transitive-outlives.bad.stderr b/tests/ui/dropck/transitive-outlives.bad.stderr
new file mode 100644
index 00000000000..da5088b27b4
--- /dev/null
+++ b/tests/ui/dropck/transitive-outlives.bad.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `'a: 'c` but the struct it is implemented for does not
+  --> $DIR/transitive-outlives.rs:20:9
+   |
+LL |     'a: 'c,
+   |         ^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/transitive-outlives.rs:7:1
+   |
+LL | struct DropMe<'a, 'b: 'a, 'c: 'b>(PhantomData<&'a ()>, PhantomData<&'b ()>, PhantomData<&'c ()>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/dropck/transitive-outlives.rs b/tests/ui/dropck/transitive-outlives.rs
new file mode 100644
index 00000000000..d071664abde
--- /dev/null
+++ b/tests/ui/dropck/transitive-outlives.rs
@@ -0,0 +1,26 @@
+// revisions: good bad
+//[good] check-pass
+
+use std::marker::PhantomData;
+use std::ops::Drop;
+
+struct DropMe<'a, 'b: 'a, 'c: 'b>(PhantomData<&'a ()>, PhantomData<&'b ()>, PhantomData<&'c ()>);
+
+#[cfg(good)]
+impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
+where
+    'c: 'a,
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad)]
+impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
+where
+    'a: 'c,
+    //[bad]~^ ERROR `Drop` impl requires `'a: 'c`
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/trivial-impl-bounds.rs b/tests/ui/dropck/trivial-impl-bounds.rs
new file mode 100644
index 00000000000..a8f5d2c354b
--- /dev/null
+++ b/tests/ui/dropck/trivial-impl-bounds.rs
@@ -0,0 +1,34 @@
+// revisions: good1 good2 good3
+// check-pass
+
+use std::ops::Drop;
+
+struct Foo;
+
+const X: usize = 1;
+
+#[cfg(good1)]
+impl Drop for Foo
+where
+    [(); X]:, // Trivial WF bound
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good2)]
+impl Drop for Foo
+where
+    for<'a> &'a (): Copy, // Trivial trait bound
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good3)]
+impl Drop for Foo
+where
+    for<'a> &'a (): 'a, // Trivial outlives bound
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/extern-flag/auxiliary/panic_handler.rs b/tests/ui/extern-flag/auxiliary/panic_handler.rs
new file mode 100644
index 00000000000..a625761a838
--- /dev/null
+++ b/tests/ui/extern-flag/auxiliary/panic_handler.rs
@@ -0,0 +1,17 @@
+#![feature(lang_items)]
+#![no_std]
+
+// Since `rustc` generally passes `-nodefaultlibs` to the linker,
+// Rust programs link necessary system libraries via `#[link()]`
+// attributes in the `libc` crate. `libc` is a dependency of `std`,
+// but as we are `#![no_std]`, we need to include it manually.
+#![feature(rustc_private)]
+extern crate libc;
+
+#[panic_handler]
+pub fn begin_panic_handler(_info: &core::panic::PanicInfo<'_>) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/tests/ui/extern-flag/force-extern.rs b/tests/ui/extern-flag/force-extern.rs
new file mode 100644
index 00000000000..f56b5378223
--- /dev/null
+++ b/tests/ui/extern-flag/force-extern.rs
@@ -0,0 +1,9 @@
+// check-pass
+// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header)
+// aux-crate:force:panic_handler=panic_handler.rs
+// compile-flags: -Zunstable-options --crate-type dylib
+// edition:2018
+
+#![no_std]
+
+fn foo() {}
diff --git a/tests/ui/extern-flag/no-force-extern.rs b/tests/ui/extern-flag/no-force-extern.rs
new file mode 100644
index 00000000000..ce9cbfe1cd2
--- /dev/null
+++ b/tests/ui/extern-flag/no-force-extern.rs
@@ -0,0 +1,10 @@
+// aux-crate:panic_handler=panic_handler.rs
+// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header)
+// compile_flags: -Zunstable-options --crate-type dylib
+// error-pattern: `#[panic_handler]` function required, but not found
+// dont-check-compiler-stderr
+// edition: 2018
+
+#![no_std]
+
+fn foo() {}
diff --git a/tests/ui/extern-flag/redundant-force-extern.rs b/tests/ui/extern-flag/redundant-force-extern.rs
new file mode 100644
index 00000000000..a4091616dd5
--- /dev/null
+++ b/tests/ui/extern-flag/redundant-force-extern.rs
@@ -0,0 +1,11 @@
+// check-pass
+// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header)
+// aux-crate:force:panic_handler=panic_handler.rs
+// compile-flags: -Zunstable-options --crate-type dylib
+// edition:2018
+
+#![no_std]
+
+extern crate panic_handler;
+
+fn foo() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs
deleted file mode 100644
index fc47a9061d3..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// only-x86
-#[link(name = "foo")]
-extern "C" {
-    #[link_ordinal(42)]
-    //~^ ERROR: `#[link_ordinal]` is unstable on x86
-    fn foo();
-    #[link_ordinal(5)]
-    //~^ ERROR: `#[link_ordinal]` is unstable on x86
-    static mut imported_variable: i32;
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr
deleted file mode 100644
index 0e900760d24..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `#[link_ordinal]` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-2.rs:4:5
-   |
-LL |     #[link_ordinal(42)]
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error[E0658]: `#[link_ordinal]` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-2.rs:7:5
-   |
-LL |     #[link_ordinal(5)]
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
deleted file mode 100644
index 295f502d6a3..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// only-windows
-// only-x86
-#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-//~^ ERROR link kind `raw-dylib` is unstable on x86
-//~| ERROR import name type is unstable
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
deleted file mode 100644
index d6b165b7610..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: link kind `raw-dylib` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-   |                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error[E0658]: import name type is unstable
-  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:61
-   |
-LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-   |                                                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.rs b/tests/ui/feature-gates/feature-gate-raw-dylib.rs
deleted file mode 100644
index 291cca8fd25..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// only-windows
-// only-x86
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: link kind `raw-dylib` is unstable on x86
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib.stderr
deleted file mode 100644
index f02241e4908..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: link kind `raw-dylib` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   |                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/impl-trait/issues/issue-86800.rs b/tests/ui/impl-trait/issues/issue-86800.rs
index 351243c6727..ec4fda322d0 100644
--- a/tests/ui/impl-trait/issues/issue-86800.rs
+++ b/tests/ui/impl-trait/issues/issue-86800.rs
@@ -1,14 +1,12 @@
 #![feature(type_alias_impl_trait)]
 
 // edition:2021
-// unset-rustc-env:RUST_BACKTRACE
 // compile-flags:-Z treat-err-as-bug=1
-// error-pattern:stack backtrace:
+// error-pattern: aborting due to `-Z treat-err-as-bug=1`
 // failure-status:101
-// normalize-stderr-test "note: .*" -> ""
-// normalize-stderr-test "thread 'rustc' .*" -> ""
-// normalize-stderr-test " +[0-9]+:.*\n" -> ""
-// normalize-stderr-test " +at .*\n" -> ""
+// normalize-stderr-test ".*note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// rustc-env:RUST_BACKTRACE=0
 
 use std::future::Future;
 
diff --git a/tests/ui/impl-trait/issues/issue-86800.stderr b/tests/ui/impl-trait/issues/issue-86800.stderr
index f3a77383778..facab390d15 100644
--- a/tests/ui/impl-trait/issues/issue-86800.stderr
+++ b/tests/ui/impl-trait/issues/issue-86800.stderr
@@ -1,24 +1,12 @@
 error: unconstrained opaque type
-  --> $DIR/issue-86800.rs:33:34
+  --> $DIR/issue-86800.rs:31:34
    |
 LL | type TransactionFuture<'__, O> = impl '__ + Future<Output = TransactionResult<O>>;
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = 
-
-
-stack backtrace:
-
 error: the compiler unexpectedly panicked. this is a bug.
 
-
-
-
-
-
-
 query stack during panic:
 #0 [type_of] computing type of `TransactionFuture::{opaque#0}`
 #1 [check_mod_item_types] checking item types in top-level module
-#2 [analysis] running analysis passes on this crate
 end of query stack
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index a282e71235c..46171880a6f 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -1,8 +1,9 @@
 // normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
-#![feature(never_type, rustc_attrs, type_alias_impl_trait)]
+#![feature(never_type, rustc_attrs, type_alias_impl_trait, repr_simd)]
 #![crate_type = "lib"]
 
 #[rustc_layout(debug)]
+#[derive(Copy, Clone)]
 enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
@@ -17,6 +18,51 @@ type Test = Result<i32, i32>; //~ ERROR: layout_of
 #[rustc_layout(debug)]
 type T = impl std::fmt::Debug; //~ ERROR: layout_of
 
+#[rustc_layout(debug)]
+pub union V { //~ ERROR: layout_of
+    a: [u16; 0],
+    b: u8,
+}
+
+#[rustc_layout(debug)]
+pub union W { //~ ERROR: layout_of
+    b: u8,
+    a: [u16; 0],
+}
+
+#[rustc_layout(debug)]
+pub union Y { //~ ERROR: layout_of
+    b: [u8; 0],
+    a: [u16; 0],
+}
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P1 { x: u32 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P2 { x: (u32, u32) } //~ ERROR: layout_of
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct F32x4(f32, f32, f32, f32);
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P3 { x: F32x4 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P4 { x: E } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
+
 fn f() -> T {
     0i32
 }
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index c5e1c41d130..b9fa1b299e9 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -81,7 +81,7 @@ error: layout_of(E) = Layout {
                ],
            },
        }
-  --> $DIR/debug.rs:6:1
+  --> $DIR/debug.rs:7:1
    |
 LL | enum E { Foo, Bar(!, i32, i32) }
    | ^^^^^^
@@ -125,7 +125,7 @@ error: layout_of(S) = Layout {
                index: 0,
            },
        }
-  --> $DIR/debug.rs:9:1
+  --> $DIR/debug.rs:10:1
    |
 LL | struct S { f1: i32, f2: (), f3: i32 }
    | ^^^^^^^^
@@ -147,7 +147,7 @@ error: layout_of(U) = Layout {
                index: 0,
            },
        }
-  --> $DIR/debug.rs:12:1
+  --> $DIR/debug.rs:13:1
    |
 LL | union U { f1: (i32, i32), f3: i32 }
    | ^^^^^^^
@@ -276,7 +276,7 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
                ],
            },
        }
-  --> $DIR/debug.rs:15:1
+  --> $DIR/debug.rs:16:1
    |
 LL | type Test = Result<i32, i32>;
    | ^^^^^^^^^
@@ -302,10 +302,218 @@ error: layout_of(i32) = Layout {
                index: 0,
            },
        }
-  --> $DIR/debug.rs:18:1
+  --> $DIR/debug.rs:19:1
    |
 LL | type T = impl std::fmt::Debug;
    | ^^^^^^
 
-error: aborting due to 5 previous errors
+error: layout_of(V) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(2 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:22:1
+   |
+LL | pub union V {
+   | ^^^^^^^^^^^
+
+error: layout_of(W) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(2 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:28:1
+   |
+LL | pub union W {
+   | ^^^^^^^^^^^
+
+error: layout_of(Y) = Layout {
+           size: Size(0 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(2 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:34:1
+   |
+LL | pub union Y {
+   | ^^^^^^^^^^^
+
+error: layout_of(P1) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:41:1
+   |
+LL | union P1 { x: u32 }
+   | ^^^^^^^^
+
+error: layout_of(P2) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:45:1
+   |
+LL | union P2 { x: (u32, u32) }
+   | ^^^^^^^^
+
+error: layout_of(P3) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:53:1
+   |
+LL | union P3 { x: F32x4 }
+   | ^^^^^^^^
+
+error: layout_of(P4) = Layout {
+           size: Size(12 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:57:1
+   |
+LL | union P4 { x: E }
+   | ^^^^^^^^
+
+error: layout_of(P5) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Scalar(
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:61:1
+   |
+LL | union P5 { zst: [u16; 0], byte: u8 }
+   | ^^^^^^^^
+
+error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Scalar(
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:64:1
+   |
+LL | type X = std::mem::MaybeUninit<u8>;
+   | ^^^^^^
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/lint/internal/trivial-diagnostics.rs b/tests/ui/lint/internal/trivial-diagnostics.rs
new file mode 100644
index 00000000000..e536e1164fc
--- /dev/null
+++ b/tests/ui/lint/internal/trivial-diagnostics.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options
+
+pub fn issue_111280() {
+    struct_span_err(msg).emit(); //~ ERROR cannot find value `msg`
+    //~^ ERROR cannot find function `struct_span_err`
+}
+
+fn main() {}
diff --git a/tests/ui/lint/internal/trivial-diagnostics.stderr b/tests/ui/lint/internal/trivial-diagnostics.stderr
new file mode 100644
index 00000000000..d47a7dae023
--- /dev/null
+++ b/tests/ui/lint/internal/trivial-diagnostics.stderr
@@ -0,0 +1,15 @@
+error[E0425]: cannot find value `msg` in this scope
+  --> $DIR/trivial-diagnostics.rs:4:21
+   |
+LL |     struct_span_err(msg).emit();
+   |                     ^^^ not found in this scope
+
+error[E0425]: cannot find function `struct_span_err` in this scope
+  --> $DIR/trivial-diagnostics.rs:4:5
+   |
+LL |     struct_span_err(msg).emit();
+   |     ^^^^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/optimization-remark.rs b/tests/ui/optimization-remark.rs
index 4f651b1dcbc..8fd30466f43 100644
--- a/tests/ui/optimization-remark.rs
+++ b/tests/ui/optimization-remark.rs
@@ -13,7 +13,7 @@
 // [merge1] compile-flags: -Cremark=all    -Cremark=giraffe
 // [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
 //
-// error-pattern: inline: 'f' not inlined into 'g'
+// error-pattern: inline (missed): 'f' not inlined into 'g'
 // dont-check-compiler-stderr
 
 #[no_mangle]
diff --git a/tests/ui/panics/default-backtrace-ice.rs b/tests/ui/panics/default-backtrace-ice.rs
index fd86a3f9dfa..b40203c339d 100644
--- a/tests/ui/panics/default-backtrace-ice.rs
+++ b/tests/ui/panics/default-backtrace-ice.rs
@@ -2,8 +2,20 @@
 // compile-flags:-Z treat-err-as-bug=1
 // error-pattern:stack backtrace:
 // failure-status:101
+// ignore-msvc
 // normalize-stderr-test "note: .*" -> ""
 // normalize-stderr-test "thread 'rustc' .*" -> ""
-// normalize-stderr-test "  .*\n" -> ""
+// normalize-stderr-test " +\d+:.*__rust_begin_short_backtrace.*" -> "(begin_short_backtrace)"
+// normalize-stderr-test " +\d+:.*__rust_end_short_backtrace.*" -> "(end_short_backtrace)"
+// normalize-stderr-test " +\d+:.*\n" -> ""
+// normalize-stderr-test " +at .*\n" -> ""
+//
+// This test makes sure that full backtraces are used for ICEs when
+// RUST_BACKTRACE is not set. It does this by checking for the presence of
+// `__rust_{begin,end}_short_backtrace` markers, which only appear in full
+// backtraces. The rest of the backtrace is filtered out.
+//
+// Ignored on msvc becaue the `__rust_{begin,end}_short_backtrace` symbols
+// aren't reliable.
 
 fn main() { missing_ident; }
diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr
index 4bd4780e25f..ddbfc4e7f3a 100644
--- a/tests/ui/panics/default-backtrace-ice.stderr
+++ b/tests/ui/panics/default-backtrace-ice.stderr
@@ -1,8 +1,13 @@
 error[E0425]: cannot find value `missing_ident` in this scope
+  --> $DIR/default-backtrace-ice.rs:21:13
+   |
 LL | fn main() { missing_ident; }
+   |             ^^^^^^^^^^^^^ not found in this scope
 
 
 stack backtrace:
+(end_short_backtrace)
+(begin_short_backtrace)
 
 error: the compiler unexpectedly panicked. this is a bug.
 
diff --git a/tests/ui/parser/eq-less-to-less-eq.rs b/tests/ui/parser/eq-less-to-less-eq.rs
new file mode 100644
index 00000000000..23c6c59d7a6
--- /dev/null
+++ b/tests/ui/parser/eq-less-to-less-eq.rs
@@ -0,0 +1,33 @@
+fn foo() {
+    let a = 0;
+    let b = 4;
+    if a =< b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn bar() {
+    let a = 0;
+    let b = 4;
+    if a = <b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn baz() {
+    let a = 0;
+    let b = 4;
+    if a = < b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn qux() {
+    let a = 0;
+    let b = 4;
+    if a =< i32>::abs(-4) { //~ERROR: mismatched types
+        println!("yay!");
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/parser/eq-less-to-less-eq.stderr b/tests/ui/parser/eq-less-to-less-eq.stderr
new file mode 100644
index 00000000000..4717d8287ff
--- /dev/null
+++ b/tests/ui/parser/eq-less-to-less-eq.stderr
@@ -0,0 +1,34 @@
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:4:15
+   |
+LL |     if a =< b {
+   |          --   ^ expected one of 7 possible tokens
+   |          |
+   |          help: did you mean: `<=`
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:12:15
+   |
+LL |     if a = <b {
+   |               ^ expected one of 7 possible tokens
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:20:16
+   |
+LL |     if a = < b {
+   |                ^ expected one of 7 possible tokens
+
+error[E0308]: mismatched types
+  --> $DIR/eq-less-to-less-eq.rs:28:8
+   |
+LL |     if a =< i32>::abs(-4) {
+   |        ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: you might have meant to compare for equality
+   |
+LL |     if a ==< i32>::abs(-4) {
+   |           +
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs
new file mode 100644
index 00000000000..d7a418959bf
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs
@@ -0,0 +1,19 @@
+// Tests that dlltool failing to generate an import library will raise an error.
+
+// only-gnu
+// only-windows
+// needs-dlltool
+// compile-flags: --crate-type lib --emit link
+// normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL"
+// normalize-stderr-test: "[^ ]*/foo.def" -> "$$DEF_FILE"
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+    // `@1` is an invalid name to export, as it usually indicates that something
+    // is being exported via ordinal.
+    #[link_name = "@1"]
+    fn f(x: i32);
+}
+
+pub fn lib_main() {
+    unsafe { f(42); }
+}
diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr
new file mode 100644
index 00000000000..020ac6a2b67
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr
@@ -0,0 +1,5 @@
+error: Dlltool could not create import library: 
+       $DLLTOOL: Syntax error in def file $DEF_FILE:1
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
index 22d57f8bedd..7bc44d65be9 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
 //~^ ERROR import name type must be of the form `import_name_type = "string"`
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
index 0e95fec29d2..fb70b987fc7 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
@@ -1,5 +1,5 @@
 error: import name type must be of the form `import_name_type = "string"`
-  --> $DIR/import-name-type-invalid-format.rs:5:42
+  --> $DIR/import-name-type-invalid-format.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
    |                                          ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
index 7ccb0082fb9..b96f61a26da 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
@@ -1,8 +1,6 @@
 // ignore-tidy-linelength
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
 //~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
index 7c0e0be911f..9533061892f 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
@@ -1,5 +1,5 @@
 error: multiple `import_name_type` arguments in a single `#[link]` attribute
-  --> $DIR/import-name-type-multiple.rs:6:74
+  --> $DIR/import-name-type-multiple.rs:4:74
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
    |                                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
index f728a578d3b..067e82a17fd 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
 //~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
index 2b299f2fea3..2bce9758e99 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
@@ -1,5 +1,5 @@
 error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
-  --> $DIR/import-name-type-unknown-value.rs:5:42
+  --> $DIR/import-name-type-unknown-value.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
index ae9207864a2..34e907bde83 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", import_name_type = "decorated")]
 //~^ ERROR import name type can only be used with link kind `raw-dylib`
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
index 5898cd875a1..75cadc471c4 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
@@ -1,11 +1,11 @@
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:5:22
+  --> $DIR/import-name-type-unsupported-link-kind.rs:3:22
    |
 LL | #[link(name = "foo", import_name_type = "decorated")]
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:9:39
+  --> $DIR/import-name-type-unsupported-link-kind.rs:7:39
    |
 LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")]
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs
new file mode 100644
index 00000000000..a07be9d92b4
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs
@@ -0,0 +1,13 @@
+// Tests that failing to run dlltool will raise an error.
+
+// only-gnu
+// only-windows
+// compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+    fn f(x: i32);
+}
+
+pub fn lib_main() {
+    unsafe { f(42); }
+}
diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr
new file mode 100644
index 00000000000..3ae901e0dbc
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr
@@ -0,0 +1,4 @@
+error: Error calling dlltool 'does_not_exit.exe': program not found
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
index 1a128c87a0c..b04c2facbcd 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name="foo")]
 extern "C" {
     #[link_name="foo"]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
index 481a06d2797..f1e54d37827 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
@@ -1,11 +1,11 @@
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:6:5
+  --> $DIR/link-ordinal-and-name.rs:4:5
    |
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:10:5
+  --> $DIR/link-ordinal-and-name.rs:8:5
    |
 LL |     #[link_ordinal(5)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
index 7c8da050cf6..9b7e8d70743 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal("JustMonika")]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
index 55cdcad75a4..6341e57a0be 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
@@ -1,5 +1,5 @@
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:5:5
+  --> $DIR/link-ordinal-invalid-format.rs:3:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal("JustMonika")]
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:8:5
+  --> $DIR/link-ordinal-invalid-format.rs:6:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
index 9feed394110..6b8cd49566d 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal()]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
index 853cdad8c1c..1b04bb228e7 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
@@ -1,5 +1,5 @@
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:5:5
+  --> $DIR/link-ordinal-missing-argument.rs:3:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal()]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:8:5
+  --> $DIR/link-ordinal-missing-argument.rs:6:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
index 631c363d4ba..8842cb94404 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
@@ -1,6 +1,4 @@
 // only-windows
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
index c0453d2bf01..2e6cf3761c2 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
@@ -1,23 +1,23 @@
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:6:5
+  --> $DIR/link-ordinal-multiple.rs:4:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:7:5
+  --> $DIR/link-ordinal-multiple.rs:5:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:9:5
+  --> $DIR/link-ordinal-multiple.rs:7:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:10:5
+  --> $DIR/link-ordinal-multiple.rs:8:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
index 54e614164b3..f33a3d62e26 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link_ordinal(123)]
 //~^ ERROR attribute should be applied to a foreign function or static
 struct Foo {}
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
index ec4104fbe50..8f279508720 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
@@ -1,17 +1,17 @@
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:3:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:1:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:7:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:5:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:11:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:9:1
    |
 LL | #[link_ordinal(42)]
    | ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
index 46731581ebc..9d741630fc9 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(72436)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
index fef6de6aedf..811145e77ee 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
@@ -1,5 +1,5 @@
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:5:5
+  --> $DIR/link-ordinal-too-large.rs:3:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal(72436)]
    = note: the value may not exceed `u16::MAX`
 
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:8:5
+  --> $DIR/link-ordinal-too-large.rs:6:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
index 71e0ac9f3ee..9988115fd8b 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(3, 4)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
index 7e0fcd845cb..d5ce8aff34f 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
@@ -1,5 +1,5 @@
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:5:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:3:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal(3, 4)]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:8:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:6:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
index 329c93fc196..14e915d602a 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(3)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
index 5fbffbda570..200b8f62874 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
@@ -1,11 +1,11 @@
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:5:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:3:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:12:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:10:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
index 6542faad264..b4173f3b60b 100644
--- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
+++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
@@ -2,7 +2,6 @@
 // only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(clashing_extern_declarations)]
-#![feature(raw_dylib)]
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     fn f(x: i32);
diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
index c6808bec7b5..51010840548 100644
--- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
@@ -1,5 +1,5 @@
 error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions
-  --> $DIR/multiple-declarations.rs:14:9
+  --> $DIR/multiple-declarations.rs:13:9
    |
 LL |         fn f(x: i32);
    |         ^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
index 4efffbd532e..d4c6658a330 100644
--- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
+++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
@@ -1,6 +1,5 @@
 // ignore-windows
 // compile-flags: --crate-type lib
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 #[link(name = "foo", kind = "raw-dylib")]
 //~^ ERROR: link kind `raw-dylib` is only supported on Windows targets
 extern "C" {}
diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
index 14e791f1fb9..b635a09afba 100644
--- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
@@ -1,5 +1,5 @@
 error[E0455]: link kind `raw-dylib` is only supported on Windows targets
-  --> $DIR/raw-dylib-windows-only.rs:4:29
+  --> $DIR/raw-dylib-windows-only.rs:3:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
    |                             ^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs
new file mode 100644
index 00000000000..e4b07ab8108
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs
@@ -0,0 +1,7 @@
+// run-pass
+
+#![feature(c_str_literals)]
+
+fn main() {
+    assert_eq!(b"test\0", c"test".to_bytes_with_nul());
+}
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs
new file mode 100644
index 00000000000..b27da26ed23
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs
@@ -0,0 +1,13 @@
+// gate-test-c_str_literals
+
+macro_rules! m {
+    ($t:tt) => {}
+}
+
+fn main() {
+    c"foo";
+    //~^ ERROR: `c".."` literals are experimental
+
+    m!(c"test");
+    //~^ ERROR: `c".."` literals are experimental
+}
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr
new file mode 100644
index 00000000000..bc0c537aada
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `c".."` literals are experimental
+  --> $DIR/gate.rs:8:5
+   |
+LL |     c"foo";
+   |     ^^^^^^
+   |
+   = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information
+   = help: add `#![feature(c_str_literals)]` to the crate attributes to enable
+
+error[E0658]: `c".."` literals are experimental
+  --> $DIR/gate.rs:11:8
+   |
+LL |     m!(c"test");
+   |        ^^^^^^^
+   |
+   = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information
+   = help: add `#![feature(c_str_literals)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
new file mode 100644
index 00000000000..7bc6097f124
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
new file mode 100644
index 00000000000..ff9006f6f97
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
Binary files differdiff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs
new file mode 100644
index 00000000000..82e8e2090d7
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+#![feature(c_str_literals)]
+
+fn main() {
+    assert_eq!(
+        c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(),
+        &[0xEF, 0x80, 0xF0, 0x9F, 0xA6, 0x80, 0xF0, 0x9F, 0xA6, 0x80, 0x00],
+    );
+}
diff --git a/tests/ui/specialization/issue-111232.rs b/tests/ui/specialization/issue-111232.rs
new file mode 100644
index 00000000000..3ed3c580e6d
--- /dev/null
+++ b/tests/ui/specialization/issue-111232.rs
@@ -0,0 +1,11 @@
+#![feature(min_specialization)]
+
+struct S;
+
+impl From<S> for S {
+    fn from(s: S) -> S { //~ ERROR `from` specializes an item from a parent `impl`, but that item is not marked `default`
+        s
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/issue-111232.stderr b/tests/ui/specialization/issue-111232.stderr
new file mode 100644
index 00000000000..27ee42fc00c
--- /dev/null
+++ b/tests/ui/specialization/issue-111232.stderr
@@ -0,0 +1,11 @@
+error[E0520]: `from` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/issue-111232.rs:6:5
+   |
+LL |     fn from(s: S) -> S {
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: parent implementation is in crate `core`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0520`.
diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr
new file mode 100644
index 00000000000..a985b1a6e12
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr
@@ -0,0 +1,24 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/drop-impl-pred.rs:6:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0367]: `Drop` impl requires `H: Foo` but the struct it is implemented for does not
+  --> $DIR/drop-impl-pred.rs:19:15
+   |
+LL |     for<H> H: Foo,
+   |               ^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/drop-impl-pred.rs:12:1
+   |
+LL | struct Bar<T>(T) where T: Foo;
+   | ^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs
new file mode 100644
index 00000000000..c65b5ea9ba4
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs
@@ -0,0 +1,25 @@
+// revisions: no yes
+//[yes] check-pass
+
+// Issue 110557
+
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+pub trait Foo {}
+
+#[cfg(no)]
+struct Bar<T>(T) where T: Foo;
+
+#[cfg(yes)]
+struct Bar<T>(T) where for<H> H: Foo;
+
+impl<T> Drop for Bar<T>
+where
+    for<H> H: Foo,
+//[no]~^ ERROR `Drop` impl requires `H: Foo` but the struct it is implemented for does not
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr
new file mode 100644
index 00000000000..165cf2ee13d
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr
@@ -0,0 +1,11 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/drop-impl-pred.rs:6:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/x b/x
index 4309b82627c..d967988e1c4 100755
--- a/x
+++ b/x
@@ -7,9 +7,12 @@
 
 set -eu
 
+# syntax check
+sh -n $0
+
 realpath() {
     if [ -d "$1" ]; then
-        CDPATH='' command cd "$1" && pwd -P   
+        CDPATH='' command cd "$1" && pwd -P
     else
         echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
     fi
diff --git a/x.ps1 b/x.ps1
index b0cddc9f930..a156017628d 100755
--- a/x.ps1
+++ b/x.ps1
@@ -2,6 +2,11 @@
 
 # See ./x for why these scripts exist.
 
+$ErrorActionPreference = "Stop"
+
+# syntax check
+Get-Command -syntax ${PSCommandPath}
+
 $xpy = Join-Path $PSScriptRoot x.py
 # Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?)
 # Double-quote all the arguments so it doesn't do that.